云笔记项目-过滤器与拦截器学习
在做云笔记项目的过程中,没有登录的情况下,也可以直接访问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