Servlet笔记六(Servlet 高级)

admin2024-08-22  6

本栏博客目录

​​Serlvet笔记一(Servlet基础)​​​​Servlet笔记二(请求和响应)​​​​Servlet笔记三(会话及其会话技术)​​​​Servlet笔记四(JSP技术)​​​​Servlet笔记五(EL表达式和JSTL)​​ Servlet笔记六(Servlet 高级)
​​Servlet笔记七(JDBC)​​​​Servlet笔记八(数据库连接池与DBUtils工具)​​​​Servlet笔记九(JSP 开发模型)​​​​Servlet笔记十(文件上传和下载)​​

文章目录

  • ​​Filter 过滤器​​
  • ​​Filter 概念​​
  • ​​Filter 映射​​
  • ​​1. 使用通配符 "*" 拦截用户的所有请求​​
  • ​​2. 拦截不同方式的访问请求​​
  • ​​Filter 链​​
  • ​​FilterConfig 接口​​
  • ​​使用 Filter 实现用户自动登录​​
  • ​​使用 Filter 实现统一全站编码​​
  • ​​Listener 监听器​​
  • ​​Servlet 事件监听器概述​​
  • ​​监听域对象的生命周期​​
  • ​​监听对象属性变更​​

Filter 过滤器

Filter 概念

Filter 被称作过滤器,其基本功能就是对 Servlet 容器调用 Servlet 的过程进行拦截,从而在 Servlet 进行响应处理前后实现一些特殊功能。这就好比现实中的污水净化设备,它可以看作一个过滤器,专门用于过滤污水杂志。

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_jsp,第1张

当浏览器访问服务器中的目标资源时,会被 Filter 拦截,在 Filter 中进行预处理操作,然后再将请求转发给目标资源。当服务器接收到这个请求后会对其进行响应,在服务器处理响应的过程中,也需要先将响应结果发送给过滤器,在过滤器中对响应结果进行处理后,才会发送给客户端。

其实,Filter 过滤器就是一个实现了 javax.servlet.Filter 接口的类,在 javax.servlet.Filter 接口中定义了 3 个方法。

Filter 接口中的方法

方法声明

功能描述

init(FilterConfig filterConfig)

init()方法用来初始化过滤器,开发人员可以在 init() 方法中完成与构造方法类似的初始化功能。如果初始化代码中要使用到 FilterConfig 对象,那么,这些初始化代码就只能在 Filter 的 init() 方法中编写,而不能在构造方法中编写

doFilter(SerlvetRequest request, ServletResonse response, FilterChain chain)

doFilter() 方法有多个参数,其中,参数 request 和 response 为 Web 服务器或 Filter 链中的上一个 Filter 传递过来的请求和响应对象;参数 chain 代表当前 Filter 链的对象,在当前 Filter 对象中的 doFilter() 方法内部需要调用 FilterChain 对象的 doFilter() 方法,才能把请求交付给 Filter 链中的下一个 Filter 或者目标程序去处理

destroy()

destroy() 方法在 Web 服务器卸载 Filter 对象之前被调用,该方法用于释放被 Filter 对象打开的资源,例如关闭数据库和 IO 流

这 3 个方法都是 Filter 的生命周期方法,其中 init() 方法在 Web 应用程序加载的时候调用,destroy() 方法在 Web 应用程序卸载的时候调用,这两个方法都只会被调用一次,而 doFilter() 方法只要有客户端请求时就会被调用,并且 Filter 所有的工作 集中 在 doFilter() 方法中。

MyServlet.java

package com.xxx;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class MyServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write("Hello World!");
}
}

MyFilter

package com.xxx;

import javax.servlet.*;
import java.io.IOException;

// 拦截myservlet, 输出自己的信息
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilter is running...");
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
response.getWriter().write("Hello MyFilter...");
}

