过滤器filter

seelooks

贡献于2017-05-01

字数:0 关键词:

1、 过滤器 Filter Servlet 和 Filter Filter 和 Lister 是 Servlet 规范里的两个高级特性。不同于 Servlet,它 们不用于处理客户端请求,只用于对 request、 response 进行修改或者对 context、session、request 事件进行监听。 Filter 意为滤镜或者过滤器,用于 Servlet 之外对 request 或者 response 进行修改。Filter 提出了滤镜链的概念,一个 Filterchain 包括多个 Filter。 1 什么是过滤器 过滤器 JavaWeb 三大组件之一,它与 Servlet 很相似!不过滤 器是用来拦截请求的,而不是处理请求的。 当用户请求某个 Servlet 时,会先执行部署在这个请求上的 Filter,如果 Filter“放行”,那么会继承执行用户请求的 Servlet;如 果 Filter 不“放行”,那么就不会执行用户请求的 Servlet。 其实可以这样理解,当用户请求某个 Servlet 时,Tomcat 会去 执行注册在这个请求上的 Filter,然后是否“放行”由 Filter 来决定。可 以理解为,Filter 来决定是否调用 Servlet!当执行完成 Servlet 的代 码后,还会执行 Filter 后面的代码。 2 过滤器之 hello world 其实过滤器与 Servlet 很相似,我们回忆一下如果写的第一个 Servlet 应用!写一个类,实现 Servlet 接口!没错,写过滤器就是 写一个类,实现 Filter 接口。 public class HelloFilter implements Filter { public void init[崔 1] (FilterConfig filterConfig) throwsServletException {} public void doFilter[崔 2] (ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("Hello Filter"); } public void destroy[崔 3] () {} } [崔 1]不去理会它 [崔 2]当访问被拦截资源时,doFilter()方法会被调用!我们先不去管它的参数是什么作 用! [崔 3]不去理会它 [崔 4]指定要拦截的路径!当用户访问 index.jsp 页面时,HelloFilter 就会被执行 第二步也与 Servlet 一样,在 web.xml 文件中部署 Filter: helloFilter cn.itcast.filter.HelloFilter helloFilter /index.jsp[崔 4] 应该没有问题吧,都可以看懂吧! OK 了,现在可以尝试去访问 index.jsp 页面了,看看是什么 效果! 当用户访问 index.jsp 页面时,会执行 HelloFilter 的 doFilter()方法!在我们的示例中,index.jsp 页面是不会被执行的, 如果想执行 index.jsp 页面,那么我们需要放行! public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { System.out.println("filter start...");[崔 5] chain.doFilter(request, response);[崔 6] System.out.println("filter end...");[崔 7] } [崔 5]执行 index.jsp 之前执行 [崔 6]放行!表示执行 index.jsp [崔 7]在执行 index.jsp 后执行这一句 有很多同学总是错误的认为,一个请求在给客户端输出之后就 算是结束了,这是不对的!其实很多事情都需要在给客户端响应之后 才能完成! 过滤器详细 1 过滤器的生命周期 我们已经学习过 Servlet 的生命周期,那么 Filter 的生命周期也就没有什 么难度了!(Filter 接口中的方法:) (l) init(FilterConfig):在服务器启动时会创建 Filter 实例,并且每个 类型的 Filter 只创建一个实例,从此不再创建!在创建完 Filter 实例后,会马 上调用 init()方法完成初始化工作,这个方法只会被执行一次; (l) doFilter(ServletRequest req,ServletResponse res,FilterChain chain):这个方法会在用户每次访问“目标资源 (pattern>/index.jsp)”时执行,如果需要“放 行”,那么需要调 FilterChain doFilter(ServletRequest,ServletResponse) 方法(就是说必须写这个函数才放行,比如上述的 doFilter 函数),如果不调 用 FilterChain 的 doFilter()方法,那么目标资源将无法执行; (l) destroy():服务器会在创建 Filter 对象之后,把 Filter 放到缓存 中一直使用,通常不会销毁它。一般会在服务器关闭时销毁 Filter 对象,在销 毁 Filter 对象之前,服务器会调用 Filter 对象的 destory()方法。 2 FilterConfig 你已经看到了吧,Filter 接口中的 init()方法的参数类型为 FilterConfig 类型。它的功能与 ServletConfig 相似,与 web.xml 文件中的配置信息对 应。下面是 FilterConfig 的功能介绍: (l) ServletContext getServletContext():获取 ServletContext 的方法; (l) String getFilterName():获取 Filter 的配置名称;与元素对应; (l) String getInitParameter(String name):获取 Filter 的初始 化配置,与元素对应; (l) Enumeration getInitParameterNames():获取所有初始化 参数的名称。 3 FilterChain doFilter()方法的参数中有一个类型为 FilterChain 的参数,它只有一个 方法:doFilter(ServletRequest,ServletResponse)。 前面我们说 doFilter()方法的放行,让请求流访问目标资源!但这么说不严 密,其实调用该方法的意思是,“我(当前 Filter)”放行了,但不代表其他人 (其他过滤器)也放行。 也就是说,一个目标资源上,可能部署了多个过滤器,就好比在你去北京 的路上有多个打劫的匪人(过滤器),而其中第一伙匪人放行了,但不代表第 二伙匪人也放行了,所以调用 FilterChain 类的 doFilter()方法表示的是执行 下一个过滤器的 doFilter()方法,或者是执行目标资源! 如果当前过滤器是最后一个过滤器,那么调用 chain.doFilter()方法表示 执行目标资源,而不是最后一个过滤器,那么 chain.doFilter()表示执行下一 个过滤器的 doFilter()方法。 4 多个过滤器执行顺序 一个目标资源可以指定多个过滤器,过滤器的执行顺序是在 web.xml 文件中 的部署顺序: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 myFilter1[崔 1] [崔 1]因为 MyFilter1 配置在前面,所以先执行 MyFilter1 的 doFilter()方法。 cn.itcast.filter.MyFilter1 myFilter1 /index.jsp myFilter2 cn.itcast.filter.MyFilter2 myFilter2 /index.jsp 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..."); } } This is my JSP page.

