Java Servlet 过滤器与 springmvc 拦截器的区别?
前言:在工作中,遇到需要记录日志的情况,不知道该选择过滤器还是拦截器,故总结了一下。
servlet 过滤器
定义
java过滤器能够对目标资源的请求和响应进行截取。过滤器的工作方式分为四种
应用场景
可以通过 doFilter 方法的 request、response 提前过滤一些不想要的信息,统一设置一些参数、统一设置字符集、控制权限是否登录等。
配置
<!-- 定义Filter -->
<filter>
<!-- Filter的名字 -->
<filter-name>loginFilter</filter-name>
<!-- Filter的实现类 -->
<filter-class>com.yule.common.filters.LoginFilter</filter-class>
</filter>
<!-- 定义Filter拦截的URL地址 -->
<filter-mapping>
<!-- Filter的名字 -->
<filter-name>loginFilter</filter-name>
<!-- Filter负责拦截的URL 全部以/的请求,如果/*,将会所有的请求-->
<url-pattern>/*</url-pattern>
</filter-mapping>
过滤器的4种工作方式
<filter-mapping>
<filter-name>myFilter</filter-name>
<servlet-name>目标资源</servlet-name>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
四中工作方式通过配置 <dispatcher> 标签来决定
- request 过滤器:不配 <dispatcher> 标签,或者配置为 <dispatcher>REQUEST</dispatcher> 。说明只有直接访问该目标资源时该过滤器才会起作用,对转发到该目标资源的请求将忽略不处理。
- forward 过滤器:配置为 <dispatcher>FORWARD</dispatcher> 。表示对转发到目标资源的请求过滤,如果直接访问目标资源,过滤器则不起作用。
- include 过滤器:配置为 <dispatcher>INCLUDE</dispatcher> 。表示对包含了目标资源的请求过滤,如果直接访问目标资源,则此过滤器将不起作用
include 包含以下语句:在 JSP 页面中的动作:<jsp:include page=.......在 Java 代码中的 request.getRequestDispatcher("....").include注意:如果目标资源一通过 <%@ include file="目标资源二"%> 指令包含,这时此过滤器不工作,因为这个是指令,在JSP 编译时插入一个包含文本或代码的文件,这个包含的过程是静态的。
- error 过滤器:配置为
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/error.jsp</url-pattern>
<dispatcher>ERROR</dispatcher>
</filter-mapping> <error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>当我们访问一个web目标资源时,如果服务器没有找到该目标资源,那么服务器就会给出一个404错误代码。如果我们给404错误代码定义一个页面,那么当404发生时就会调用该页面。
当我们访问一个不存在的文件时,就会访问error.jsp,但是配置了过滤器对错误页面进行过滤,所以过滤器先接受到请求,然后再转发给error.jsp。如果我们访问一个已经存在的页面,会不会调用error.jsp呢?如果这个页面中有response.sendError(404,"出错了!");那么该错误页面仍然会被调用,过滤器也会工作。
执行顺序
根据 web.xml 的代码顺序来决定过滤器的执行顺序。Filter 链: 一个Web应用中,可以编写多个Filter,这些 Filter 组合起来称之为一个Filter链。
当第一个 Filter 的 doFilter 方法被调用时,web 服务器会创建一个代表 Filter 链的 FilterChain 对象传递给该方法。在 doFilter 方法中,如果调用了 FilterChain 对象的 doFilter 方法,则 web 服务器会检 FilterChain 对象中是否还有 filter ,如果有,则调用第下一个 filter,如果没有,则调用目标资源。
init() 方法和 destroy() 方法随着项目的启动和关闭才会被调用,且仅一次。
举个栗子
web.xml 中
<!-- 定义Filter -->
<filter>
<!-- Filter的名字 -->
<filter-name>demoFilter</filter-name>
<!-- Filter的实现类 -->
<filter-class>com.yule.common.filters.DemoFilter</filter-class>
</filter>
<!-- 定义Filter拦截的URL地址 -->
<filter-mapping>
<!-- Filter的名字 -->
<filter-name>demoFilter</filter-name>
<!-- Filter负责拦截的URL 全部以/的请求,如果/*,将会所有的请求-->
<url-pattern>/*</url-pattern>
</filter-mapping>
Java 代码
package com.yule.common.filters; import javax.servlet.*;
import java.io.IOException; /**
* 过滤器
* @author yule
* @date 2018/7/2 21:52
*/
public class DemoFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("demo过滤器init。。。");
} @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("demo过滤器doFilter。。。此处省略业务处理逻辑"); //通过判断是否继续往下走
filterChain.doFilter(servletRequest, servletResponse);
} @Override
public void destroy() {
System.out.println("demo过滤器destroy。。。");
}
}
springmvc 拦截器
定义
Spring Web MVC的处理器拦截器。类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。拦截器是面向切面编程的,依赖的技术就是Java的动态代理。
应用场景
日志记录:记录请求日志等。权限检查:白名单等;性能监控:可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间;通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现。OpenSessionInView:如Hibernate,在进入处理器打开Session,在完成后关闭Session。
本质是AOP(面向切面编程),符合 AOP 的所有功能都可以使用拦截器实现。
配置
在 spring-mvc.xml 中
<mvc:interceptors>
<!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 -->
<!-- <bean class="com.bybo.aca.web.interceptor.Login"/> --> <mvc:interceptor>
<!--进行拦截的地址-->
<mvc:mapping path="/**"/>
<bean class="com.yule.common.interceptors.DemoInterceptor"/>
</mvc:interceptor> </mvc:interceptors>
执行顺序
根据 xml 中的配置顺序来执行。拦截器的执行顺序在过滤器之间。
方法说明
preHandle(HttpServletRequest request, HttpServletResponse response, Object handle)方法,该法在请求处理之前进行调用。SpringMVC 中的 Interceptor 是链式调用的,在一个应用中或者说是在一个请求中可以同时存在多个 Interceptor 。每个 Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是 Interceptor 中的 preHandle 方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求做一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值 Boolean 类型的,当它返回为 false 时,表示请求结束,后续的 Interceptor 和 Controller 都不会再执行;当返回值为 true 时,就会继续调用下一个 Interceptor 的 preHandle 方法,如果已经是最后一个 Interceptor 的时候,就会是调用当前请求的 Controller 中的方法。postHandle(HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView)方法,通过 preHandle 方法的解释咱们知道这个方法包括后面要说到的 afterCompletion 方法都只能在当前所属的 Interceptor 的 preHandle 方法的返回值为 true 的时候,才能被调用。postHandle 方法在当前请求进行处理之后,也就是在 Controller 中的方法调用之后执行,但是它会在 DispatcherServlet 进行视图返回渲染之前被调用,所以咱们可以在这个方法中对 Controller 处理之后的 ModelAndView 对象进行操作。postHandle 方法被调用的方向跟 preHandle 是相反的,也就是说,先声明的 Interceptor 的 postHandle 方法反而会后执行。afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)方法,也是需要当前对应的 Interceptor 的 preHandle 方法的返回值为 true 时才会执行。因此,该方法将在整个请求结束之后,也就是在 DispatcherServlet 渲染了对应的视图之后执行,这个方法的主要作用是用于进行资源清理的工作。afterCompletion 方法被调用的方向也跟 preHandle 是相反的,也就是说,先声明的 Interceptor 的 afterCompletion 方法反而会后执行
举个栗子
spring-mvc 中
<mvc:interceptors>
<!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 -->
<!-- <bean class="com.bybo.aca.web.interceptor.Login"/> --> <mvc:interceptor>
<!--进行拦截的地址-->
<mvc:mapping path="/**"/>
<bean class="com.yule.common.interceptors.DemoInterceptor"/>
</mvc:interceptor> </mvc:interceptors>
Java 代码
package com.yule.common.interceptors; import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; /**
* 自定义拦截器方式一
* Created by yule on 2018/7/2 22:37.
*/
public class DemoInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
//return true 表示继续下一个拦截器或者 control 层
//return false 表示被拦截下来
return false;
} @Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { } @Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { }
}
package com.yule.common.interceptors; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; /**
* 自定义拦截器方式二
* 一般都是通过实现HandlerInterceptor接口或者继承HandlerInterceptorAdapter抽象类,复写preHandle()、postHandle()和afterCompletion()这 3 个方法来对用户的请求进行拦截处理
* Created by yule on 2018/7/2 22:43.
*/
public class Demo2Interceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
}
区别
其实两者还是有相似之处,就是都可以用作权限检查、日志记录等情况,但是在这些情况下如何选择就要知道不同之处。
不同之处
使用范围不同:Filter 只能用于 Web 程序中。而拦截器可以用于 Web 程序,Application、Swing 程序中。
规范不同:Filter 是 servlet 规范规定的,是 servlet 支持的。而拦截器是在 spring 容器内,是 spring 框架支持的。
使用资源不同:Filter 不能直接使用 spring 的资源、对象等。而拦截器是一个 spring 组件,归 spring 管理,配置在 spring 文件中,因此能使用 spring 的任何资源、对象,例如 Service 对象、数据源、事务管理等,通过 IoC 注入到拦截器即可。也就是说在拦截器中可以注入一个 service ,用于业务逻辑或者访问数据库。
深度不同:Filter 只在 Servlet 前后起作用。而拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。
作用范围不同:拦截器只能对 Controller 层请求起作用,而过滤器则可以对几乎所有的请求起作用(如 .js、.css等)。
所以,在 Spring 构架的程序中,要优先使用拦截器。
注意
拦截器是在过滤器之间运行的。
执行顺序举例
拦截器,spring-mvc.xml 中:
<mvc:interceptors>
<!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 -->
<!-- <bean class="com.bybo.aca.web.interceptor.Login"/> --> <mvc:interceptor>
<!--进行拦截的地址-->
<mvc:mapping path="/**"/>
<bean class="com.yule.common.interceptors.DemoInterceptor"/>
</mvc:interceptor> <mvc:interceptor>
<!--进行拦截的地址-->
<mvc:mapping path="/**"/>
<bean class="com.yule.common.interceptors.Demo2Interceptor"/>
</mvc:interceptor> </mvc:interceptors>
java 代码:
package com.yule.common.interceptors; import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; /**
* 自定义拦截器方式一
* Created by yule on 2018/7/2 22:37.
*/
public class DemoInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
//return true 表示继续下一个拦截器或者 control 层
//return false 表示被拦截下来
System.out.println("preHandle");
return true;
} @Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
} @Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("afterCompletion");
}
}
package com.yule.common.interceptors; import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; /**
* 自定义拦截器方式二
* 一般都是通过实现HandlerInterceptor接口或者继承HandlerInterceptorAdapter抽象类,复写preHandle()、postHandle()和afterCompletion()这 3 个方法来对用户的请求进行拦截处理
* Created by yule on 2018/7/2 22:43.
*/
public class Demo2Interceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle 2222222...");
return true;
} @Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle 22222222");
} @Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion 2222222");
}
}
过滤器, web.xml 中:
<!-- 定义Filter -->
<filter>
<!-- Filter的名字 -->
<filter-name>demoFilter</filter-name>
<!-- Filter的实现类 -->
<filter-class>com.yule.common.filters.DemoFilter</filter-class>
</filter>
<!-- 定义Filter拦截的URL地址 -->
<filter-mapping>
<!-- Filter的名字 -->
<filter-name>demoFilter</filter-name>
<!-- Filter负责拦截的URL 全部以/的请求,如果/*,将会所有的请求-->
<url-pattern>/*</url-pattern>
</filter-mapping> <filter>
<filter-name>demo2Filter</filter-name>
<filter-class>com.yule.common.filters.Demo2Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>demo2Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
java 代码:
package com.yule.common.filters; import javax.servlet.*;
import java.io.IOException; /**
* 过滤器
* @author yule
* @date 2018/7/2 21:52
*/
public class DemoFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("demo过滤器init。。。");
} @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("demo过滤器doFilter。。。此处省略业务处理逻辑"); //通过判断是否继续往下走
filterChain.doFilter(servletRequest, servletResponse);
} @Override
public void destroy() {
System.out.println("demo过滤器destroy。。。");
}
}
package com.yule.common.filters; import javax.servlet.*;
import java.io.IOException; /**
* Created by yule on 2018/7/2 22:18.
*/
public class Demo2Filter implements Filter{
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("demo2过滤器init 2222222");
} @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("demo过滤器doFilter 222222"); //通过判断是否继续往下走
filterChain.doFilter(servletRequest, servletResponse);
} @Override
public void destroy() {
System.out.println("demo2过滤器destroy 22222 ");
}
}
调用 controller 打印结果:

Java Servlet 过滤器与 springmvc 拦截器的区别?的更多相关文章
- servlet filter和springMVC拦截器的区别
参考 http://blog.csdn.net/ggibenben1314/article/details/45341855
- Java过滤器与SpringMVC拦截器的差异学习笔记
学习摘录地址:http://blog.csdn.net/chenleixing/article/details/44573495 今天学习和认识了一下,过滤器和SpringMVC的拦截器的区别,学到了 ...
- Filter(过滤器)与Interceptor(拦截器)的区别
Filter能够对请求和响应资源进行拦截: Interceptor只针对请求进行拦截 在 Struts2中: (1)拦截器是基于java反射机制的,而过滤器是基于函数回调的. (2)过滤器依赖与ser ...
- springMVC 拦截器源码解析
前言:这两天学习了代理模式,自然想到了 springmvc 的 aop 使用的就是动态代理,拦截器使用的就是 jdk 的动态代理.今天看了看源码,记录一下.转载请注明出处:https://www.cn ...
- java 过滤器(Filter)与springMVC 拦截器(interceptor)的实现案例
java 过滤器Filter: package com.sun.test.aircraft.filter;import javax.servlet.*;import java.io.IOExcepti ...
- Java过滤器(Filter)与SpringMVC拦截器(Interceptor)之间的关系与区别
过滤器和拦截器的区别: ①拦截器是基于java的反射机制的,而过滤器是基于函数回调. ②拦截器不依赖与servlet容器,过滤器依赖与servlet容器. ③拦截器只能对action请求起作用,而过滤 ...
- JAVA过滤器与SpringMVC拦截器之间的区别
今天学习和认识了一下,过滤器和SpringMVC的拦截器的区别,学到了不少的东西,以前一直以为拦截器就是过滤器实现的,现在想想还真是一种错误啊, 而且看的比较粗浅,没有一个全局而又细致的认识,由于已至 ...
- Java过滤器与SpringMVC拦截器之间的关系与区别
今天学习和认识了一下,过滤器和SpringMVC的拦截器的区别,学到了不少的东西,以前一直以为拦截器就是过滤器实现的,现在想想还真是一种错误啊,而且看的比较粗浅,没有一个全局而又细致的认识,由于已至深 ...
- Java过滤器,SpringMVC拦截器之间的一顺序点关系
由于最近做的项目中有一部分是接口远程调用,用到了接入权限和业务权限的鉴定,需要采用SpringMVC的拦截器,以前用Struts2的时候用过拦截器,而SpringMVC的拦截器功能之前没研究过,所以这 ...
随机推荐
- linux的RPM软件包管理工具
RPM(Redhat Package Manage)原本是Red Hat Linux发行版专门用来管理Linux各项套件的程序,由于它遵循GPL规则且功能强大方便,因而广受欢迎.逐渐受到其他发行版的采 ...
- Python上下文管理协议:__enter__和__exit__
上下文管理器(context manager)是Python2.5开始支持的一种语法,用于规定某个对象的使用范围.一旦进入或者离开该使用范围,会有特殊操作被调用 (比如为对象分配或者释放内存).它的语 ...
- Vue2.5开发去哪儿网App 第四章笔记 下
1.解决非父子组件之间的传值问题 非父子组件传值(Bus/总线/发布订阅模式/观察者模式) 给 Vue类上挂在一个属性,然后创建vue实例时,实例就拥有了这个属性 Vue.prototype.bus ...
- (转)Python3之shutil模块
原文:https://www.cnblogs.com/wang-yc/p/5625046.html 一. 简介 shutil 是高级的文件,文件夹,压缩包处理模块. 二. 使用 shutil.copy ...
- Java 内存分配及垃圾回收机制初探
一.运行时内存分配 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域. 这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则 ...
- Proxy代理模式(结构型模式)
1.问题 在面向对象系统中,有些对象由于某种原因(比如创建对象的开销很大,或者某些操作需要安全控制,或者需要进程外的访问等),直接访问会给调用者带来麻烦,那么如何在不损失接口透明性的情况下,解决这些麻 ...
- Gen对于数组Array的处理
举个例子,如下: public void t() { String[][] a = new String[][] { { "x", "y" } }; Strin ...
- 翻译api调用
<?php function language($value,$from="auto",$to="auto") { $value_code=urlenco ...
- vue代码上传服务器后背景图片404解决方法
问题:代码上传服务器后,图片404,使用的font-awesome图标也是404 解决办法: 如果你用了vue-cil,那么在build目录下找到utils.js中的ExtractTextPlugin ...
- Chapter 3 Phenomenon——23
Charlie put one arm behind my back, not quite touching me, and led me to the glass doors of the exit ...