@Override
public void destroy() {
System.out.println("MyFilter is destroy...");
}
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.xxx.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/myservlet</url-pattern>
<!-- <url-pattern>/*</url-pattern>-->
<!-- <url-pattern>/index.jsp</url-pattern>-->
</filter-mapping>

<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>com.xxx.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/myservlet</url-pattern>
</servlet-mapping>

</web-app>

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_jsp_02,第2张

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_Servlet_03,第3张

Filter 映射

1. 使用通配符 “*” 拦截用户的所有请求

Filter 的 <filter-mapping> 元素用于配置过滤拦截的资源信息,如果想让过滤器拦截所有的请求访问,那么需要使用通配符 “*” 来实现。

2. 拦截不同方式的访问请求

在 web.xml 文件中,一个 <filter-mapping> 元素用于配置一个 Filter 所负责拦截的资源。<filter-mapping> 元素中有一个特殊的子元素 <dispatcher>,该元素用于指定过滤器所拦截的资源被 Servlet 容器调用方式,<dispatcher> 元素的值共有 4 个。

注意: dispather 元素的值默认是 REQUEST

1)REQUEST
当用户直接访问页面时,Web 容器将会调用过滤器。如果目标资源是通过 RequestDispather 的 include() 或 forward() 方法访问的,那么该过滤器将不会被调用。

2)INCLUDE
如果目标资源是通过 RequestDispatcher 的 forward() 方法访问的,那么该过滤器将被调用。除此之外,该过滤器不会被调用。

3)FORWARD
如果目标资源是通过 RequestDispatcher 的 include() 方法访问的,那么该过滤器将被调用。除此之外,该过滤器不会被调用。

4)ERROR
如果目标资源是通过声明式异常处理机制调用的,那么该过滤器将被调用。除此之外,过滤器不会被调用。

现将拦截页面改为 index.jsp

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_Servlet_04,第4张

直接访问 index.jsp 页面 被拦截

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_Listener_05,第5张

而通过 /myservlet 页面调用 forward() 方法 请求转发到 index.jsp 页面 则不会被拦截

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_Filter_06,第6张

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_jsp_07,第7张

当将 dispather 元素的值配置为 FORWARD 时

直接访问 index.jsp 不会被拦截,但是通过 /myservlet 请求转发到 index.jsp 页面则会被拦截

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_Listener_08,第8张

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_jsp_09,第9张

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_Filter_10,第10张

Filter 链

在一个 Web 应用程序中可以注册多个 Filter 程序,每个 Filter 程序可以针对某一个 URL 进行拦截。如果多个 Filter 程序都对用一个 URL 进行拦截,那么这些 Filter 就会组成一个 Filter 链(也叫过滤器链)。Filter 链用 FilterChain 对象来表示,FilterChain 对象中有一个 doFilter() 方法,该方法的作用就是让 Filter 链上的当前过滤放行,使请求进入下一个 Filter。

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_Listener_11,第11张

当浏览器访问 Web 服务器中的资源时需要经过两个过滤器 Filter1 和 Filter2。首先 Filter1 会对这个请求进行拦截,在 Filter1 过滤器中处理好请求后,通过调用 Filter1 的 doFilter() 方法将请求传递给 Filter2,Filter2 将用户请求处理后同样调用 doFilter() 方法,最终将请求发送给目标资源。当 Web 服务器对这个请求做出响应时,也会被过滤器拦截,这个拦截顺序与之前相反,最终将响应结果发送给客户端。

MyServlet.java

package com.xxx;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class MyServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write("Hello World!<br />");

// req.getRequestDispatcher("index.jsp").forward(req, resp);
}
}

MyFilter01.java

package com.xxx;

import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;

public class MyFilter01 implements Filter {

@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilter01 is running...");
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
PrintWriter out = response.getWriter();
out.write("Hello MyFilter01...<br/>");
// 向后传递
chain.doFilter(request, response);

}

@Override
public void destroy() {

}
}

MyFilter02.java

package com.xxx;

import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;

public class MyFilter02 implements Filter {

@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("MyFilter02...");
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
PrintWriter out = response.getWriter();
out.write("Hello MyFilter02...<br/>");
out.write("MyFilter02 Before...<br/>");
// 向后传递
chain.doFilter(request, response);
// 响应回去
out.write("MyFilter02 After...<br />");

}

@Override
public void destroy() {

}
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">

<filter>
<filter-name>myFilter01</filter-name>
<filter-class>com.lz.jiaotong.MyFilter01</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter01</filter-name>
<url-pattern>/myservlet</url-pattern>
</filter-mapping>

<filter>
<filter-name>myFilter02</filter-name>
<filter-class>com.lz.jiaotong.MyFilter02</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter02</filter-name>
<url-pattern>/myservlet</url-pattern>
</filter-mapping>

<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>com.lz.jiaotong.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/myservlet</url-pattern>
</servlet-mapping>

</web-app>

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_Servlet_12,第12张

FilterConfig 接口

为了获取 Filter 程序在 web.xml 文件中的配置信息,Servlet API 提供了一个 FilterConfig 接口,该接口封装了 Filter 程序在 web.xml 中的所有注册信息,并且提供了一系列获取这些配置信息的方法。

方法声明

功能描述

String getFilterName()

getFilterName() 方法用于返回在 web.xml 文件中为 Filter 所设置的名称,也就是返回 <filter-name> 元素的设置值

String getInitParameter(String name)

getInitParameter(String name) 方法用于返回在 web.xml 文件中为 Filter 所设置的某个名称的初始化参数值,如果指定名称的初始化参数不存在,则返回 null

Enumeration getInitParameterNames()

getInitParameterNames() 方法用于返回一个 Enumeration 集合的对象,该集合中包含了在 web.xml 文件中为当前 Filter 设置的所有初始化参数的名称

ServletContext getServletContext()

getServletContext() 方法用于返回 FilterConfig 对象中所包装的ServletContext 对象的引用

MyServlet.java

package com.xxx;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class MyServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write("Hello World!<br />");

// req.getRequestDispatcher("index.jsp").forward(req, resp);
}
}

MyFilterConfig.java

package com.xxx;

import javax.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;

public class MyFilterConfig implements Filter {

private String characterEncoding;
private FilterConfig fc;

@Override
public void init(FilterConfig filterConfig) throws ServletException {

fc = filterConfig;
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

response.setContentType("text/html;charset=utf-8");

characterEncoding = fc.getInitParameter("encoding");
PrintWriter out = response.getWriter();

// System.out.println("初始化 encoding 的参数值是:" + characterEncoding);
chain.doFilter(request, response);
out.write("初始化 encoding 的参数值是:" + characterEncoding + "<br />");

}

@Override
public void destroy() {

}
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">

<filter>
<filter-name>myFilterConfig</filter-name>
<filter-class>com.xxx.MyFilterConfig</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>myFilterConfig</filter-name>
<url-pattern>/myservlet</url-pattern>
</filter-mapping>


<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>com.xxx.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/myservlet</url-pattern>
</servlet-mapping>

</web-app>

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_jsp_13,第13张

使用 Filter 实现用户自动登录

可以在 Filter 程序中实现 Cookie 的校验,由于 Filter 可以对服务器的所有请求进行拦截,因此,一旦请求通过 Filter 程序,就相当于用户信息校验通过,Servlet 程序根据获取到的用户信息,就可以实现自动登录了。

1. 编写 User 类

User.java

package com.xxx;

public class User {

private String username;
private String passward;

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}

public String getPassward() {
return passward;
}

public void setPassward(String passward) {
this.passward = passward;
}
}

2. 实现登录页面和首页

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title></title>
</head>
<body>
<center><h3>用户登录</h3></center>
<form action="${pageContext.request.contextPath}/LoginServlet" method="post">
<table border="1" width="600px" cellpadding="0" cellspacing="0" align="center">
<tr>
<td height="30" align="center">用户名:</td>
<td>&nbsp;&nbsp;
<input type="text" name="username" /> ${errerMsg}
</td>
</tr>
<tr>
<td height="35" align="center">&nbsp;码:</td>
<td>&nbsp;&nbsp;
<input type="password" name="password" />
</td>
</tr>
<tr>
<td height="35" align="center">自动登录时间</td>
<td>
<input type="radio" name="autologin" value="${60*60*24*31}"/> 一个月
<input type="radio" name="autologin" value="${60*60*24*31*3}"/> 三个月
<input type="radio" name="autologin" value="${60*60*24*31*6}"/> 半年
<input type="radio" name="autologin" value="${60*60*24*31*12}"/> 一年
</td>
</tr>
<tr>
<td height="30" colspan="2" align="center">
<input type="submit" value="登录" />
<input type="reset" value="重置" />
</td>
</tr>
</table>
</form>
</body>
</html>

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>显示登录的用户信息</title>
</head>
<body>
<br />
<center><h3>欢迎光临</h3></center>
<br />
<br />
<c:choose>
<c:when test="${sessionScope.user==null}">
<a href="${pageContext.request.contextPath}/login.jsp">用户登录</a>
</c:when>
<c:otherwise>
欢迎你,${sessionScope.user.username}!
<a href="${pageContext.request.contextPath}/LogoutServlet">注销</a>
</c:otherwise>
</c:choose>
</body>
</html>

3. 创建 Servlet

LoginServlet.java

package com.xxx;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class LoginServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

// 获得用户名和密码
String username = req.getParameter("username");
String password = req.getParameter("password");

if("admin".equals(username) && "123456".equals(password)){

// 将用户状态 user 对象存入 session 域
User user = new User();
user.setUsername(username);
user.setPassward(password);
req.getSession().setAttribute("user", user);

String autoLogin = req.getParameter("autologin");

if(autoLogin != null){

Cookie cookie = new Cookie("autologin", username+"-"+password);
cookie.setMaxAge(Integer.parseInt(autoLogin));
cookie.setPath(req.getContextPath());
resp.addCookie(cookie);
}

resp.sendRedirect(req.getContextPath() + "/index.jsp");

}else {
req.setAttribute("errerMsg", "用户名或密码错误");
req.getRequestDispatcher("/login.jsp").forward(req, resp);
}
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}

LogoutServlet.java

package com.xxx;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class LogoutServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

// 注销
req.getSession().removeAttribute("user");

Cookie cookie = new Cookie("autologin", "msg");
cookie.setPath(req.getContextPath());
cookie.setMaxAge(0);
resp.addCookie(cookie);
resp.sendRedirect(req.getContextPath()+"/index.jsp");
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}

4. 创建过滤器

AutoLoginFilter.java

package com.xxx;


import javax.servlet.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class AutoLoginFilter implements Filter {

@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

HttpServletRequest req = (HttpServletRequest) request;
Cookie[] cookies = req.getCookies();
String autologin = null;

for (int i = 0; cookies!=null && i<cookies.length;i++){

if("autologin".equals(cookies[i].getName())){

autologin = cookies[i].getValue();
break;
}
}

if(autologin != null){
String[] parts = autologin.split("-");
String username = parts[0];
String password = parts[1];

if("admin".equals(username)&& "123456".equals(password)){

User user = new User();
user.setUsername(username);
user.setPassward(password);
req.getSession().setAttribute("user", user);
}
}
chain.doFilter(req, response);
}

@Override
public void destroy() {
}
}

5. 配置映射信息

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<filter>
<filter-name>AutoLoginFilter</filter-name>
<filter-class>com.xxx.AutoLoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AutoLoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.xxx.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/LoginServlet</url-pattern>
</servlet-mapping>

<servlet>
<servlet-name>LogoutServlet</servlet-name>
<servlet-class>com.xxx.LogoutServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LogoutServlet</servlet-name>
<url-pattern>/LogoutServlet</url-pattern>
</servlet-mapping>
</web-app>

6. 运行项目,查看结果

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_jsp_14,第14张

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_Listener_15,第15张

使用 Filter 实现统一全站编码

在 Web 开发中,经常遇到中文乱码问题,按照前面所学的知识,解决乱码的通常做法都是在 Servlet 程序中设置编码方式,但是,如果多个 Servlet 程序都需要设置编码方式,势必会书写大量重复代码。为了解决上述问题,可以在 Filter 中对获取到的请求和响应消息进行编码,从而统一全站的编码方式。

1. 编写 form.jsp 页面

form.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>用户登录</title>
</head>
<body>
<a href="${pageContext.request.contextPath}/CharacterServlet?name=小李&password=超级密码">单击超级链接登录</a>
<br />
<br />
<form action="${pageContext.request.contextPath}/CharacterServlet" method="post">
<table border="1" width="400" cellpadding="0" cellspacing="0" align="center">
<tr>
<td height="30" align="center">用户名:</td>
<td>&nbsp;<input type="text" name="name" /></td>
</tr>
<tr>
<td height="30" align="center">&nbsp;&nbsp;码:</td>
<td>&nbsp;<input type="password" name="password" /></td>
</tr>
<tr>
<td height="30" colspan="2" align="center">
<input type="submit" value="登录" />
&nbsp;&nbsp;&nbsp;&nbsp;
<input type="reset" value="重置" />
</td>

</tr>
</table>
</form>
</body>
</html>

2. 创建 Servlet

CharacterServlet.java

package com.xxx;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/CharacterServlet")
public class CharacterServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

String name = req.getParameter("name");
String pass = req.getParameter("password");
System.out.println("name" + name + ", password=" + pass);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}

3. 创建过滤器

CharacterFilter 类用于拦截用户的请求访问,实现统一全站编码的功能。只是针对请求的方式不同,解决乱码的方式也不同。其中,POST 方式的请求参数存放在消息头中,可以通过 setCharacterEncoding() 方法进行设置;而 GET 方式的请求参数存放在消息头中,必须得通过提取 URI 参数才能进行设置。如果每次单独对 GET 请求方式进行处理,势必会很麻烦。为此,可以通过 HttpServletWrapper 类对 HttpServletRequest 类进行包装,通过重写 getParameter() 的方式来设置 GET 方式提交参数的编码。

CharacterFilter.java

package com.xxx;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

public class CharacterFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("CharacterFilter is running...");
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse)response;
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");

CharacterRequest request1 = new CharacterRequest(req);

chain.doFilter(request1, response);
}

@Override
public void destroy() {
System.out.println("CharacterFilter is destroyed...");
}
}

// 如果地址栏(GET方式)按 iso-8859-1 传送参数,则改为 utf-8
class CharacterRequest extends HttpServletRequestWrapper{

private HttpServletRequest request;

/**
* Constructs a request object wrapping the given request.
*
* @param request The request to wrap
* @throws IllegalArgumentException if the request is null
*/
public CharacterRequest(HttpServletRequest request) {
super(request);
this.request = request;
}