index.jsp

<%System.out.println("index.jsp"); %> 当有用户访问 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 执行目标资源,不会执行过滤器!(跳转的不会 执行 F) 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); } } myfilter cn.itcast.filter.MyFilter myfilter /b.jsp

b.jsp

a.jsp

<% request.getRequestDispatcher("/b.jsp").forward(request, response); %> 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。 l REQUEST:直接访问目标资源时执行过滤器。包括:在地址栏中直 接访问、表单提交、超链接、重定向,只要在地址栏中可以看到目标资源的路 径,就是 REQUEST; l FORWARD:转发访问执行过滤器。包括 RequestDispatcher#forward()方法、标签都是转发访问; l INCLUDE:包含访问执行过滤器。包括 RequestDispatcher#include()方法、标签都是包含访问; l ERROR:当目标资源在 web.xml 中配置为中时,并 且真的出现了异常,转发到目标资源时,会执行过滤器。 可以在中添加 0~n 个子元素,来说 明当前访问的拦截方式。 myfilter /b.jsp REQUEST[崔 1] FORWARD[崔 2] myfilter /b.jsp [崔 3] myfilter /b.jsp FORWARD[崔 4] [崔 1]b.jsp 为目标资源,当直接请求 b.jsp 时,会执行过滤器 [崔 2]当转发到 b.jsp 页面时,会执行过滤器(这种申明了就可以转发的也执行过滤器) [崔 3]当没有给出拦截方式时,那么默认为 REQUEST [崔 4]当转发到 b.jsp 页面时,会执行过滤器!因为已经给出了 FORWARD了,那么就没有默认的 REQUEST 了!所以 只有在转发到 b.jsp 时才会执行过滤,而转发到 b.jsp 时,不会执行 b.jsp 其实最为常用的就是 REQUEST 和 FORWARD 两种拦截方式,而 INCLUDE 和 ERROR 都比较少用!其中 INCLUDE 比较好理解,我们这里不 再给出代码,可以通过 FORWARD 方式修改,来自己测试。而 ERROR 方式 不易理解,下面给出 ERROR 拦截方式的例子: myfilter /b.jsp ERROR[崔 5] 500 /b.jsp[崔 6]

