11-过滤器
## 介绍
首先来看,过滤器在整个Web流程的哪里:
从上面的图,我们可以看出来,当浏览器发送请求给服务器时,会先执行过滤器,再访问Web资源;服务器响应Response时,也会先执行过滤器,再发送请求资源给浏览器。
作用
- 拦截Http服务器,帮助Http服务器检测当前请求合法性
- 拦截Http服务器,对当前请求进行增强操作
例如,在没有过滤器时,如果要处理中文乱码情况,需要在每个Sevlet中都设定编码,但是这样,代码重复率很高;有了过滤器,情况就不一样了,只要在过滤器中指定了编码,那么就可以使全站的Web资源都是使用该编码。
当然,过滤器的作用很多,还可以过滤一些敏感的字符串,权限验证(规定只有带Session或Cookie的浏览器才能访问web资源)等等。
Filter接口(过滤器接口)
- 来自于Sevlet规范下接口
- Filter接口实现类由开发人员提供,Http服务器不提供实现
Filter接口开发类步骤
- 创建一个Java类实现Filter接口
- 重写Filter接口中的doFilter方法
- 在web.xml文件中将过滤器接口实现类注册到Http服务器
Filter接口 API
Filter接口有三个方法
- void init(FilterConfig filterconfig)
- void destroy()
- void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
前两个方法很好理解,它们只在Web服务器加载和销毁时被执行,且只会被执行一次。
比较重要的是doFilter方法:有三个参数,前面两个参数和doGet,doPost方法参数一样,请求参数和响应参数,ServletRequest是HttpServletRequest的父接口。
第三个参数FilterChain类型,也是一个接口,该接口只有一个方法:doFilter(ServletRequest var1, ServletResponse var2)。
感觉有点糊涂了,怎么有一个doFilter方法。
可以这样理解:过滤器不止一个,那么就需要管理这些过滤器,在Java中使用了链式结构,把所有的过滤器都放在了FilterChain中,如果符合条件,就执行下一个过滤器,一直到没有符合条件的过滤器,就执行目标资源。
简单来说,FilterChain掌管着所有过滤器,执行完一个,由FilterChain去判断是否还有符合条件的下一个过滤器,如果有,继续执行下一个过滤器,没有,就执行目标资源。
一个简单的例子
首先写一个简单的过滤器:设置当浏览器访问timg.jpg图片资源时,如果年龄小于等于40,就可以访问,大于40,就不能访问,并输出提示信息。
WebFilter代码:
1 |
|
然后需要在web.xml文件中进行注册:
1 |
|
这个例子中,希望过滤器当浏览器访问timg.jpg文件时,进行拦截。
filter标签中有:
filter-name:用于为过滤器设置一个名字
filter-class:是过滤器实现类的完整限定类名
init-param:该元素用于为过滤器指定初始化参数,它的子元素param-name指定参数名字,param-value指定参数的值,在过滤器中可以使用FilterConfig接口对象来访问初始化参数
filter-mapping:是用来设置当浏览器访问哪些资源时,哪个过滤器需要进行拦截
可以有两种方式来指定:Sevlet名称,资源访问的请求路径
filter-mapping标签中有:
- filter-name:写上需要使用的过滤器名字,该值必须是在filter中声明过的
- url-pattern:设置filter所拦截的请求路径
- servlet-name:指定过滤器所拦截的Servlet名称
- dispatcher:指定当用户以什么样的方式访问资源时,过滤器需要拦截,有四个可取值:REQUEST,INCLUDE,FORWORD,ERROR, 默认为REQUEST,用户可以设置多个
标签子元素来指定Filter对资源的多种调用方式进行拦截。 - REQUEST:当用户直接访问页面时,Web容器将会调用此过滤器。如果目标资源是通过RequestDispatcher的include()或forword方法访问时,那么该过滤器就不会被调用
- INCLUDE:如果目标资源是通过RequestDispatcher的include方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用
- FORWORD:如果该目标资源是通过RequestDispatcher的forword方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
- ERROR:如果目标资源使用过声明式异常处理机制被调用时,那么该过滤器将被调用,除此之外,过滤器不会被调用
过滤器的执行顺序
首先看一个测试:
1 |
|
执行结果为:
完整的执行流程为:客户端发送请求给Http服务器,服务器执行过滤器,先打印"准备放行",接着执行doFilter方法,服务器发现没有其他过滤器,就执行目标资源,执行完以后,再回到过滤器,继续执行代码,打印"放行成功"。
再看一个测试:
有两个过滤器:
1 |
|
测试的Servlet的doGet方法:
1 |
|
执行结果为:
由该执行结果可知,执行顺序为:先执行Filter1,然后执行Filter1的doFilter方法,就转到下一个过滤器Filter2,等Filter2执行完后,再回到Filter1继续执行。
其中,过滤器之间的执行顺序是看在web.xml文件中mapping的先后顺序的,放在前面的先执行。
Filter的简单应用
filter有三种典型应用:
- 可以在filter中根据条件来决定是否调用filterChain.doFilter()方法,即是否让目标资源继续执行
- 在让目标资源执行之前,可以对request\response作预处理,再让目标资源执行
- 在目标资源执行之后,可以捕获目标资源执行结果,从而实现一些特殊功能
过滤器拦截地址 url-pattern 格式
在web.xml文件中,以下语法用来定义映射:
- 以 “/” 和 “/*” 结尾的是用来做路径映射
- 以前缀 “*.” 开头的是用来做 拓展映射
- “/” 是用来定义default servlet映射的
- 剩下的都是用来定义详细映射的,比如:/aa/bb/cc.jpg
有几种情况:
- 在调用某一具体文件时,拦截格式:
/img/test.jpg - 在调用某一文件下的资源文件时,拦截格式:
/img/* - 在调用任意文件夹下某种类型文件时,拦截格式:
*.jpg - 在调用网站任意文件时,拦截格式:
/*
注意:定义例如 “/*.action”是错误的,因为这既属于路径映射,又属于拓展映射,服务器无法分辨