Serlvet笔记一(Servlet基础)Servlet笔记二(请求和响应)Servlet笔记三(会话及其会话技术)Servlet笔记四(JSP技术)Servlet笔记五(EL表达式和JSTL) Servlet笔记六(Servlet 高级)
Servlet笔记七(JDBC)Servlet笔记八(数据库连接池与DBUtils工具)Servlet笔记九(JSP 开发模型)Servlet笔记十(文件上传和下载)
Filter 被称作过滤器,其基本功能就是对 Servlet 容器调用 Servlet 的过程进行拦截,从而在 Servlet 进行响应处理前后实现一些特殊功能。这就好比现实中的污水净化设备,它可以看作一个过滤器,专门用于过滤污水杂志。
当浏览器访问服务器中的目标资源时,会被 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>
Filter 的 <filter-mapping> 元素用于配置过滤拦截的资源信息,如果想让过滤器拦截所有的请求访问,那么需要使用通配符 “*” 来实现。
在 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
直接访问 index.jsp 页面 被拦截
而通过 /myservlet 页面调用 forward() 方法 请求转发到 index.jsp 页面 则不会被拦截
当将 dispather 元素的值配置为 FORWARD 时
直接访问 index.jsp 不会被拦截,但是通过 /myservlet 请求转发到 index.jsp 页面则会被拦截
在一个 Web 应用程序中可以注册多个 Filter 程序,每个 Filter 程序可以针对某一个 URL 进行拦截。如果多个 Filter 程序都对用一个 URL 进行拦截,那么这些 Filter 就会组成一个 Filter 链(也叫过滤器链)。Filter 链用 FilterChain 对象来表示,FilterChain 对象中有一个 doFilter() 方法,该方法的作用就是让 Filter 链上的当前过滤放行,使请求进入下一个 Filter。
当浏览器访问 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>
为了获取 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>
可以在 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>
<input type="text" name="username" /> ${errerMsg}
</td>
</tr>
<tr>
<td height="35" align="center">密 码:</td>
<td>
<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. 运行项目,查看结果
在 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> <input type="text" name="name" /></td>
</tr>
<tr>
<td height="30" align="center">密 码:</td>
<td> <input type="password" name="password" /></td>
</tr>
<tr>
<td height="30" colspan="2" align="center">
<input type="submit" value="登录" />
<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 方式
post 方式
输出(无乱码)
在程序开发中,经常需要对某些事件进行监听,如监听鼠标单击事件、监听键盘按下事件等,此时就需要使用监听器,监听器在监听的过程中会涉及几个重要组成部分,具体如下。
当用户进行一个操作触发事件源上的事件时,就会被事件监听器监听到。当监听器监听到事件发生时,相应的事件处理器就会对发生的事件进行处理。
事件监听器在进行工作时,可分为如下几个步骤:
在开发 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 类:
在 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. 查看运行结果
1 分钟后控制台输出 session 销毁信息
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. 运行结果