a.jsp

<% if(true) throw new RuntimeException("嘻嘻~");[崔 7] %> [崔 5]拦截方式为 ERROR [崔 6]把 b.jsp 执行为 500 的错误页面 [崔 7]当用户访问 a.jsp 页面时会抛出异常,即 500 了! 这时服务器会转发到 b.jsp,在这之前会执行过滤器! 6 过滤器的应用场景 过滤器的应用场景: l 执行目标资源之前做预处理工作,例如设置编码,这种试通常都会放行, 只是在目标资源执行之前做一些准备工作;[c8] l 通过条件判断是否放行,例如校验当前用户是否已经登录,或者用户 IP 是否已经被禁用; l 在目标资源执行后,做一些后续的特殊处理工作,例如把目标资源输出的 数据进行处理[c9] ; [c8]几乎是的 Sevlet 中都需要写 request.setCharacterEndoing() 可以把 它入到一个 Filter 中(中文乱码必须添加,因为架构后面影藏了一些编码分方 式,只能在过滤器中去声明) [c9]回程拦截! 7 设置目标资源 在 web.xml 文件中部署 Filter 时,可以通过“*”来执行目标资源: myfilter /*[崔 10] 这一特性与 Servlet 完全相同!通过这一特性,我们可以在用户访问敏感 资源时,执行过滤器,例如:/admin/*,可 以把所有管理员才能访问的资源放到/admin 路径下,这时可以通过过滤器来 校验用户身份。 还可以为指定目标资源为某个 Servlet,例如: myservlet cn.itcast.servlet.MyServlet myservlet /abc myfilter cn.itcast.filter.MyFilter myfilter myservlet[崔 11] 当用户访问 http://localhost:8080/filtertest/abc 时,会执行名字为 myservlet 的 Servlet,这时会执行过滤器。 [崔 10]表示过滤所有资源 [崔 11]这里没有指定,而是指定!注意, 它与某个 Servlet 的配置名称相同! Filter 小结 Filter 的三个方法: 1. l void init(FilterConfig):在 Tomcat 启动时被调用; 2. l void destroy():在 Tomcat 关闭时被调用; 3. l void doFilter(ServletRequest,ServletResponse,FilterChain):每次有请求 时都调用该方法; FilterConfig 类:与 ServletConfig 相似,用来获取 Filter 的初始化参数 1. l ServletContext getServletContext():获取 ServletContext 的方法; 2. l String getFilterName():获取 Filter 的配置名称; 3. l String getInitParameter(String name):获取 Filter 的初始化配置,与 元素对应; 4. l Enumeration getInitParameterNames():获取所有初始化参数的名称。 FilterChain 类: l void doFilter(ServletRequest,ServletResponse):放行!表示执行下一个过滤 器,或者执行目标资源。可以在调用 FilterChain 的 doFilter()方法的前后添加语句,在 FilterChain 的 doFilter()方法之前的语句会在目标资源执行之前执行,在 FilterChain 的 doFilter()方法之后的语句会在目标资源执行之后执行。 四各拦截方式:REQUEST、FORWARD、INCLUDE、ERROR,默认是 REQUEST 方 式。 l REQUEST:拦截直接请求方式; l FORWARD:拦截请求转发方式; l INCLUDE:拦截请求包含方式; l ERROR:拦截错误转发方式。

下载文档,方便阅读与编辑

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 10 金币 [ 分享文档获得金币 ] 0 人已下载

下载文档

相关文档