在做云笔记项目的过程中, 没有登录的情况下, 也可以直接访问 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)过滤器
- package Filter;
- import java.io.IOException;
- import javax.servlet.Filter;
- import javax.servlet.FilterChain;
- import javax.servlet.FilterConfig;
- import javax.servlet.ServletException;
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- /**
- * 测试过滤器
- * @author yangchaolin
- *
- */
- public class SomeFilter implements Filter{
- public void destroy() {
- System.out.println("过滤器的 destroy 方法执行了");
- }
- public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
- throws IOException, ServletException {
- System.out.println("过滤器的 doFilter...before 执行了");
- chain.doFilter(req, res);
- System.out.println("过滤器的 doFilter...after 执行了");
- }
- public void init(FilterConfig config) throws ServletException {
- System.out.println("过滤器的 init 方法执行了");
- }
- }
(2)拦截器
- package Interceptors;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.springframework.Web.servlet.HandlerInterceptor;
- import org.springframework.Web.servlet.ModelAndView;
- /**
- * 拦截器类需要实现 HandlerInterceptor 接口
- * @author yangchaolin
- *
- */
- public class SomeInterceptor implements HandlerInterceptor{
- /**
- * DispatcherServlet 在收到请求后, 会先调用 preHandler 方法, 如果该方法的返回值为 true, 则继续向后调用 Controller 的方法
- * 如果返回值是 false, 则中断请求
- *
- * DispatcherServlet, 拦截器以及 Controller 会共享同一个 request,response
- * handler:Controller 的方法对象, 利用了 java 反射机制, 后面了解学习
- */
- public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
- throws Exception {
- System.out.println("拦截器的 preHandler 方法执行了");
- return true;
- }
- /**
- * 是 Controller 处理完后, 在将 ModelAndView 返回给前端控制器 DispatcherServlet 之前, 执行的方法
- * 可以在该方法里, 修改 ModelAndView 的处理结果
- */
- public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
- ModelAndView modelAndView) throws Exception {
- System.out.println("拦截器的 postHandler 方法执行了");
- }
- /**
- * 最后执行
- * ex: 是处理器 Controller 所抛出的异常
- * 可以写一个拦截器专门处理处理器 Controller 抛出的异常
- */
- public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
- throws Exception {
- System.out.println("拦截器的 afterCompletion 方法执行了");
- }
- }
(3)Web.xml 中配置过滤器
- <!-- 测试拦截器配置 -->
- <filter>
- <filter-name>someFilter</filter-name>
- <filter-class>Filter.SomeFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>someFilter</filter-name>
- <url-pattern>/*</url-pattern>
- </filter-mapping>
(4)spring-mvc.xml 中配置拦截器
- <!-- 设置拦截器 Interceptor -->
- <!-- 如果想要拦截所有的请求, path 应该写成 /** -->
- <mvc:interceptors>
- <mvc:interceptor>
- <mvc:mapping path="/**"/>
- <bean class="Interceptors.SomeInterceptor"></bean>
- </mvc:interceptor>
- </mvc:interceptors>
(5)控制器中方法
- package Controller;
- import org.springframework.stereotype.Controller;
- import org.springframework.Web.bind.annotation.RequestMapping;
- @Controller
- public class HelloController {
- @RequestMapping("/hello.do")
- public String hello() {
- System.out.println("控制器的 hello()方法执行了");
- return "hello";
- }
- /**
- * 如果路径加一个 demo, 然而拦截器 mapping 还是 /* 的话, 将不会拦截
- * 如果想实现各种路径的拦截, 不论几层都能实现拦截效果的话, 需要将 mapping 修改为 /**
- * @return
- */
- @RequestMapping("/demo/hello.do")
- public String hello1() {
- System.out.println("控制器的 hello1()方法执行了");
- return "hello";
- }
- }
测试部分:
(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 执行完后才执行结束, 所以过滤器的方法更加靠近浏览器端.
总结图示:
1 发送 action 请求后, Filter 的 doFilter 方法开始执行(此时还未执行完).
2 DispatcherServlet 会得到 Web 的请求, 调用 HandlerMapping 进行控制器匹配, 如果控制器没有对应的 action 地址, 将不会执行 Interceptor 的方法(如发送 demo.do 请求时没执行拦截器的方法). 当控制器有对应的请求时会开始执行拦截器的方法.
3 Interceptor 的 preHandler 方法执行.
4 控制器的方法执行.
5 控制器执行后, 将结果 (本例中为一个 "hello" 字符串) 发给 ModelAndView.
6 ModelAndView 将结果再发送给 DispatcherServlet 之前, 会执行 Interceptor 的 postHandler 方法.
7 DispatcherServlet 将 ModelAndView 返回的结果发送给视图解析器解析, 如本例解析得到 / Web-INF/hello.jsp.
8 视图解析器将渲染页面准备发送给浏览器前, 将执行 afterCompletion 方法.
9 最后, 将执行完 Filter 的 doFilter 方法.
参考博客:
参考博客:
来源: http://www.bubuko.com/infodetail-2991132.html