一、了解过滤器
过滤器是可以拦截访问资源的请求、资源的响应或者同时拦截两者的应用组件,它们将以某种方式作用于这些请求或响应。过滤器可以检测和修改请求或响应,它们甚至可以拒绝、重定向或转发请求。如同Servlet一样,过滤器可以在部署描述符中以编程或者声明的方式进行声明,它们可以有初始化参数,并且可以访问ServletContext。
二、创建、声明、映射过滤器
过滤器在初始化时将调用init方法,它可以访问过滤器的配置、初始化参数和ServletContext。当请求进入到过滤器中时,doFilter方法将会被调用,在doFilter之中,可以拒绝请求或者调用FilterChain对象的doFilter方法;可以修改请求或响应;可以封装请求或响应对象。应用程序在关闭时,将调用过滤器的destroy方法。
1、了解过滤器链
尽管只有一个Servlet可以处理请求,但可以使用许多过滤器拦截请求。调用FilterChain.doFilter()方法将触发过滤器链的持续执行,如果当前处理器是过滤器链的最后一个过滤器,那么调用FilterChain.doFilter()方法将把控制权返回到Servlet容器中,它将把请求传递给Servlet。如果当前的过滤器没有调用FilterChain.doFilter()方法,那么过滤器链将会被中断,Servlet和所有剩余的过滤器都无法再处理该请求。
过滤器链的工作原理:
过滤器链的这种工作方式非常像栈(确实,一系列方法的执行都运行在Java栈上)。当请求来临时,它将首先进入第一个过滤器,该过滤器将被添加到栈中。当过滤器链继续执行时,下一个过滤器将被添加到栈中。一直到请求进入到Servlet中,它是被添加到栈中的最后一个元素。当请求完成并且Servlet的service方法也返回时,Servlet将从栈中移除,然后控制权被返回到最后一个过滤器,当它的doFilter方法返回时,该过滤器将从栈中移除,控制也将返回到之前的过滤器中。一直到控制权返回到第一个过滤器中,当它的doFilter方法也返回时,它将被从栈中移除,此时栈是空的,请求处理也就完成了。因此,过滤器可以在目标Servlet处理请求的前后执行某些操作。
2、映射到URL模式和Servle名称
同Servlet一样,过滤器可以映射到URL模式,这会决定哪个或哪些过滤器拦截某个请求。任何匹配某个过滤器的URL模式的请求在被匹配的Servlet处理之前将首先进入该过滤器。通过使用URL模式,我们不止可以拦截Servlet的请求,还可以拦截其他资源,例如图片、CSS文件、JavaScript文件等。
与映射到URL上相反,我们可以把它映射到一个或多个Servlet名称,如果请求匹配于某个Servlet,容器将寻找所有匹配该Servlet名称的过滤器,并将它们应用到请求上。
3、映射到不同的请求派发器类型
① 普通请求
这些请求来自于客户端,并包含了容器中特定Web应用程序的目标URL;
② 转发请求
当代码调用RequestDispatcher的forward方法或者使用<jsp:forward>标签时将触发这些请求;
③ 包含请求
使用<jsp:include>标签或者调用RequestDispatcher的include方法时,将会产生一个不同的、与原始请求相关的内部请求;
④ 错误资源请求
这些是访问处理HTTP错误的错误页面的请求。
④ 异步请求
这些请求是在处理任何其他请求的过程中,由AsyncContext派发的请求。
注意:在Servlet3.0中,Servlet的service方法将在请求的响应发送之前返回,所以过滤器链的能力受到了损害。为了作出补偿,Servlet3.0为AsyncContext派发的过滤器拦截请求添加了新的异步派发类型。实现异步过滤器要小心,因为它们可以被单个异步请求调用多次(多个不同的线程)。
4、使用部署描述符配置过滤器
下面看一个简单的过滤器在部署描述符中的配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.mengfei.hellofilter.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/do/*</url-pattern>
<url-pattern>/bur</url-pattern>
<servlet-name>myServlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>ASYNC</dispatcher>
</filter-mapping>
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>com.mengfei.hellofilter.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/index</url-pattern>
</servlet-mapping>
</web-app>
此时,过滤器会处理所有相对于应用程序的URL——/do/*和/bur的请求,以及任何最终由myServlet处理的请求。有效的<dispatcher>类型有REQUEST、FORWARD、INCLUDE、ERROR、ASYNC,过滤器可以映射0个或多个<dispatcher>元素,如果没有指定,那么默认的就是REQUEST。
与Servlet不同的是,过滤器不可以在第一个请求到达时加载,过滤器的init()方法总是在应用程序启动时调用,在ServletContextListener初始化之后,Servlet初始化之前,它们将按照部署描述符中出现的顺序依次加载。
5、使用注解配置过滤器
&