云笔记项目-过滤器与拦截器学习

在做云笔记项目的过程中,没有登录的情况下,也可以直接访问edit.html页面。这个跟以前自己用Servlet做过的PadAndFilterManagement情况类似,当时在没有登录的情况下可以访问任何的action,后面加了过滤器才解决。只是在云笔记项目中,其使用的Spring MVC框架,即也可以使用Spring容器下的拦截器Interceptor进行拦截。但是过滤器和拦截器到底有什么区别,博客中有很多大牛分享了经验,这里直接贴过来,作为今后自己的查看的参考。

过滤器Filter和拦截器Interceptor的主要区别

(1)使用范围:Filter是Servlet规范的,只能用于Web程序中,而拦截器既可以用于Web程序,也可以用于Application、Swing程序中。

(2)规范不同:Filter是在Servlet规范中定义的,由Servlet容器支持。拦截器Interceptor是在Spring容器中的,由Spring框架支持。

(3)可以调用的资源不同:拦截器Interceptor是Spring的一个组件,由Spring管理,配置在Spring文件中,因此可以使用Spring里的任何资源、对象。比如Service,对象,数据源,事务管理等,通过注入到拦截器就可以进行深层次访问。Filter不具备此功能。

(4)Filter只在Servlet前后起作用,Interceptor能够深入到方法前后,异常抛出前后等,因此拦截器的使用具有更大的弹性,如果只拦截action请求,在Spring框架程序中,优先使用拦截器。

过滤器Filter和拦截器Interceptor的执行顺序

项目中使用了过滤器进行特定网页的过滤,如不过滤log_in.html,让用户首先能看到登录页面。并且使用了拦截器进行action的拦截,如果是登录注册的请求就不进行了拦截。其实项目使用过滤器也可以实现需求,但是同时使用了两种的话,就有必要大致了解浏览器访问服务端后,过滤器和拦截器的执行顺序。参考了大牛的博文,进行如下测试:

(1)过滤器

 1 package Filter;
 2 
 3 import java.io.IOException;
 4 
 5 import javax.servlet.Filter;
 6 import javax.servlet.FilterChain;
 7 import javax.servlet.FilterConfig;
 8 import javax.servlet.ServletException;
 9 import javax.servlet.ServletRequest;
10 import javax.servlet.ServletResponse;
11 
12 /**
13  * 测试过滤器
14  * @author yangchaolin
15  *
16  */
17 public class SomeFilter implements Filter{
18 
19     public void destroy() {
20      System.out.println("过滤器的destroy方法执行了");        
21     }
22 
23     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
24             throws IOException, ServletException {
25        System.out.println("过滤器的doFilter...before执行了");
26        chain.doFilter(req, res);    
27        System.out.println("过滤器的doFilter...after执行了");
28     }
29 
30     public void init(FilterConfig config) throws ServletException {
31       System.out.println("过滤器的init方法执行了");
32     }
33 
34 }

(2)拦截器

 1 package Interceptors;
 2 
 3 import javax.servlet.http.HttpServletRequest;
 4 import javax.servlet.http.HttpServletResponse;
 5 
 6 import org.springframework.web.servlet.HandlerInterceptor;
 7 import org.springframework.web.servlet.ModelAndView;
 8 /**
 9  * 拦截器类需要实现HandlerInterceptor接口
10  * @author yangchaolin
11  *
12  */
13 public class SomeInterceptor implements HandlerInterceptor{
14     /**
15      * DispatcherServlet在收到请求后,会先调用preHandler方法,如果该方法的返回值为true,则继续向后调用Controller的方法
16      * 如果返回值是false,则中断请求
17      * 
18      * DispatcherServlet,拦截器以及Controller会共享同一个request,response
19      * handler:Controller的方法对象,利用了java反射机制,后面了解学习
20      */
21     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
22             throws Exception {
23         System.out.println("拦截器的preHandler方法执行了");
24         return true;
25     }
26     /**
27      * 是Controller处理完后,在将ModelAndView返回给前端控制器DispatcherServlet之前,执行的方法
28      * 可以在该方法里,修改ModelAndView的处理结果
29      */
30     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
31             ModelAndView modelAndView) throws Exception {
32         System.out.println("拦截器的postHandler方法执行了");
33         
34     }
35     /**
36      * 最后执行
37      * ex:是处理器Controller所抛出的异常
38      * 可以写一个拦截器专门处理处理器Controller抛出的异常
39      */
40     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
41             throws Exception {
42         System.out.println("拦截器的afterCompletion方法执行了");
43         
44     }
45 
46 }

