阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

过滤器详解

169次阅读
没有评论

共计 6197 个字符,预计需要花费 16 分钟才能阅读完成。

1、过滤器的生命周期

我们已经学习过 Servlet 的生命周期,那么 Filter 的生命周期也就没有什么难度了!

init(FilterConfig)

在服务器启动时会创建 Filter 实例,并且每个类型的 Filter 只创建一个实例,从此不再创建!在创建完 Filter 实例后,会马上调用 init()方法完成初始化工作,这个方法只会被执行一次;

doFilter(ServletRequest req,ServletResponse res,FilterChain chain)

这个方法会在用户每次访问“目标资源(pattern>index.jsp)”时执行,如果需要“放行”,那么需要调用 FilterChain 的 doFilter(ServletRequest,ServletResponse)方法,如果不调用 FilterChain 的 doFilter()方法,那么目标资源将无法执行;

destroy()

服务器会在创建 Filter 对象之后,把 Filter 放到缓存中一直使用,通常不会销毁它。一般会在服务器关闭时销毁 Filter 对象,在销毁 Filter 对象之前,服务器会调用 Filter 对象的 destory()方法。

2、FilterConfig

你已经看到了吧,Filter 接口中的 init()方法的参数类型为 FilterConfig 类型。它的功能与 ServletConfig 相似,与 web.xml 文件中的配置信息对应。下面是 FilterConfig 的功能介绍:

  • ServletContext getServletContext():获取 ServletContext 的方法;
  • String getFilterName():获取 Filter 的配置名称;与 元素对应;
  • String getInitParameter(String name):获取 Filter 的初始化配置,与 元素对应;
  • Enumeration getInitParameterNames():获取所有初始化参数的名称。

过滤器详解

3、FilterChain

doFilter()方法的参数中有一个类型为 FilterChain 的参数,它只有一个方法:doFilter(ServletRequest,ServletResponse)。

前面我们说 doFilter()方法的放行,让请求流访问目标资源!但这么说不严密,其实调用该方法的意思是,“我(当前 Filter)”放行了,但不代表其他人(其他过滤器)也放行。

也就是说,一个目标资源上,可能部署了多个过滤器,就好比在你去北京的路上有多个打劫的匪人(过滤器),而其中第一伙匪人放行了,但不代表第二伙匪人也放行了,所以 调用 FilterChain 类的 doFilter()方法表示的是执行下一个过滤器的 doFilter()方法,或者是执行目标资源!

如果当前过滤器是最后一个过滤器,那么调用 chain.doFilter()方法表示执行目标资源,而不是最后一个过滤器,那么 chain.doFilter()表示执行下一个过滤器的 doFilter()方法。

4、多个过滤器执行顺序

一个目标资源可以指定多个过滤器,过滤器的执行顺序是在 web.xml 文件中的部署顺序:

<filter> <filter-name>myFilter1 </filter-name> <filter-class>com.tyschool.filter.MyFilter1</filter-class> </filter> <filter-mapping> <filter-name>myFilter1</filter-name> <url-pattern>/index.jsp</url-pattern> </filter-mapping> <filter> <filter-name>myFilter2</filter-name> <filter-class>com.tyschool.filter.MyFilter2</filter-class> </filter> <filter-mapping> <filter-name>myFilter2</filter-name> <url-pattern>/index.jsp</url-pattern> </filter-mapping>
public class MyFilter1 extends HttpFilter {public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("filter1 start..."); chain.doFilter(request, response);// 放行,执行 MyFilter2 的 doFilter()方法 System.out.println("filter1 end..."); } }
public class MyFilter2 extends HttpFilter {public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("filter2 start..."); chain.doFilter(request, response);// 放行,执行目标资源 System.out.println("filter2 end..."); } }
<body> This is my JSP page. <br> <h1>index.jsp</h1> <%System.out.println("index.jsp"); %> </body>

当有用户访问 index.jsp 页面时,输出结果如下:

filter1 start...
filter2 start...
index.jsp
filter2 end...
filter1 end...

5、四种拦截方式

我们来做个测试,写一个过滤器,指定过滤的资源为 b.jsp,然后我们在浏览器中直接访问 b.jsp,你会发现过滤器执行了!

但是,当我们在 a.jsp 中 request.getRequestDispathcer(“/b.jsp”).forward(request,response)时,就不会再执行过滤器了!也就是说,默认情况下,只能直接访问目标资源才会执行过滤器,而 forward 执行目标资源,不会执行过滤器!

public class MyFilter extends HttpFilter {public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("myfilter..."); chain.doFilter(request, response); } }
<filter> <filter-name>myfilter</filter-name> <filter-class>com.tyschool.filter.MyFilter</filter-class> </filter> <filter-mapping> <filter-name>myfilter</filter-name> <url-pattern>/b.jsp</url-pattern> </filter-mapping>
<body> <h1>b.jsp</h1> </body>
<h1>a.jsp</h1> <% request.getRequestDispatcher("/b.jsp").forward(request, response); %> </body>

http://localhost:8080/filtertest/b.jsp –> 直接访问 b.jsp 时,会执行过滤器内容;

http://localhost:8080/filtertest/a.jsp –> 访问 a.jsp,但 a.jsp 会 forward 到 b.jsp,这时就不会执行过滤器!

其实过滤器有四种拦截方式!分别是:REQUEST、FORWARD、INCLUDE、ERROR。

