Filter简介
实现了Filter接口,则把这个java类称之为过滤器Filter。通过Filter技术,开发人员可以实现用户在访问某个目标资源之前,对访问的请求和响应进行拦截
原理图
如何实现拦截
Filter接口中有一个doFilter方法,当开发人员编写好Filter,并配置对哪个web资源进行拦截后,WEB服务器每次在调用web资源的service方法之前,都会先调用一下filter的doFilter方法,因此,在该方法内编写代码可达到如下目的:
调用目标资源之前,让一段代码执行是否调用目标资源(即是否让用户访问web资源)。 web服务器在调用doFilter方法时,会传递一个filterChain对象进来,filterChain对象是filter接口中最重要的一个对象,它也提供了一个doFilter方法,开发人员可以根据需求决定是否调用此方法,调用该方法,则web服务器就会调用web资源的service方法,即web资源就会被访问,否则web资源不会被访问。
Filter链
多个Filter组合起来称之为一个Filter链。 web服务器根据Filter在web.xml文件中的注册顺序,决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第2个的filterdoFilter方法,如果没有,则调用目标资源。
Filter的生命周期
空参构造() 1次
init() 1次
doFilter(请求,响应,过滤器链) N次,与请求次数有关
destory() 1次
Filter是一个单例
init(FilterConfig filterConfig)throws ServletException:
Filter的创建和销毁由WEB服务器负责。 web 应用程序启动时,web 服务器将创建Filter 的实例对象,并调用其init方法,完成对象的初始化功能,从而为后续的用户请求作好拦截的准备工作(注:filter对象只会创建一次,init方法也只会执行一次。 )
destroy():
在Web容器卸载 Filter 对象之前被调用。该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源。
web.xml的配置
<filter>
<filter-name>FilterDemo5</filter-name>
<filter-class>cn.itcast.web.filter.FilterDemo5</filter-class>
<init-param>
<param-name>html</param-name>
<param-value>86400</param-value>
</init-param>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>FilterDemo5</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- <filter-name>用于为过滤器指定一个名字,该元素的内容不能为空。
- <filter-class>元素用于指定过滤器的完整的限定类名。
- <init-param>元素用于为过滤器指定初始化参数
- <param-name>指定参数的名字
- <param-value>指定参数的值
6 <filter-mapping>
用于设置一个 Filter 所负责拦截的资源。
一个Filter拦截的资源可通过两种方式来指定:
1资源访问的请求路径
<filter-name>子元素用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名字
<url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)
2Servlet名称
<servlet-name>指定过滤器所拦截的Servlet名称。
7<dispatcher>
指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST。用户可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截。
REQUEST:
当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
INCLUDE:
如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。 FORWARD:
如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。 ERROR:
如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
Servlet名称的案例
<filter-mapping>
<filter-name>testFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
具体案例
web.xml
<filter>
<filter-name>FilterDemo4</filter-name>
<filter-class>cn.itcast.web.filter.FilterDemo4</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>FilterDemo4</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>FilterDemo5</filter-name>
<filter-class>cn.itcast.web.filter.FilterDemo5</filter-class>
<init-param>
<param-name>html</param-name>
<param-value>86400</param-value>
</init-param>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>FilterDemo5</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
代码
//针对POST请求和响应的编码方式处理
public class FilterDemo4 implements Filter {
private FilterConfig filterConfig;
public FilterDemo4(){
}
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("FilterDemo4_init");
this.filterConfig = filterConfig;
}
//Web容器调用
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
System.out.println("FilterDemo4_doFilter");
Enumeration<String> enums = filterConfig.getInitParameterNames();
while(enums.hasMoreElements()){
String key = enums.nextElement();
String value = filterConfig.getInitParameter(key);
System.out.println(key+":"+value);
}
String encoding = filterConfig.getInitParameter("encoding");
response.setContentType("text/html;charset="+encoding);
//放行请求[类似于函数调用]
chain.doFilter(request,response);
}
public void destroy() {
}
//禁止浏览器缓存动态资源,例如JSP资源
public class FilterDemo5 implements Filter {
private FilterConfig filterConfig;
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("FilterDemo5_init");
this.filterConfig = filterConfig;
}
public void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException {
System.out.println("FilterDemo5_doFilter");
//NO将父子接口强转
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//NO1取得客户端访问的资源的URI,形式/day19/login.jsp
String uri = request.getRequestURI();
//NO2判段是否以jsp结尾,即动态资源
if(uri!=null && uri.endsWith("jsp")){
//NO3如果是动态资源,设置三个响应头通知浏览器不缓存
response.setHeader("expires","-1");
response.setHeader("cache-control","no-cache");
response.setHeader("pragma","no-cache");
}else if(uri!=null && uri.endsWith("html")){
//NO4如果是静态资源,缓存一定的时间
String strHtml = filterConfig.getInitParameter("html");
long time = System.currentTimeMillis()+Integer.parseInt(strHtml)*1000;
//time为毫秒值
response.setDateHeader("expires",time);
response.setHeader("cache-control",time/1000+"");
response.setHeader("pragma",time/1000+"");
}
//NO5 放行请求[类似于函数调用]
chain.doFilter(request,response);
}
public void destroy() {
}
}
访问路径
结果:
FilterDemo4_doFilter
encoding:UTF-8
FilterDemo5_doFilter