JavaWeb Filter
Posted Mr.Aaron
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaWeb Filter相关的知识,希望对你有一定的参考价值。
1. 过滤器概述
1.1. 什么是过滤器
Filter译为过滤器,是JavaWeb的三大组件之一,用于在Servlet之外对Request或者Response进行修改。对于Web应用程序来说,过滤器是一个驻留在服务器端的Web组件,它可以截取客户端和服务器端之间的请求与响应信息。
1.2. 发展历史
由于Servlet规范是开放的,借助于公众与开源社区的力量,Servlet规范越来越科学,功能也越来越强大。2000年,Sun公司在Servlet2.3规范中添加了Filter功能,并在Servlet2.4中对Filter进行了细节上的补充。目前主流版本为Servlet2.5的Filter。
1.3. 运行原理
Servlet是服务器端用于处理客户端的请求与响应的,而Filter就是介于客户端与服务器端拦截客户端的请求或服务器端的响应,并对其修改或过滤。具体实现流程如下:
当客户端向服务器端发送一个请求时,如果有对应的过滤器进行拦截,过滤器可以改变请求的内容、或者重新设置请求协议的相关信息等,然后再将请求发送给服务器端的Servlet进行处理。当Servlet对客户端做出响应时,过滤器同样可以进行拦截,将响应内容进行修改或者重新设置后,再响应给客户端浏览器。在上述过程中,客户端与服务器端并不需要知道过滤器的存在。
在一个Web应用程序中,可以部署多个过滤器进行拦截,这些过滤器组成了一个过滤器链。过滤器链中的每个过滤器负责特定的操作和任务,客户端的请求在这些过滤器之间传递,直到服务器端的Servlet。具体执行流程如下:
1.4. 第一个过滤器
在Servlet API中提供了一个Filter接口,实现过滤器只需要实现该接口即可。以下是Filter接口的API:
Method Summary |
|
void |
destroy() |
void |
doFilter(ServletRequest request, ServletResponse response, FilterChain chain) |
void |
init(FilterConfig filterConfig) |
实现过滤器的具体步骤如下:
- 创建一个Java类,并实现Filter接口,重写该接口的方法。
public class MyFitler implements Filter { /** * init()方法用于Filter的初始化 */ public void init(FilterConfig filterConfig) throws ServletException { System.out.println("执行了Filter的init()方法..."); } /** * doFilter()方法用于Filter的拦截 */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("执行了Filter的doFilter()方法..."); } /** * destory()方法用于Filter的销毁 */ public void destroy() { System.out.println("执行了Filter的destroy()方法..."); } }
- 在Web工程的web.xml文件中配置过滤器。
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- 配置过滤器 --> <filter> <!-- 配置过滤器的名称 --> <filter-name>MyFitler</filter-name> <!-- 配置对应过滤器类的完整路径 --> <filter-class>app.java.fitler.MyFitler</filter-class> </filter> <!-- 配置过滤器的拦截路径 --> <filter-mapping> <!-- 配置过滤器的名称 --> <filter-name>MyFitler</filter-name> <!-- 配置过滤器的拦截的路径 --> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
- 创建Web动态资源Servlet。
public class HelloServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); PrintWriter out = response.getWriter(); out.println("<h1>Hello Servlet.</h1>"); out.flush(); out.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
- 在Web工程的web.xml文件中配置Servlet。
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>HelloServlet</servlet-name> <servlet-class>app.java.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloServlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>
- 创建Web工程的静态资源JSP页面。
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>hello.jsp</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> </head> <body> <h1>Hello JSP.</h1> </body> </html>
- 发布Web工程并访问,无论是访问动态资源Servlet还是静态资源JSP,过滤器都会拦截,并执行过滤器的doFilter()方法。
- 这时访问的Servlet或者JSP并没有被执行,原因是过滤器只进行了拦截,并没有将请求发送到对应的Servlet或者JSP。在过滤器的doFilter()方法中执行FilterChain对象的doFilter()方法将进行放行。
public class MyFitler implements Filter { /** * init()方法用于Filter的初始化 */ public void init(FilterConfig filterConfig) throws ServletException { System.out.println("执行了Filter的init()方法..."); } /** * doFilter()方法用于Filter的拦截 */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("执行了Filter的doFilter()方法..."); chain.doFilter(request, response); } /** * destory()方法用于Filter的销毁 */ public void destroy() { System.out.println("执行了Filter的destroy()方法..."); } }
2. 深入过滤器
2.1. 生命周期
Servlet API提供的Filter接口中含有三个方法,分别为init()、doFilter()和destroy()方法。该三个方式就是Filter的生命周期方法。
- Filter的构造函数
- 在Tomcat服务器启动时执行。
- 在Filter的生命周期中只执行一次。
- init(FilterConfig)方法
- 在Tomcat服务器启动时执行。
- 在Filter的生命周期中只执行一次。
- 用于Filter的初始化工作。
- doFilter(ServletRequest, ServletResponse, FilterChain)方法
- 在每次拦截时执行。
- 在Filter的生命周期中只执行多次。
- 用于Filter的拦截处理工作。
- destroy()方法
- 在Tomcat服务器关闭时执行。
- 在Filter的生命周期中只执行一次。
- 用于Filter的销毁工作。
2.2. 过滤器链
在一个Web应用程序中,可以部署多个过滤器进行拦截,这些过滤器组成了一个过滤器链。完成过滤器链的功能,具体步骤如下:
- 创建一个Java类,并实现Filter接口,重写该接口的方法。
public class MyFitler1 implements Filter { /** * init()方法用于Filter的初始化 */ public void init(FilterConfig filterConfig) throws ServletException { System.out.println("执行了Filter1的init()方法..."); } /** * doFilter()方法用于Filter的拦截 */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("执行了Filter1的doFilter()方法..."); } /** * destory()方法用于Filter的销毁 */ public void destroy() { System.out.println("执行了Filter1的destroy()方法..."); } }
- 再创建一个Java类,并实现Filter接口,重写该接口的方法。
public class MyFilter2 implements Filter { public void init(FilterConfig filterConfig) throws ServletException { System.out.println("执行了Filter2的init()方法..."); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("执行了Filter2的doFilter()方法..."); } public void destroy() { System.out.println("执行了Filter2的destroy()方法..."); } }
- 在Web工程的web.xml文件中配置过滤器。
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- 配置过滤器 --> <filter> <!-- 配置过滤器的名称 --> <filter-name>MyFitler</filter-name> <!-- 配置对应过滤器类的完整路径 --> <filter-class>app.java.fitler.MyFitler</filter-class> </filter> <!-- 配置过滤器的拦截路径 --> <filter-mapping> <!-- 配置过滤器的名称 --> <filter-name>MyFitler</filter-name> <!-- 配置过滤器的拦截的路径 --> <url-pattern>/*</url-pattern> </filter-mapping> <filter> <filter-name>MyFitler2</filter-name> <filter-class>app.java.fitler.MyFilter2</filter-class> </filter> <filter-mapping> <filter-name>MyFitler2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
需要注意的是,FilterChain的doFilter()方法执行时,如果只有一个过滤器的话,执行该方法会将请求发送给服务器端的动态或静态资源。如果是过滤器链的话,只有在执行过滤器链的最后一个过滤器的FilterChain的doFilter()方法时,才会将请求发送给服务器端的动态或静态资源。如果不是在过滤器链的最后一个过滤器的FilterChain的doFilter()方法时,将请求发送给下一个过滤器进行拦截。
在过滤器链中的过滤器执行的先后顺序是按照Web工程的web.xml文件配置过滤器的先后顺序被执行。
2.3. FilterConfig
在过滤器接口的init()方法中提供了FilterConfig参数,通过该参数可以获取web.xml配置过滤器的参数内容,或者获取ServletContext对象等。FilterConfig API内容如下:
Method Summary |
|
getFilterName() |
|
getInitParameter(String name) |
|
getInitParameterNames() |
|
getServletContext() |
具体使用方式如下:
- 创建一个Java类,并实现Filter接口,重写该接口的方法。
public class MyFitler implements Filter { public void init(FilterConfig filterConfig) throws ServletException { System.out.println("执行了Filter的init()方法..."); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("执行了Filter的doFilter()方法..."); } public void destroy() { System.out.println("执行了Filter的destroy()方法..."); } }
- 在Web工程的web.xml文件中配置过滤器,并且设置初始化参数内容。
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <filter> <filter-name>MyFitler</filter-name> <filter-class>app.java.fitler.MyFitler</filter-class> <init-param> <param-name>longestory</param-name> <param-value>http://www.baidu.com.com</param-value> </init-param> </filter> <filter-mapping> <filter-name>MyFitler</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
- 在过滤器的init()方法中获取配置文件的初始化参数。
public class MyFitler implements Filter { public void init(FilterConfig filterConfig) throws ServletException { System.out.println("执行了Filter的init()方法..."); System.out.println(filterConfig.getInitParameter("longestory")); } public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("执行了Filter的doFilter()方法..."); } public void destroy() { System.out.println("执行了Filter的destroy()方法..."); } }
需要注意的是,通过getInitParameter()方法获取的初始化参数是私有参数。只有当前过滤器才能获取到,而其他过滤器并不能访问。如果配置全局初始化参数,可以使用<context-param>来配置,并使用ServletContext对象获取。
2.4. Filter映射配置
过滤器需要配置在web.xml中才能生效。一个过滤器需要配置<filter>和<filter-mapping>标签,例如如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <!-- 配置过滤器 --> <filter> <!-- 配置过滤器的名称 --> <filter-name>MyFitler</filter-name> <!-- 配置对应过滤器类的完整路径 --> <filter-class>app.java.fitler.MyFitler</filter-class> </filter> <!-- 配置过滤器的拦截路径 --> <filter-mapping> <!-- 配置过滤器的名称 --> <filter-name>MyFitler</filter-name> <!-- 配置过滤器的拦截的路径 --> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
<filter>配置过滤器的名称,实现类以及初始化参数。<filter-mapping>配置当前过滤器拦截的路径。<filter-mapping>中的<url-pattern>标签用于配置当前过滤器拦截的路径,配置方式与Servlet的<url-pattern>配置方式类似,共有三种方式:
- 完全匹配
- 目录匹配
- 扩展名匹配
如果需要拦截的是Servlet的话,有两种方式配置拦截路径:
- 使用<url-pattern>标签:<url-pattern>/hello</url-pattern>
- 使用<servlet-name>标签:<servlet-name>HelloServlet</servlet-name>
<dispatcher>标签配置到达Servlet的方法,有四种取值:REQUEST、FORWARD、INCLUDE和ERROR。可以同时配置多个<dispatcher>标签,如果没有配置<dispatcher>标签,默认为REQUEST。这四种取值的区别如下:
- REQUEST:表示仅当直接请求Servlet时才生效。
- FORWARD:表示仅当某Servlet通过FORWARD到该Servlet时才生效。
- INCLUDE:JSP中可以通过<jsp:include>标签请求某Servlet或调用RequestDispatcher的include()方法请求某Servlet,仅这种情况下有效。
- ERROR:JSP中可以通过<%@ page errorPage=”error.jsp”>标签指定错误处理页面,仅这种情况下有效。
<url-pattern>标签与<dispatcher>标签的关系是“且”的关系。只有满足<url-pattern>标签的条件,且满足<dispatcher>标签的条件时,当前过滤器才能生效。
3. 过滤器案例
3.1. 全站乱码案例
中文乱码问题一直都是Web应用开发的问题,想要解决整个Web应用程序的中文乱码问题,可以如下操作:
- 创建一个Java类继承于HttpServletRequestWrapper类,用于重写HttpServletRequest,解决GET方式的中文乱码问题。
public class MyRequest extends HttpServletRequestWrapper { public MyRequest(HttpServletRequest request) { super(request); } @Override public String getParameter(String name) { String value = super.getParameter(name); if (getMethod().equalsIgnoreCase("GET")) { try { value = new String(value.getBytes("ISO-8859-1"),"utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } return value; } }
- 创建一个过滤器用于解决整个Web应用程序的中文乱码问题。
public class EncodingFilter implements Filter { public void init(FilterConfig filterConfig) throws ServletException {} public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); MyRequest req = new MyRequest((HttpServletRequest)request); chain.doFilter(req, response); } public void destroy() {} }
- 配置Web工程的web.xml文件。
<?javaWeb 使用 filter 处理 html 标签问题学习日记:关于javaweb filter中过滤了css文件的解决方法