  • REQUEST:直接访问目标资源时执行过滤器。包括:在地址栏中直接访问、表单提交、超链接、重定向,只要在地址栏中可以看到目标资源的路径,就是 REQUEST;
  • FORWARD:转发访问执行过滤器。包括 RequestDispatcher#forward()方法、jsp:forward标签都是转发访问;
  • INCLUDE:包含访问执行过滤器。包括 RequestDispatcher#include()方法、jsp:include标签都是包含访问;
  • ERROR:当目标资源在 web.xml 中配置为 中时,并且真的出现了异常,转发到目标资源时,会执行过滤器。

可以在 中添加 0~n 个 子元素,来说明当前访问的拦截方式。

<filter-mapping> <filter-name>myfilter</filter-name> <url-pattern>/b.jsp</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping>
<filter-mapping> <filter-name>myfilter</filter-name> <url-pattern>/b.jsp</url-pattern> </filter-mapping>
<filter-mapping> <filter-name>myfilter</filter-name> <url-pattern>/b.jsp</url-pattern> <dispatcher>FORWARD</dispatcher> </filter-mapping>

其实最为常用的就是 REQUEST 和 FORWARD 两种拦截方式,而 INCLUDE 和 ERROR 都比较少用!其中 INCLUDE 比较好理解,我们这里不再给出代码,学员可以通过 FORWARD 方式修改,来自己测试。而 ERROR 方式不易理解,下面给出 ERROR 拦截方式的例子:

<filter-mapping> <filter-name>myfilter</filter-name> <url-pattern>/b.jsp</url-pattern> <dispatcher>ERROR</dispatcher> </filter-mapping> <error-page> <error-code>500</error-code> <location>/b.jsp</location> </error-page>
<body> <h1>a.jsp</h1> <% if(true) throw new RuntimeException("嘻嘻~"); %> </body>

6、过滤器的应用场景

过滤器的应用场景:

  • 执行目标资源之前做 预处理 工作,例如设置编码,这种试 通常都会放行,只是在目标资源执行之前做一些准备工作;
  • 通过条件判断是否放行,例如校验当前用户是否已经登录,或者用户 IP 是否已经被禁用;
  • 在目标资源执行后,做一些后续的特殊处理工作,例如把目标资源输出的数据进行处理;

7、设置目标资源

在 web.xml 文件中部署 Filter 时,可以通过“*”来执行目标资源:

	<filter-mapping>
		<filter-name>myfilter</filter-name>
		<url-pattern>/*</url-pattern> 
	</filter-mapping>

这一特性与 Servlet 完全相同!通过这一特性,我们可以在用户访问敏感资源时,执行过滤器,例如:/admin/*,可以把所有管理员才能访问的资源放到 /admin 路径下,这时可以通过过滤器来校验用户身份。

还可以为 指定目标资源为某个 Servlet,例如:

<servlet>
		<servlet-name>myservlet</servlet-name>
		<servlet-class>cn.itcast.servlet.MyServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>myservlet</servlet-name>
		<url-pattern>/abc</url-pattern>
	</servlet-mapping>
	<filter>
		<filter-name>myfilter</filter-name>
		<filter-class>cn.itcast.filter.MyFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>myfilter</filter-name>
		<servlet-name>myservlet</servlet-name> 
	</filter-mapping>

当用户访问 http://localhost:8080/filtertest/abc 时,会执行名字为 myservlet 的 Servlet,这时会执行过滤器。

8、Filter 小结

Filter 的三个方法:

  • void init(FilterConfig):在 Tomcat 启动时被调用;
  • void destroy():在 Tomcat 关闭时被调用;
  • void doFilter(ServletRequest,ServletResponse,FilterChain):每次有请求时都调用该方法;

FilterConfig 类:与 ServletConfig 相似,用来获取 Filter 的初始化参数

  • ServletContext getServletContext():获取 ServletContext 的方法;
  • String getFilterName():获取 Filter 的配置名称;
  • String getInitParameter(String name):获取 Filter 的初始化配置,与 元素对应;
  • Enumeration getInitParameterNames():获取所有初始化参数的名称。

FilterChain 类:

void doFilter(ServletRequest,ServletResponse):放行!表示执行下一个过滤器,或者执行目标资源。可以在调用 FilterChain 的 doFilter()方法的前后添加语句,在 FilterChain 的 doFilter()方法之前的语句会在目标资源执行之前执行,在 FilterChain 的 doFilter()方法之后的语句会在目标资源执行之后执行。

四各拦截方式:REQUEST、FORWARD、INCLUDE、ERROR,默认是 REQUEST 方式。

  • REQUEST:拦截直接请求方式;
  • FORWARD:拦截请求转发方式;
  • INCLUDE:拦截请求包含方式;
  • ERROR:拦截错误转发方式。

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-06-06发表,共计6197字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中