@Override
public String getParameter(String name) {

String value = super.getParameter(name);
if(value == null) return null;
String method = super.getMethod();
String encoding = request.getCharacterEncoding();

if("iso-8859-1".equalsIgnoreCase(encoding)){
if("get".equalsIgnoreCase(method.toLowerCase())){
try{
value = new String(value.getBytes("iso-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}
return value;
}
}

4. 配置映射信息

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.xxx.CharacterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

5. 测试结果

get 方式

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_java_16,第16张

post 方式

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_Listener_17,第17张

输出(无乱码)

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_java_18,第18张

Listener 监听器

在程序开发中,经常需要对某些事件进行监听,如监听鼠标单击事件、监听键盘按下事件等,此时就需要使用监听器,监听器在监听的过程中会涉及几个重要组成部分,具体如下。

  • 事件(Event):用户的一个操作,如单击一个按钮、调用一个方法、创建一个对象等。
  • 事件源:产生事件的对象。
  • 事件监听器(Listener):负责监听发生在事件源上的事件。
  • 事件处理器:监听器的成员方法,当事件发生的时候会触发对应的处理器(成员方法)。

当用户进行一个操作触发事件源上的事件时,就会被事件监听器监听到。当监听器监听到事件发生时,相应的事件处理器就会对发生的事件进行处理。

事件监听器在进行工作时,可分为如下几个步骤:

  • 将监听器绑定到事件源,也就是注册监听器。
  • 事件发生时会触发监听器的成员方法,即事件处理器,传递事件对象。
  • 事件处理器通过事件对象获得事件源,并对事件源进行处理。

Servlet 事件监听器概述

在开发 Web 应用程序时,也经常会使用监听器,这个监听器也被称为 Servlet 事件监听器。Servlet 事件监听器就是一个实现了特定接口的 Java 程序,专门用于监听 Web 应用程序中 ServletContext、HttpSession 和 ServletRequest 等域对象的创建和销毁过程,监听这些域对象属性的修改以及感知绑定到 HttpSession 域中某个对象的状态。

Servlet 规范中共有 8 种监听器

类型

描述

ServletContextListener

用于监听 ServletContext 对象的创建与销毁过程

HttpSessionListener

用于监听 HttpSession 对象的创建与销毁过程

ServletRequestListener

用于监听 ServletRequest 对象的创建与销毁过程

ServletContextAttributeListener

用于监听 ServletContext 对象中的属性变更

HttpSessionAttributeListener

用于监听 HttpSession 对象中的属性变更

ServletRequestAttributeListener

用于监听 ServletRequest 对象中的属性变更

HttpSessionBindingListener

用于监听 JavaBean 对象绑定到 HttpSession 对象和从 HttpSession 对象解绑的事件

HttpSessionActivationListener

用于监听 HttpSession 中对象活化和钝化的过程

HttpSession 对象从内存中转移至硬盘的过程称为钝化。HttpSession 对象从持久化的状态变为运行状态的过程被称为活化。

上述监听器根据监听事件的不同可以将其分为 3 类:

  • 用于监听域对象创建和销毁的事件监听器(ServletContextListener 接口、HttpSessionListener 接口、ServletRequestListener 接口)。
  • 用于监听域对象属性增加和删除的事件监听器(ServletContextAttributeListener 接口、HttpSessionAttributeListener 接口、ServletRequestAttributeListener 接口)。
  • 用于监听绑定到 HttpSession 域中某个对象状态的事件监听器(HttpSessionBindingListener 接口、HttpSessionActivationListener 接口)

在 Servlet 规范中,这 3 类事件监听器都定义了相应的接口,在编写事件监听程序时只需要实现对应的接口就可以。Web 服务器会根据监听器所实现的接口,把它注册到被监听的对象上,当触发了某个对象的监听事件时,Web 容器将会调用 Servlet 监听器与之相关的方法对事件进行处理。

监听域对象的生命周期

要想对 Servlet 域对象的生命周期进行监听,首先需要实现域对应的 ServletContextListener、HttpSessionListener 和 ServletRequestListener 接口,这些接口中的方法和执行过程非常类似。可以为每一个监听器编写一个单独的类,也可以用一个类来实现这 3 个接口,从而让这个类具有 3 个事件监听器的功能。

1. 创建监听器

MyListener.java

package com.xxx;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

//@WebListener
public class MyListener implements
ServletContextListener,
HttpSessionListener,
ServletRequestListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("ServletContext对象被创建了...");
}

@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("ServletContext对象被销毁了...");
}

@Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("ServletRequest对象被销毁了...");
}

@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("ServletRequest对象被创建了...");
}