(3)web.xml中配置过滤器

1   <!-- 测试拦截器配置 -->
2   <filter>
3     <filter-name>someFilter</filter-name>
4     <filter-class>Filter.SomeFilter</filter-class>
5   </filter> 
6   <filter-mapping>
7      <filter-name>someFilter</filter-name>
8      <url-pattern>/*</url-pattern>
9   </filter-mapping>

(4)spring-mvc.xml中配置拦截器

1     <!-- 设置拦截器Interceptor -->
2     <!-- 如果想要拦截所有的请求,path应该写成/** -->    
3     <mvc:interceptors>
4       <mvc:interceptor>
5        <mvc:mapping path="/**"/>       
6        <bean class="Interceptors.SomeInterceptor"></bean>
7       </mvc:interceptor>
8     </mvc:interceptors>

(5)控制器中方法

 1 package Controller;
 2 
 3 import org.springframework.stereotype.Controller;
 4 import org.springframework.web.bind.annotation.RequestMapping;
 5 
 6 @Controller
 7 public class HelloController {
 8     @RequestMapping("/hello.do")
 9     public String hello() {
10         System.out.println("控制器的hello()方法执行了");
11         return "hello";        
13     }
14     /**
15      * 如果路径加一个demo,然而拦截器mapping还是/*的话,将不会拦截
16      * 如果想实现各种路径的拦截,不论几层都能实现拦截效果的话,需要将mapping修改为/**
17      * @return
18      */
19     @RequestMapping("/demo/hello.do")
20     public String hello1() {
21         System.out.println("控制器的hello1()方法执行了");
22         return "hello";        
24     }
25 }

 测试部分

(1)启动测试项目,地址1为:http://localhost:8088/SpringMVC03/hello.do,控制台输出结果为:

 (2)启动测试项目,地址2为:http://localhost:8088/SpringMVC03/demo/hello.do,控制台输出结果为:

在两次请求服务端后,控制台只输出了一次"过滤器的init方法执行了"。说明过滤器初始化过程在servlet容器中只执行了一次。

(3)启动测试项目,地址3为:http://localhost:8088/SpringMVC03/demo.do,控制器输出结果为:

从测试的结果来看,发现在浏览器发送请求给服务端的时候,过滤器Filter更早于拦截器Interceptor执行,而在浏览器接收服务端返回的信息时,过滤器Filter在拦截器Interceptor执行完后才执行结束,所以过滤器的方法更加靠近浏览器端。

 总结图示

① 发送action请求后,Filter的doFilter方法开始执行(此时还未执行完)。

② DispatcherServlet会得到web的请求,调用HandlerMapping进行控制器匹配,如果控制器没有对应的action地址,将不会执行Interceptor的方法(如发送demo.do请求时没执行拦截器的方法)。当控制器有对应的请求时会开始执行拦截器的方法。

③ Interceptor的preHandler方法执行。

④ 控制器的方法执行。

⑤ 控制器执行后,将结果(本例中为一个“hello”字符串)发给ModelAndView。

⑥ ModelAndView将结果再发送给DispatcherServlet之前,会执行Interceptor的postHandler方法。

⑦ DispatcherServlet将ModelAndView返回的结果发送给视图解析器解析,如本例解析得到/WEB-INF/hello.jsp。

⑧ 视图解析器将渲染页面准备发送给浏览器前,将执行afterCompletion方法。

⑨ 最后,将执行完Filter的doFilter方法。

参考博客:https://blog.csdn.net/chenleixing/article/details/44573495

参考博客:https://blog.csdn.net/zxd1435513775/article/details/80556034

原文地址:https://www.cnblogs.com/youngchaolin/p/10549020.html