JSP 过滤器 (filter)
JSP 过滤器(filter) 可以动态地拦截请求和响应,以获取或改变包含在请求或响应中的信息
可以将一个或多个过滤器附加到一个 Servlet 或一组 Servlet,也可以将一个或多个过滤器附加到 JavaServer Pages (JSP) 文件和 HTML 页面
JSP 过滤器可以实现以下目录
- 在客户端的请求访问后端资源之前,拦截这些请求
- 在服务器的响应发送回客户端之前,处理这些响应
JSP 规范建议的过滤器类型有
- 身份验证过滤器(Authentication Filters)
- 数据压缩过滤器(Data compression Filters)
- 加密过滤器(Encryption Filters)
- 触发资源访问事件过滤器
- 图像转换过滤器(Image Conversion Filters)
- 日志记录和审核过滤器(Logging and Auditing Filters)
- MIME-TYPE 链过滤器(MIME-TYPE Chain Filters)
- 标记化过滤器(Tokenizing Filters)
- XSL/T 过滤器(XSL/T Filters),转换 XML 内容
过滤器在 Web 部署描述符(web.xml)中定义
当 Web 容器启动 Web 应用程序时,它会为 web.xml 中的每一个过滤器创建一个实例
Filter 的执行顺序与在 web.xml 配置文件中的配置顺序一致
Servlet 过滤器方法
Servlet 过滤器是一个实现了 javax.servlet.Filter 接口的 Java 类
javax.servlet.Filter 接口定义了三个方法:
-
- public void doFilter (ServletRequest, ServletResponse, FilterChain)
- 该方法完成实际的过滤操作,当客户端请求方法与过滤器设置匹配的URL时,Servlet容器将先调用过滤器的doFilter方法 FilterChain用户访问后续过滤器
-
- public void init(FilterConfig filterConfig)
- web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,读取web.xml配置,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(filter对象只会创建一次,init方法也只会执行一次)
开发人员可以通过 init 方法的参数,可获得代表当前 filter 配置信息的FilterConfig对象
-
- public void destroy()
- Servlet 容器在销毁过滤器实例前调用该方法,在该方法中释放 Servlet 过滤器占用的资源
FilterConfig 使用
Filter 的 init 方法中提供了一个 FilterConfig 对象
如 web.xml 文件配置如下:
<filter> <filter-name>LogFilter</filter-name> <filter-class>cn.twle.demo.LogFilter</filter-class> <init-param> <param-name>site</param-name> <param-value>简单教程</param-value> </init-param> </filter>
在 init 方法使用 FilterConfig 对象获取参数
public void init(FilterConfig config) throws ServletException { // 获取初始化参数 String site = config.getInitParameter("site"); // 输出初始化参数 System.out.println("网站名称: " + site); }
JSP 过滤器范例
下面的过滤器将输出网站名称和地址
cn.twle.demo.LogFilter.java
// author: 简单教程(www.twle.cn) // Copyright © 2015-2065 www.twle.cn. All rights reserved. package cn.twle.demo; import javax.servlet.*; import java.util.*; //实现 Filter 类 public class LogFilter implements Filter { public void init(FilterConfig config) throws ServletException { // 获取初始化参数 String site = config.getInitParameter("site"); // 输出初始化参数 System.out.println("网站名称: " + site); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException { // 输出站点名称 System.out.println("站点网址:http://www.twle.cn"); // 把请求传回过滤链 chain.doFilter(request,response); } public void destroy() { /* 在 Filter 实例被 Web 容器从服务移除之前调用 */ } }
cn.twle.demo.DisplayHeaderServlet.java
DisplayHeader.java 文件代码如下:
// author: 简单教程(www.twle.cn) // Copyright © 2015-2065 www.twle.cn. All rights reserved. package cn.twle.demo; import java.io.IOException; import java.io.PrintWriter; import java.util.Enumeration; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class DisplayHeaderServlet extends HttpServlet { // 处理 GET 方法请求的方法 public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 设置响应内容类型 response.setContentType("text/html;charset=UTF-8"); PrintWriter out = response.getWriter(); String title = "HTTP Header 请求范例 - 简单教程(www.twle.cn)"; String docType = "<!DOCTYPE html> \n"; out.println(docType + "<meta charset=\"utf-8\"><title>" + title + "</title>" + "<style>table, th, td {border: 1px solid #ddd;border-spacing: 0;border-collapse: collapse;text-align: left;}th {height:32px;line-height: 32px}th,td {padding:5px 10px;}</style>" + "<p>" + title + "</h1>\n" + "<table width=\"100%\">\n" + "<tr>\n" + "<th>Header 名称</th><th>Header 值</th>\n"+ "</tr>\n"); Enumeration headerNames = request.getHeaderNames(); while(headerNames.hasMoreElements()) { String paramName = (String)headerNames.nextElement(); out.print("<tr><td>" + paramName + "</td>\n"); String paramValue = request.getHeader(paramName); out.println("<td> " + paramValue + "</td></tr>\n"); } out.println("</table>"); } // 处理 POST 方法请求的方法 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
Web.xml 中的 Servlet 过滤器映射(Servlet Filter Mapping)
定义过滤器,然后映射到一个 URL 或 Servlet,这与定义 Servlet,然后映射到一个 URL 模式方式大致相同。在部署描述符文件 web.xml 中为 filter 标签创建下面的条目:
<?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_3_1.xsd" version="3.1"> <filter> <filter-name>LogFilter</filter-name> <filter-class>cn.twle.demo.LogFilter</filter-class> <init-param> <param-name>site</param-name> <param-value>简单编程</param-value> </init-param> </filter> <filter-mapping> <filter-name>LogFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <!-- 类名 --> <servlet-name>DisplayHeaderServlet</servlet-name> <!-- 所在的包 --> <servlet-class>cn.twle.demo.DisplayHeaderServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>DisplayHeaderServlet</servlet-name> <!-- 访问的网址 --> <url-pattern>/display_header</url-pattern> </servlet-mapping> <servlet> <display-name>UploadServlet</display-name> <servlet-name>UploadServlet</servlet-name> <servlet-class>UploadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>UploadServlet</servlet-name> <url-pattern>/form/upload</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/upload/*</url-pattern> </servlet-mapping> </web-app>
上述过滤器适用于所有的 Servlet,因为我们在配置中指定 /*
如果只想在少数的 Servlet 上应用过滤器,则可以指定一个特定的 Servlet 路径
现在试着以常用的方式调用任何 Servlet,我们会看到在 Web 服务器中生成的日志
在浏览器上输入 http://localhost:8080/jsp/display_header 显示结果如下
WEB 服务器日志显示如下
使用多个过滤器
我们的应用程序可以根据不同的需求定义多个不同的过滤器
假设我们定义了两个过滤器:cn.twle.demo.LogFilter 和 cn.twle.demo.AuthenFilter
那么在 web.xml 中就可以做如下的配置
<filter> <filter-name>LogFilter</filter-name> <filter-class>cn.twle.demo.LogFilter</filter-class> <init-param> <param-name>test-param</param-name> <param-value>Initialization Paramter</param-value> </init-param> </filter> <filter> <filter-name>AuthenFilter</filter-name> <filter-class>cn.twle.demo.AuthenFilter</filter-class> <init-param> <param-name>test-param</param-name> <param-value>Initialization Paramter</param-value> </init-param> </filter> <filter-mapping> <filter-name>LogFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>AuthenFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
过滤器的应用顺序
Servlet 或 JSP 容器会根据 web.xml 中过滤器定义的顺序应用过滤器。上面的 web.xml 文件中会优先应用 LogFilter,然后再应用 AuthenFilter
如果要反转过滤器的顺序,只需要在 web.xml 文件中反转 filter-mapping 即可
web.xml 中的 filter-mapping 元素的顺序决定了 Web 容器应用过滤器到 Servlet 的顺序。若要反转过滤器的顺序,您只需要在 web.xml 文件中反转 filter-mapping 元素即可
就像下面这样
<filter-mapping> <filter-name>AuthenFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>LogFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
web.xml配置各节点说明
-
<filter>
- 指定一个过滤器
-
<filter-name>
- 用于为过滤器指定一个名字,该元素的内容不能为空
-
<filter-class>
- 元素用于指定过滤器的完整的限定类名
-
<init-param>
- 元素用于为过滤器指定初始化参数,它的子元素
<param-name>
指定参数的名字,<param-value>
指定参数的值
在过滤器中,可以使用
FilterConfig
接口对象来访问初始化参数。
-
<filter-mapping>
- 元素用于设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径
-
<filter-name>
- 子元素用于设置filter的注册名称。该值必须是在
<filter>
元素中声明过的过滤器的名字
-
<url-pattern>
- 设置 filter 所拦截的请求路径(过滤器关联的URL样式)
-
<servlet-name>
- 指定过滤器所拦截的Servlet名称
-
<dispatcher>
- 指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是
REQUEST
,INCLUDE
,FORWARD
和ERROR
之一,默认REQUEST
。用户可以设置多个<dispatcher>
子元素用来指定 Filter 对资源的多种调用方式进行拦截
-
<dispatcher>
- 子元素可以设置的值及其意义
REQUEST
:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。INCLUDE
:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。FORWARD
:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。ERROR
:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用