-
2021-03-04 00:20:41
1.过滤器:
依赖于servlet容器。在实现上基于函数回调,可以对几乎所有请求进行过滤,但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作,获取我们想要获取的数据,比如:在过滤器中修改字符编码;在过滤器中修改HttpServletRequest的一些参数,包括:过滤低俗文字、危险字符等
2.拦截器:
依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。由于拦截器是基于web框架的调用,因此可以使用Spring的依赖注入(DI)进行一些业务操作,同时一个拦截器实例在一个controller生命周期之内可以多次调用。但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理
3.过滤器和拦截器的区别:
①拦截器是基于java的反射机制的,而过滤器是基于函数回调。
②拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
④拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
⑤在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
⑥拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
过滤器
@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {
System.out.println("before...");
chain.doFilter(request, response);
System.out.println("after...");
}
chain.doFilter(request, response);这个方法的调用作为分水岭。事实上调用Servlet的doService()方法是在chain.doFilter(request, response);这个方法中进行的。
拦截器
拦截器是被包裹在过滤器之中的。@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {
System.out.println("preHandle");
returntrue;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception {
System.out.println("postHandle");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {
System.out.println("afterCompletion");
}
a.preHandle()这个方法是在过滤器的chain.doFilter(request, response)方法的前一步执行,也就是在 [System.out.println("before...")][chain.doFilter(request, response)]之间执行。
b.preHandle()方法之后,在return ModelAndView之前进行,可以操控Controller的ModelAndView内容。
c.afterCompletion()方法是在过滤器返回给前端前一步执行,也就是在[chain.doFilter(request, response)][System.out.println("after...")]之间执行。
SpringMVC的机制是由同一个Servlet来分发请求给不同的Controller,其实这一步是在Servlet的service()方法中执行的。所以过滤器、拦截器、service()方法,dispatc()方法的执行顺序应该是这样的,大致画了个图:其实非常好测试,自己写一个过滤器,一个拦截器,然后在这些方法中都加个断点,一路F8下去就得出了结论。
更多相关内容 -
Java中的拦截器、过滤器、监听器用法详解
2020-08-30 13:40:06主要介绍了Java中的拦截器、过滤器、监听器用法,详细分析了Java拦截器、过滤器、监听器的功能、使用方法及相关注意事项,需要的朋友可以参考下 -
Java中的拦截器和过滤器有什么区别
2021-06-23 23:13:46本文收录于JavaStarter ,里面有我完整的Java系列文章,学习或面试都可以看看 (一)什么是过滤器 过滤器Filter基于Servlet实现,过滤器的主要应用场景是对字符编码、跨域等问题进行过滤。Servlet的工作原理是拦截...本文收录于JavaStarter ,里面有我完整的Java系列文章,学习或面试都可以看看
(一)什么是过滤器
过滤器Filter基于Servlet实现,过滤器的主要应用场景是对字符编码、跨域等问题进行过滤。Servlet的工作原理是拦截配置好的客户端请求,然后对Request和Response进行处理。Filter过滤器随着web应用的启动而启动,只初始化一次。
Filter的使用比较简单,继承Filter 接口,实现对应的init、doFilter以及destroy方法即可。
1、init:在容器启动时调用初始化方法,只会初始化一次
2、doFilter:每次请求都会调用doFilter方法,通过FilterChain 调用后续的方法
3、destroy:当容器销毁时,执行destory方法,只会被调用一次。
下面是详细的代码编写方式:
public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("初始化拦截器"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //做一些处理 chain.doFilter(request,response); } @Override public void destroy() { System.out.println("销毁拦截器"); } }
(二)什么是拦截器
拦截器是SpringMVC中实现的一种基于Java反射(动态代理)机制的方法增强工具,拦截器的实现是继承HandlerInterceptor 接口,并实现接口的preHandle、postHandle和afterCompletion方法。
1、preHandle:请求方法前置拦截,该方法会在Controller处理之前进行调用,Spring中可以有多个Interceptor,这些拦截器会按照设定的Order顺序调用,当有一个拦截器在preHandle中返回false的时候,请求就会终止。
2、postHandle:preHandle返回结果为true时,在Controller方法执行之后,视图渲染之前被调用
3、afterCompletion:在preHandle返回ture,并且整个请求结束之后,执行该方法。
具体的代码实现如下,首先编写一个拦截器:
@Component public class UserInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle"); String userName=request.getParameter("userName"); String password = request.getParameter("password"); if (userName==null||password==null){ response.setStatus(500); response.setContentType("text/html; charset=UTF-8"); response.getWriter().print("参数缺失"); return false; } //进行用户校验 if (userName.equals("admin")&&password.equals("admin")){ return true; }else { response.setStatus(500); response.setContentType("text/html; charset=UTF-8"); response.getWriter().print("用户名或密码错误"); return false; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion"); } }
编写完拦截器之后,通过一个配置类设置拦截器,并且可以通过addPathPatterns和excludePathPatterns执行哪些请求需要被拦截,哪些不需要被拦截。
@Configuration public class MvcConfig implements WebMvcConfigurer { @Autowired private UserInterceptor userInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(userInterceptor) .addPathPatterns("/**") .excludePathPatterns("/error"); } }
(三)拦截器与过滤器的区别
相同点:
1、拦截器与过滤器都是体现了AOP的思想,对方法实现增强,都可以拦截请求方法。
2、拦截器和过滤器都可以通过Order注解设定执行顺序
不同点:
1、过滤器属于Servlet级别,拦截器属于Spring级别
Filter是在javax.servlet包中定义的,要依赖于网络容器,因此只能在web项目中使用。Interceptor是SpringMVC中实现的,归根揭底拦截器是一个Spring组件,由Spring容器进行管理。
2、过滤器和拦截器的执行顺序不同:
下面通过一张图展示Filter和Interceprtor的执行顺序
首先当一个请求进入Servlet之前,过滤器的doFilter方法进行过滤,进入Servlet容器之后,执行Controller方法之前,拦截器的preHandle方法进行拦截,
执行Controller方法之后,视图渲染之前,拦截器的postHandle方法进行拦截,
请求结束之后,执行拦截器的postHandle方法。
3、过滤器基于函数回调方式实现,拦截器基于Java反射机制实现
(四)总结
实际开发中,拦截器的应用场景会比过滤器要更多,下面是拦截器和过滤器的主要应用场景
拦截器的应用场景:权限控制,日志打印,参数校验
过滤器的应用场景:跨域问题解决,编码转换
我翻了一下历史项目的代码,拦截器在用户权限校验场景下使用会比较多,由于一般是前后端分离项目,过滤器的使用场景就会少很多。
拦截器和过滤器算是比较常用的了,但是还是得注意两者的差距,我是鱼仔,我们下期再见!
-
Java过滤器与拦截器的区别
2021-11-09 18:26:59Java过滤器与拦截器的区别1. 过滤器与拦截器概述1.1 过滤器 Filter1.2 拦截器 interceptor2. 过滤器与拦截器区别3. 过滤器与拦截器实现3.1 过滤器(Filter)3.2 拦截器 (Interceptor)3.3 拦截器WebMvc配置3.4 切片...Java过滤器与拦截器的区别
1. 过滤器与拦截器概述
1.1 过滤器 Filter
依赖于servlet容器,实现基于函数回调,可以对几乎所有请求进行过滤, 但是缺点是一个过滤器实例只能在容器初始化时调用一次。使用过滤器的目的是用来做一些过滤操作, 获取我们想要获取的数据,过滤器一般用于登录权限验证、资源访问权限控制、敏感词汇过滤、 字符编码转换等等操作,便于代码重用,不必每个servlet中进行冗余操作。 Java中的Filter并不是一个标准的Servlet ,它不能处理用户请求,也不能对客户端生成响应。 主要用于对HttpServletRequest 进行预处理,也可以对HttpServletResponse 进行后处理,是个典型的处理链。 完整的流程是:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应, 最后Filter再对服务器响应进行后处理。在HttpServletRequest 到达Servlet 之前,拦截客户的HttpServletRequest。 根据需要检查HttpServletRequest ,也可以修改HttpServletRequest 头和数据。在响应到达客户端之前,拦截HttpServletResponse。根据需要检查HttpServletResponse ,可以修改HttpServletResponse 头和数据。 Filter随web应用的启动而启动,只初始化一次,随web应用的停止而销毁。 1.启动服务器时加载过滤器的实例,并调用init()方法来初始化实例; 2.每一次请求时都只调用方法doFilter()进行处理; 3.停止服务器时调用destroy()方法,销毁实例。
1.2 拦截器 interceptor
依赖于web框架,在SpringMVC中就是依赖于SpringMVC框架。 在实现上基于Java的反射机制,属于面向切面编程(AOP)的一种运用。 由于拦截器是基于web框架的调用,拦截器可以调用IOC容器中的各种依赖,而过滤器不能, 因此可以使用Spring的依赖注入进行一些业务操作, 同时一个拦截器实例在一个controller生命周期之内可以多次调用。 但是缺点是只能对controller请求进行拦截,对其他的一些比如直接访问静态资源的请求则没办法进行拦截处理。 spring mvc中的Interceptor可以理解为是Spring MVC框架对AOP的一种实现方式。 一般简单的功能又是通用的,每个请求都要去处理的,比如判断token是否失效可以使用spring mvc的HanlderInterceptor, 复杂的,比如缓存,需要高度自定义的就用spring aop。一般来说service层更多用spring aop, controller层有必要用到request和response的时候,可以用拦截器。 spring mvc中的Interceptor拦截请求是通过HandlerInterceptor来实现的。 所以HandlerInteceptor拦截器只有在Spring Web MVC环境下才能使用。 在SpringMVC中定义一个拦截器主要有两种方式,第一种方式是要实现Spring的HandlerInterceptor接口, 或者是其它实现了HandlerInterceptor接口的类,比如HandlerInterceptorAdapter。 第二种方式是实现WebRequestInterceptor接口,或者其它实现了WebRequestInterceptor的类。 HandlerInterceptor接口定义方法preHandle, postHandle, 和afterCompletion: preHandle(进入 Handler方法之前执行):预处理回调方法,实现处理器的预处理(如登录检查),返回值:true表示继续流程 (如调用下一个拦截器或处理器),false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器, 此时我们需要通过response来产生响应。 postHandle(进入handler方法之后,返回modelAndView之前):后处理回调方法, 实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView (模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。 afterCompletion(执行Handler完成执行此方法):整个请求处理完毕回调方法,即在视图渲染完毕时回调。 该方法也是需要当前对应的Interceptor 的preHandle方法的返回值为true时才会执行。 这个方法的主要作用是用于进行资源清理工作的,如性能监控中我们可以在此记录结束时间并输出消耗时间。
2. 过滤器与拦截器区别
1、实现原理不同
过滤器和拦截器 底层实现方式大不相同,过滤器是基于函数回调的,拦截器则是基于Java的反射机制(动态代理)实现的。2、使用范围不同
我们看到过滤器 实现的是 javax.servlet.Filter 接口,而这个接口是在Servlet规范中定义的,也就是说过滤器Filter 的使用要依赖于Tomcat等容器,导致它只能在web程序中使用。
而拦截器(Interceptor) 它是一个Spring组件,并由Spring容器管理,并不依赖Tomcat等容器,是可以单独使用的。不仅能应用在web程序中,也可以用于Application、Swing等程序中。3、触发时机不同
过滤器 和 拦截器的触发时机也不同,我们看下边这张图。
过滤器Filter是在请求进入容器后,但在进入servlet之前进行预处理,请求结束是在servlet处理完以后。
拦截器 Interceptor 是在请求进入servlet后,在进入Controller之前进行预处理的,Controller 中渲染了对应的视图之后请求结束。
4、拦截的请求范围不同
过滤器的init()方法,随着容器的启动进行了初始化。
执行顺序 :Filter 处理中 -> Interceptor 前置 -> 我是controller -> Interceptor 处理中 -> Interceptor 处理后
过滤器Filter执行了两次,拦截器Interceptor只执行了一次。这是因为过滤器几乎可以对所有进入容器的请求起作用,而拦截器只会对Controller中请求或访问static目录下的资源请求起作用。5、注入Bean情况不同
在拦截器与过滤器中分别注入service进行逻辑处理,拦截器会空指针:
原因:拦截器加载的时间点在springcontext之前,而Bean又是由spring进行管理。
解决方案也很简单,我们在注册拦截器之前,先将Interceptor 手动进行注入。「注意」:在registry.addInterceptor()注册的是getMyInterceptor() 实例。6、控制执行顺序不同
实际开发过程中,会出现多个过滤器或拦截器同时存在的情况,不过,有时我们希望某个过滤器或拦截器能优先执行,就涉及到它们的执行顺序。
过滤器用@Order注解控制执行顺序,通过@Order控制过滤器的级别,值越小级别越高越先执行。
拦截器默认的执行顺序,就是它的注册顺序,也可以通过Order手动设置控制,值越小越先执行。注意:
先声明的拦截器 preHandle() 方法先执行,而postHandle()方法反而会后执行。
postHandle() 方法被调用的顺序跟 preHandle() 居然是相反的!如果实际开发中严格要求执行顺序,那就需要特别注意这一点。原因:
得到答案就只能看源码了,我们要知道controller 中所有的请求都要经过核心组件DispatcherServlet路由,都会执行它的 doDispatch() 方法,而拦截器postHandle()、preHandle()方法便是在其中调用的。
看看两个方法applyPreHandle()、applyPostHandle()具体是如何被调用的,就明白为什么postHandle()、preHandle() 执行顺序是相反的了。
发现两个方法中在调用拦截器数组 HandlerInterceptor[] 时,循环的顺序竟然是相反的。。。,导致postHandle()、preHandle() 方法执行的顺序相反。3. 过滤器与拦截器实现
3.1 过滤器(Filter)
package com.example.category.aop; import lombok.extern.slf4j.Slf4j; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import java.io.IOException; /** * 过滤器(Filter) * 注意: * init与destroy方法不是所必须实现的,可以选择或者手动实现 * 启动类如果不加@ServletComponentScan就算这个类和运行类平级或者子级也不会被扫描上 * filterName可以省略不能重复@WebFilter(filterName = "myFilterTwo"), * * @author zrj * @since 2021/8/17 **/ @Slf4j @WebFilter(filterName = "myFilter", urlPatterns = "/*") public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { log.info("[过滤器]过滤器初始化"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { log.info("[过滤器]过滤器执行过滤操作"); //放行 filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { log.info("[过滤器]过滤器销毁"); } }
3.2 拦截器 (Interceptor)
package com.example.category.aop; import lombok.extern.slf4j.Slf4j; import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 拦截器 (Interceptor) * HandlerInterceptor:springMVC框架拦截器 * 必须在WebMvc配置以后生效 * * @author zrj * @since 2021/8/17 **/ @Slf4j @Component public class MyInterceptor implements HandlerInterceptor { /** * 前置拦截器 * 如果该方法的返回值为false ,将视为当前请求结束,不仅自身的拦截器会失效,还会导致其他的拦截器也不再执行。 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info("[拦截器]前置拦截器preHandle"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { log.info("[拦截器]处理拦截器postHandle"); } /** * 后置拦截器 * afterCompletion:只有在 preHandle() 方法返回值为true 时才会执行 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { log.info("[拦截器]后置拦截器afterCompletion"); } }
3.3 拦截器WebMvc配置
package com.example.category.config; import com.example.category.aop.MyInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import javax.annotation.Resource; /** * WebMvc配置 * 配置自定义拦截器 * * @author zrj * @since 2021/8/17 **/ @Configuration public class CommonWebConfig implements WebMvcConfigurer { @Resource private MyInterceptor myInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(myInterceptor); } }
3.4 切片(Aspect)
package com.example.category.aop; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; import java.util.Arrays; /** * 切片(Aspect) * * @author zrj * @since 2021/8/17 **/ @Slf4j @Aspect @Component public class MyAspect { // 定义切点位置 private final String POINT_CUT = "execution(* com.example.category.controller..*.*(..))"; private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); /** * 定义切点位置:下面如果你在SSM中用AOP,在xml中配的就是下面 */ @Pointcut(POINT_CUT) public void pointCut() { } /** * 前置通知 * * @param joinPoint 连接点 * @throws Throwable */ @Before("pointCut()") public void before(JoinPoint joinPoint) throws Throwable { log.info("[切片]前置通知@Before"); //获取目标方法参数信息 Object[] args = joinPoint.getArgs(); Arrays.stream(args).forEach(arg -> { try { log.info(OBJECT_MAPPER.writeValueAsString(arg)); } catch (JsonProcessingException e) { log.info(arg.toString()); } }); } /** * 后置返回通知 * 如果第一个参数为JoinPoint,则第二个参数为返回值的信息 * 如果第一个参数不为JoinPoint,则第一个参数为returning中对应的参数 * returning:限定了只有目标方法返回值与通知方法参数类型匹配时才能执行后置返回通知,否则不执行, * 参数为Object类型将匹配任何目标返回值 */ @AfterReturning(value = POINT_CUT, returning = "result") public void doAfterReturningAdvice1(JoinPoint joinPoint, Object result) { log.info("[切片]后置返回通知@AfterReturning,第一个的返回值:" + result); } @AfterReturning(value = POINT_CUT, returning = "result", argNames = "result") public void doAfterReturningAdvice2(String result) { log.info("[切片]后置返回通知@AfterReturning,第二个的返回值:" + result); } /** * 后置异常通知 * 定义一个名字,该名字用于匹配通知实现方法的一个参数名,当目标方法抛出异常返回后,将把目标方法抛出的异常传给通知方法; * throwing:限定了只有目标方法抛出的异常与通知方法相应参数异常类型时才能执行后置异常通知,否则不执行, * 对于throwing对应的通知方法参数为Throwable类型将匹配任何异常。 * * @param joinPoint 连接点 * @param exception 异常 */ @AfterThrowing(value = POINT_CUT, throwing = "exception") public void doAfterThrowingAdvice(JoinPoint joinPoint, Throwable exception) { log.info("[切片]后置异常通知@AfterThrowing"); log.info(joinPoint.getSignature().getName()); if (exception instanceof NullPointerException) { log.info("发生了空指针异常!!!!!"); } } /** * 后置通知 * * @param joinPoint 连接点 * @return void */ @After(value = POINT_CUT) public void doAfterAdvice(JoinPoint joinPoint) { log.info("[切片]后置通知@After"); } /** * 环绕通知: * 注意:Spring AOP的环绕通知会影响到AfterThrowing通知的运行,不要同时使用 * 环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。 * 环绕通知第一个参数必须是org.aspectj.lang.ProceedingJoinPoint类型 */ @Around(value = POINT_CUT) public Object doAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) { log.info("[切片]环绕通知@Around开始," + proceedingJoinPoint.getSignature().toString()); Object obj = null; try { obj = proceedingJoinPoint.proceed(); //可以加参数 log.info("[切片]环绕通知@Around执行" + obj.toString()); } catch (Throwable throwable) { throwable.printStackTrace(); } log.info("[切片]环绕通知@Around结束"); return obj; } }
4. 过滤器与拦截器执行顺序验证
-> 过滤器doFilter -> 前置拦截器preHandle
-> 环绕通知@Around开始 -> 前置通知@Before
-> UserController
-> 后置返回通知@AfterReturning -> 后置通知@After
-> 环绕通知@Around执行 ->环绕通知@Around结束
-> 处理拦截器postHandle -> 后置拦截器afterCompletion -
通过实例解析java过滤器和拦截器的区别
2020-08-19 09:54:30主要介绍了通过实例解析java过滤器和拦截器的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 -
java中拦截器和过滤器详解
2022-01-06 17:14:141 过滤器和拦截器的异同 1.1 一张图表明两者之间的差异: tomcat,filter,servet,interceptor以及controller等各种容器的关系图 1.2 两者的区别: 拦截器是基于java的反射机制的,而过滤器是基于函数回调。 ...1 过滤器和拦截器的异同
1.1 一张图表明两者之间的差异:
tomcat,filter,servet,interceptor以及controller等各种容器的关系图
1.2 两者的区别:
-
拦截器是基于java的反射机制的,而过滤器是基于函数回调。
-
拦截器不依赖与servlet容是依赖于spring容器,过滤器依赖与servlet容器。
-
拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用,可以限制用户对图片,文件以及其他资源的访问。
-
拦截器可以访问action请求上下文、值栈里的对象,而过滤器不能访问。
-
在action的生命周期中,拦截器可以多次被调用(因为拦截器是基于反射机制实现的,即通过加载java字节码而实现的函数的调用,所以每一次运行拦截器的时候都需要找到拦截器相关的字节码并且执行),而过滤器只需在容器初始化时被调用一次(意思是只需要调用一次,filter过滤器程序就会一直在内存中执行下去,每当碰到一次请求,服务器无需再次调用都会进行拦截,除非被主动摧毁。(1)启动服务器时加载过滤器的实例,并调用init()方法来初始化实例;(2)、每一次请求时都只调用方法doFilter()进行处理;(3)、停止服务器时调用destroy()方法,销毁实例。)。
-
拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
1.3 两者的相同之处:
本文主要对基于Spring boot对过滤器和拦截器的配置进行的讲解。无论是过滤器还是拦截器都属于AOP(面向切面编程)思想的具体实现。
2 过滤器
2.1 用法
当Web容器接受到一个对资源的请求时:
- 它将判断是否有过滤器与这个资源相关联。
- 如果有,那么容器将把请求交给过滤器进行处理。在过滤器中,你可以改变请求的内容,或者重新设置请求的报头信息,然后再将请求发送给目标资源
。 - 当目标资源对请求作出响应时候,容器同样会将响应先转发给相应的过滤器。
2.2 作用
在过滤器中你可以对响应的内容进行转换,然后再将响应发送到客户端。常见的过滤器用途
主要包括:
- 对用户请求进行统一认证
- 对用户的访问请求进行记录和审核、
- 对用户发送的文本数据进行过滤或替换,比如替换掉脏话、
- 转换图象格式、
- 对响应内容进行压缩以减少传输量、
- 对请求或响应进行加解密处理、
- 触发资源访问事件、
- 对XML的输出应用XSLT等。
2.3 实现过滤器 方法一:不使用@WebFilter下,既需要编写过滤器类,又要编写配置类
2.3.1 先编写过滤器类
过滤器类就是指 当拦截到某一个请求后,在该请求发往servlet容器前,执行什么操作,需要进行什么处理
public class LogCostFilter implements Filter{ @Override public void init(FilterConfig filterConfig)throws ServletException{ } @Override public void doFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain)throws IOException,ServletException{ long start =System.currentTimeMillis(); filterChain.doFilter(servletRequest,servletResponse); System.out.println("Execute cost="+(System.currentTimeMillis()-start)); } @Override public void destroy(){ } }
这段代码的逻辑比较简单,就是在方法执行前先记录时间戳,然后通过过滤器链完成请求的执行,在返回结果之间计算执行的时间。这里需要主要,这个类必须继承Filter类,这个是Servlet的规范,这个跟以前的Web项目没区别。
2.3.2 再在其配置类中配置过滤器需要拦截的请求类型的正则表达式以及决定使用哪一个过滤器类
但是,有了过滤器类以后,以前的web项目可以在web.xml中进行配置,但是spring- boot项目并没有web.xml这个文件,那怎么配置?在Spring boot中,我们需要FilterRegistrationBean来完成配置。其实现过程如下:
@Configuration public class FilterConfig{ @Bean public FilterRegistrationBean registFilter(){ FilterRegistrationBean registration =new FilterRegistrationBean(); registration.setFilter(newLogCostFilter()); registration.addUrlPatterns("/*"); registration.setName("LogCostFilter"); registration.setOrder(1); return registration; } }
这样配置就完成了,需要配置的选项主要包括实例化Filter类,然后指定url的匹配模式,设置过滤器名称和执行顺序,这个过程和在web.xml中配置其实没什么区别,只是形式不同而已。现在我们可以启动服务器访问任意URL:
2.4 过滤器实现代码 方法二:仅仅使用@WebFilter和过滤器类,不要编写配置类
大家可以看到上面的配置已经生效了。除了通过 FilterRegistrationBean 来配置以外,还有一种更直接的办法,
2.4.1 直接通过注解@WebFilter就可以完成了:
@WebFilter(urlPatterns ="/*", filterName ="logFilter2") public class LogCostFilter2 implements Filter{ @Override publicvoid init(FilterConfig filterConfig)throwsServletException{ } @Override public void doFilter(ServletRequest servletRequest,ServletResponse servletResponse,FilterChain filterChain)throwsIOException,ServletException{ long start =System.currentTimeMillis(); filterChain.doFilter(servletRequest, servletResponse); System.out.println("LogFilter2 Execute cost="+(System.currentTimeMillis()- start)); } @Override public void destroy(){ } }
2.4.2
这里直接用@WebFilter就可以进行配置,同样,可以设置url匹配模式,过滤器名称等。这里需要注意一点的是@WebFilter这个注解是Servlet3.0的规范,并不是Spring boot提供的。除了这个注解以外,我们还需在配置类中加另外一个注解:@ServletComponetScan,指定扫描的包。
@SpringBootApplication @MapperScan("com.pandy.blog.dao") @ServletComponentScan("com.pandy.blog.filters") public class springbootApplication{ public static void main(String[] args) throws Exception{ SpringApplication.run(Application.class, args); } }
现在,我们再来访问一下任意URL:
2.4.3 多个拦截器存在时候的执行顺序问题
可以看到,我们配置的两个过滤器都生效了。细心的读者会发现,第二个Filter我们并没有指定执行的顺序,但是却在第一个Filter之前执行。这里需要解释一下,@WebFilter这个注解并没有指定执行顺序的属性,其执行顺序依赖于Filter的名称,是根据Filter类名(注意不是配置的filter的名字)的字母顺序倒序排列,并且@WebFilter指定的过滤器优先级都高于FilterRegistrationBean配置的过滤器。有兴趣的朋友可以自己实验一下。
3 拦截器
3.1 拦截器定义
3.1.1 讲一讲拦截器实现的机制。
在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截,然后在之前或之后加上某些操作。拦截是AOP的一种实现策略。
3.1.2 拦截器作用有什么作用呢?
AOP面向切面有什么作用,那么拦截器就有什么作用。
- 日志记录:记录请求信息的日志,以便进行信息监控、信息统计、计算PV…
- 权限检查:认证或者授权等检查性能
- 监控:通过拦截器在进入处理器之前记录开始时间,处理完成后记录结束时间,得到请求处理时间。
- 通用行为:读取cookie得到用户信息并将用户对象放入请求头中,从而方便后续流程使用。
3.1.3 拦截器实现拦截器集成接口HandlerInterceptor,实现拦截,接口方法有下面三种:
-
preHandler(HttpServletRequest request, HttpServletResponse response, Object handler) 方法将在请求处理之前进行调用。SpringMVC中的Interceptor同Filter一样都是链式调用。每个Interceptor的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor中的preHandle方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值Boolean 类型的,当它返回为false时,表示请求结束,后续的Interceptor和Controller都不会再执行;当返回值为true时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法。
-
postHandler(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) 在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。
-
afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex) 该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行。顾名思义,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。总结一点就是:preHandle是请求执行前执行postHandle是请求结束执行afterCompletion是视图渲染完成后执行
3.2 拦截器实现
3.2.1
上面我们已经介绍了过滤器的配置方法,接下来我们再来看看如何配置一个拦截器。我们使用拦截器来实现上面同样的功能,记录请求的执行时间。首先我们实现拦截器类:
public class LogCostInterceptor implements HandlerInterceptor{ long start =System.currentTimeMillis(); @Override publicboolean preHandle(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Object o) throws Exception{ start =System.currentTimeMillis(); return true; } @Override public void postHandle(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Object o,ModelAndView modelAndView) throws Exception{ System.out.println("Interceptor cost="+(System.currentTimeMillis()-start)); } @Override publicvoid afterCompletion(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Object o,Exception e)throwsException{ } }
3.3.2
这里我们需要实现HandlerInterceptor这个接口,这个接口包括三个方法,preHandle是请求执行前执行的,postHandler是请求结束执行的,但只有preHandle方法返回true的时候才会执行,afterCompletion是视图渲染完成后才执行,同样需要preHandle返回true,该方法通常用于清理资源等工作。除了实现上面的接口外,我们还需对其进行配置:
@Configuration public class InterceptorConfig extends WebMvcConfigurerAdapter{ @Override public void addInterceptors(InterceptorRegistry registry){ registry.addInterceptor(newLogCostInterceptor()).addPathPatterns("/**"); super.addInterceptors(registry); } }
这里我们继承了WebMVCConfigurerAdapter,看过前面的文章的朋友应该已经见过这个类了,在进行静态资源目录配置的时候我们用到过这个类。这里我们重写了addInterceptors这个方法,进行拦截器的配置,主要配置项就两个,一个是指定拦截器,第二个是指定拦截的URL。现在我们再启动系统访问任意一个URL:
可以看到,我们通过拦截器实现了同样的功能。不过这里还要说明一点的是,其实这个实现是有问题的,因为preHandle和postHandle是两个方法,所以我们这里不得不设置一个共享变量start来存储开始值,但是这样就会存在线程安全问题。当然,我们可以通过其他方法来解决,比如通过ThreadLocal就可以很好的解决这个问题,有兴趣的同学可以自己实现。不过通过这一点我们其实可以看到,虽然拦截器在很多场景下优于过滤器,但是在这种场景下,过滤器比拦截器实现起来更简单。
-
-
Java拦截器和过滤器
2020-01-09 17:07:14Java中关于函数回调和反射机制的介绍 拦截器和过滤器的区别 Spring Boot实战:拦截器与过滤器(看看就好,大体还是可以的) SpringBoot - 拦截器和过滤器(主要用这个) ... -
浅析JAVA中过滤器、监听器、拦截器的区别
2020-09-03 08:05:10本文通过代码分析和文字说明的方式给大家浅析JAVA中过滤器、监听器、拦截器的区别,感兴趣的朋友一起看下吧 -
java-web -- servlet 拦截器 过滤器使用
2018-02-24 21:23:57java-web servlet 拦截器 过滤器使用 java-web servlet 拦截器 过滤器使用 -
Java过滤器和拦截器的区别
2022-05-31 13:20:08过滤器和拦截器的区别? -
java过滤器和拦截器的使用及其区别
2022-06-16 11:39:36我们必须额外编写代码进行异常处理 主要区别: 1、拦截器是基于Java的反射机制的,而过滤器是基于函数回调。 2、拦截器不依赖于servlet容器,过滤器依赖于servlet容器。 3、拦截器只能对action请求起作用,而过滤器... -
Java拦截器,过滤器,监听器(三大器)简单原理和区别
2021-10-07 21:35:47java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action 执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式。在... -
Java之拦截器与过滤器
2022-04-22 23:42:23Java之拦截器与过滤器 -
Java SpringBoot实现的过滤器(和拦截器)控制登录页面跳转
2018-04-13 15:50:28该压缩包实现了利用过滤器或者拦截器对登录信息进行验证跳转登陆页的功能,利用的是SpringBoot和thymeleaf,使用前请先看使用说明 -
java过滤器,java过滤器和拦截器的区别
2021-04-13 12:07:37java过滤器,java过滤器和拦截器的区别,java中的过滤器过滤器过滤器是处于客户端与服务器资源文件之间的一道过滤网,在访问资源文件之前,通过一系列的过滤器对请求进行修改、判断等,把不符合规则的请求在中途拦截或... -
java拦截器、过滤器、监听器总结
2021-11-09 15:01:501.过滤器(Filter):所谓过滤器顾名思义是用来过滤的,Java的过滤器能够为我们提供系统级别的过滤,也就是说,能过滤所有的web请求, 这一点,是拦截器无法做到的。在Java Web中,你传入的request,response提前过滤... -
过滤器 和 拦截器的 6个区别(别再傻傻分不清了)
2020-08-19 02:06:24主要介绍了过滤器 和 拦截器的 6个区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 -
Java中的过滤器和拦截器
2021-05-20 10:20:431.什么是拦截器? (1)在AOP中用于在某个方法或字段被访问之前,进行拦截然后再之前货之后加入某些操作。拦截是AOP的一种实现策略。 (2)拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者定义一个... -
Java中过滤器与拦截器
2022-05-08 16:01:52自JavaWeb中的过滤器,到Spring MVC中新增了拦截器,目的也是为了分离前后台。 对于二者的理解: 过滤器(FIlter):过滤器实际上是对一些web资源进行拦截 ,做一些处理后再交给下一个Servlet或者过滤器处理,它... -
拦截器和过滤器的执行顺序和区别
2022-04-12 21:47:521. 拦截器和过滤器的概念 1.1. 过滤器概念 过滤器Filter是JavaEE标准,在Servlet的规范中定义的,是Servlet容器支持的,是属于Servlet容器的,依赖Servlet容器; 若用配置文件方式(servlet3.0以下版本)配置,Filter... -
拦截器、过滤器、监听器各有什么作用?
2021-03-15 03:39:35这里是修真院后端小课堂,每篇分享文从【背景介绍】【知识剖析】【常见问题】【解决方案】【编码实战...今天给大家分享一下,修真院官网JAVA任务五,扩展思考中的知识点——拦截器、过滤器、监听器各有什么作用?一... -
Java中的过滤器、拦截器、监听器
2021-02-02 16:54:28拦截器在invocation.invoke()之前的代码,将会在Action之前被依次执行,而在invocation.invoke ()之后的代码,将会在Action之后被逆序执行? 可以简化成下面两段代码: ---------------------------------- ... -
谈谈Java编程中的拦截器与过滤器的区别
2021-02-28 16:48:48拦截器是基于java反射机制的,而过滤器是基于函数回调的。 过滤器依赖于servlet容器,而拦截器不依赖于servlet容器。 拦截器只能对Action请求起作用,而过滤器则可以对几乎所有请求起作用。 拦截器可以访问... -
Java拦截过滤器模式
2021-09-11 15:34:11Java拦截过滤器模式 拦截过滤器模式(Intercepting Filter Pattern)用于对应用程序的请求或响应做一些预处理/后处理。定义过滤器,并在把请求传给实际目标应用程序之前应用在请求上。过滤器可以做认证/授权/记录... -
拦截器与过滤器的区别
2019-06-20 23:11:09文章目录一、二者理解过滤器(Filter)拦截器(Interceptor)二、拦截器与过滤器的区别区别:三、拦截器与过滤器的触发时机拦截器与过滤器触发时机不一样四、使用场景五、图解 一、二者理解 过滤器(Filter) 过滤器...