JavaWeb三大组件:
Servlet、Listener、Filter
都需要在web.xml中进行配置,Listener中的两个感知监听器不需要配置。
——过滤器概述
过滤器是JavaWeb的三大组件之一,它与Servlet很相似,不过过滤器是用来拦截请求的,而不是处理请求的。
当用户请求某个Servlet或其他资源(JSP、css、html)时,会先执行部署在这个请求上的Filter,如果Filter“放行”,那么会继续执行用户请求的资源,如果Filter“不放行”,那么就不会执行用户请求的资源。
其实可以这么理解,当用户请求某个Servlet时,Tomcat会去执行注册在这个请求上的Filter,然后是否“放行”由Filter来决定,可以理解为,Filter来决定是否调用Servlet,当执行完成Servlet的代码后,还会执行FilterChain中doFilter()方法后面的代码。
——编写一个过滤器
Filter是单例的。
1、编写一个类,并且实现Filter接口
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* 编写过滤器
* 1、写一个类,并且实现Filter接口
* 2、在web.xml中进行相关配置
*
* @author 31067
*
*/
public class AFilter implements Filter {
/**
* 在销毁之前执行,用来对非内存资源进行释放
*/
@Override
public void destroy() {
System.out.println("销毁");
}
/**
* 每次过滤时都会执行
*/
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain chain) throws IOException, ServletException {
System.out.println("拦截");
chain.doFilter(request, response);
System.out.println("放行了");
}
/**
* 在Filter创建后马上调用,用来做初始化操作
*/
@Override
public void init(FilterConfig arg0) throws ServletException {
System.out.println("出生");
}
}
2、在web.xml文件中进行配置
<filter>
<filter-name>xxx</filter-name>
<filter-class>com.wyc.web.filter.AFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>xxx</filter-name>
<url-pattern>/*</url-pattern> //通常会使用通配符进行url-pattern的配置 /web/*
</filter-mapping>
——Filter的生命周期
1、Filter接口生命周期方法:
* void init(FilterConfig config)
在服务器启动时会创建Filter的实例对象,并且每个类型的Filter只会创建一个实例对象,也就是说Filter是单例的。
在创建完Filter实例后,会马上调用init()方法完成初始化操作,这个方法只会被执行一次。
* void destory()
服务器会在创建Filter对象之后,把Filter放到内存中一直使用,通常不会销毁它,一般会在服务器关闭时销毁Filter对象。
在销毁Filter对象之前,服务器会调用Filter对象的destory()方法。
* void doFilter(ServletRequest , ServletResponse , FilterChain)
这个方法会在用户每次访问“目标资源<url-pattern>/index.jsp</url-pattern>”时执行。
如果需要“放行”,那么需要调用FilterChain对象的doFilter(ServletRequest, ServletResponse)方法,如果不调用该方法,则无法请求目标资源。
2、生命周期方法中的参数
FilterConfig:
* 获取初始化参数:getInitParameter();
* 获取所有初始化参数的名称:Enumeration getInitParameterNames()。
* 获取过滤器名称:getFilterName();
* 获取application:getServletContext();(获取当前上下文对象)
FilterChain:
* doFilter(ServletRequest, ServletResponse)
执行“放行”功能,使请求可以访问到资源。
相当于调用了请求Servlet的Service方法。
如果当前过滤器是最后一个过滤器,那么调用chain.doFilter()方法表示执行目标资源,如果不是最后一个过滤器,那么chain.doFilter()表示执行下一个过滤器的doFilter()方法。
面试:Filter接口的doFilter()方法和FilterChain的doFilter()方法有什么区别?
——过滤器的四种拦截方式
拦截方式:
* 请求:DISPATCHER
* 转发:FORWARD
* 包含:INCLUDE
* 错误:ERROR
如果不写,则默认<dispatcher>REQUEST</dispatcher>,如果只写一种,则默认拦截方式就不存在了。
拦截方式需要在<filter-mapping>中进行配置:
<filter-mapping>
<filter-name>BFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher> // 默认拦截方式
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
——过滤器的执行顺序
<filter-mapping>中的配置执行顺序决定了过滤器的执行顺序。
先配置先执行。
XML配置如下:
<web-app>
<filter>
<filter-name>AFilter</filter-name>
<filter-class>com.wyc.web.filter.AFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>BFilter</filter-name>
<filter-class>com.wyc.web.filter.BFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>BFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
执行效果如下:(与栈相似,当chain的doFilter()方法执行完毕后,还会继续执行剩余代码)
AFilter...start
BFilter...start
index.jsp
BFilter...end
AFilter...end
——Filter的应用场景
1、执行目标资源之前做预处理工作,例如设置编码,这种操作通常都会放行,只是在目标资源执行之前做一些准备工作。
几乎在所有的Servlet中都需要写:request.setCharacterEncoding();,这就可以把代码放到过滤器中。
2、通过条件判断是否放行,例如校验当前用户是否已经登录,或者用户IP是否被禁用。
3、在目标资源执行后,做一些后续的特殊处理工作,例如把目标资源输出的数据进行处理。
也称为回程拦截。
——Filter设置目标资源
在web.xml文件中部署Filter时,可以通过“*”来执行目标资源:
<filter-mapping>
<filter-name>myfilter</filter-name>
<url-pattern>/*</url-pattern> // 表示过滤所有资源
</filter-mapping>
这一特性与Servlet完全相同,通过这一特性,可以在用户访问敏感资源时,执行过滤器,例如:<url-pattern>/admin/*</url-pattern>,可以把所有管理员才能访问的资源放到/admin路径下,这时就可以通过过滤器来校验用户身份了。
还可以为<filter-mapping>指定目标资源为某个Servlet,例如:
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.wyc.servlet.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyServlet</servlet-name>
<url-pattern>/MyServlet</url-pattern>
</servlet-mapping>
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.wyc.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilger</filter-name>
<servlet-name>MyServlet</servlet-name> // 访问指定的Servlet
</filter-mapping>
当用户访问:localhost:8080/FilterDemo/MyServlet时,会执行名称为MyServlet的Servlet,这时会执行绑定的过滤器。
<filter-mapping>中可以写以下四种标签:
<filter-name>
<url-pattern>
<dispatcher>
<servlet-name>