@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("HttpSession对象被创建了...");
}

@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("HttpSession对象被销毁了...");
}
}

2. 添加监听器类信息

在 web.xml 中添加如下配置

<listener>
<listener-class>com.xxx.MyListener</listener-class>
</listener>

3. 创建测试页面

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
${pageContext.session.getAttribute("name")}
<% session.setAttribute("name", "666666"); %>
</body>
</html>

4. 设置监听超时信息

在 web.xml 中添加如下配置:

<session-config>
<session-timeout>1</session-timeout>
</session-config>

5. 查看运行结果

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_Filter_19,第19张

1 分钟后控制台输出 session 销毁信息

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_Listener_20,第20张

监听对象属性变更

1. 创建测试页面

test.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Insert title here</title>
</head>
<body>
<h3>这是一个测试对象属性信息监听器的页面</h3>
<%
pageContext.getServletContext().setAttribute("username", "u1");
getServletContext().setAttribute("username", "t2");
getServletContext().removeAttribute("username");

session.setAttribute("username", "u1");
session.setAttribute("username", "t2");
session.removeAttribute("username");

request.setAttribute("username", "u1");
request.setAttribute("username", "t2");
request.removeAttribute("username");
%>
</body>
</html>

2. 创建监听器

MyAttributeListener.java

