- Filter 过滤器
- Filter 概念
- Filter 映射
- 1. 使用通配符 "*" 拦截用户的所有请求
- 2. 拦截不同方式的访问请求
- Filter 链
- FilterConfig 接口
- 使用 Filter 实现用户自动登录
- 使用 Filter 实现统一全站编码
- Listener 监听器
- Servlet 事件监听器概述
- 监听域对象的生命周期
- 监听对象属性变更
Filter 过滤器 Filter 概念
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
myFilter com.xxx.MyFilter myFilter /myservlet 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. 配置映射信息
myFilter com.xxx.CharacterFilter myFilter /*
5. 测试结果
get 方式
post 方式
输出(无乱码)
在程序开发中,经常需要对某些事件进行监听,如监听鼠标单击事件、监听键盘按下事件等,此时就需要使用监听器,监听器在监听的过程中会涉及几个重要组成部分,具体如下。
- 事件(Event):用户的一个操作,如单击一个按钮、调用一个方法、创建一个对象等。
- 事件源:产生事件的对象。
- 事件监听器(Listener):负责监听发生在事件源上的事件。
- 事件处理器:监听器的成员方法,当事件发生的时候会触发对应的处理器(成员方法)。
当用户进行一个操作触发事件源上的事件时,就会被事件监听器监听到。当监听器监听到事件发生时,相应的事件处理器就会对发生的事件进行处理。
事件监听器在进行工作时,可分为如下几个步骤:
- 将监听器绑定到事件源,也就是注册监听器。
- 事件发生时会触发监听器的成员方法,即事件处理器,传递事件对象。
- 事件处理器通过事件对象获得事件源,并对事件源进行处理。
在开发 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 中添加如下配置
com.xxx.MyListener
3. 创建测试页面
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
$Title$
${pageContext.session.getAttribute("name")}
<% session.setAttribute("name", "666666"); %>
4. 设置监听超时信息
在 web.xml 中添加如下配置:
1
5. 查看运行结果
1 分钟后控制台输出 session 销毁信息
监听对象属性变更1. 创建测试页面
test.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
Insert title here
这是一个测试对象属性信息监听器的页面
<%
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");
%>
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. 运行结果