package com.xxx;

import javax.servlet.*;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;

@WebListener
public class MyAttributeListener implements
ServletContextAttributeListener,
HttpSessionAttributeListener,
ServletRequestAttributeListener {

@Override
public void attributeAdded(ServletContextAttributeEvent scae) {
String name = scae.getName(); // 触发时间的属性名
// e.getxxx() 通过事件获取事件源对象
System.out.println("ServletContext 添加属性:" + name + "="
+ scae.getServletContext().getAttribute(name));
}

@Override
public void attributeRemoved(ServletContextAttributeEvent scae) {
String name = scae.getName();
System.out.println("ServletContext 移除属性:" + name);
}

@Override
public void attributeReplaced(ServletContextAttributeEvent scae) {
String name = scae.getName();
System.out.println("ServletContext 替换属性:" + name + "="
+ scae.getServletContext().getAttribute(name));
}

@Override
public void attributeAdded(ServletRequestAttributeEvent srae) {
String name = srae.getName();
System.out.println("ServletRequest 添加属性:" + name + "="
+ srae.getServletRequest().getAttribute(name));
}

@Override
public void attributeRemoved(ServletRequestAttributeEvent srae) {
String name = srae.getName();
System.out.println("ServletRequest 移除属性:" + name);
}

@Override
public void attributeReplaced(ServletRequestAttributeEvent srae) {
String name = srae.getName();
System.out.println("ServletRequest 替换属性:" + name + "="
+ srae.getServletRequest().getAttribute(name));
}

@Override
public void attributeAdded(HttpSessionBindingEvent se) {
String name = se.getName();
System.out.println("HttpSession 添加属性:" + name + "="
+ se.getSession().getAttribute(name));
}

@Override
public void attributeRemoved(HttpSessionBindingEvent se) {
String name = se.getName();
System.out.println("HttpSession 移除属性:" + name);
}

@Override
public void attributeReplaced(HttpSessionBindingEvent se) {
String name = se.getName();
System.out.println("HttpSession 替换属性:" + name + "="
+ se.getSession().getAttribute(name));
}
}

3. 运行结果

Servlet笔记六(Servlet 高级),Servlet笔记六(Servlet 高级)_Listener_21,第21张


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明原文出处。如若内容造成侵权/违法违规/事实不符,请联系SD编程学习网:675289112@qq.com进行投诉反馈,一经查实,立即删除!