赞
踩
只能对request和response进行操作,提前过滤掉一些信息。或者设置一些参数。然后在然后再传入servlet或者Controller进行业务逻辑操作。通常用的场景是:在过滤器中修改字符编(CharacterEncodingFilter)、在过滤器中修改HttpServletRequest的一些参数(XSSFilter(自定义过滤器)),如:过滤低俗文字、危险字符等。
重要一点是需要配置SpringMVC,使拦截器生效。:可以对request、response、handler、modelAndView、exception进行操作拦截器本质上是面向切面编程(AOP),符合横切关注点的功能都可以放在拦截器中来实现,主要的应用场景包括:
1、过滤器和拦截器触发时机不一样,过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。
如下图:
2、拦截器可以获取IOC容器中的各个bean,而过滤器就不行,因为拦截器是spring提供并管理的,spring的功能可以被拦截器使用,在拦截器里注入一个service,可以调用业务逻辑。而过滤器是JavaEE标准,只需依赖servlet api ,不需要依赖spring。
过滤器拦截器运行先后步骤:
其中第2步,SpringMVC的机制是由DispaterServlet来分发请求给不同的Controller,其实这一步是在Servlet的service()方法中执行的.
3、过滤器的实现基于回调函数。而拦截器(代理模式)的实现基于反射,代理分静态代理和动态代理,动态代理是拦截器的简单实现。
何时使用拦截器?何时使用过滤器?
如果是非spring项目,那么拦截器不能用,只能使用过滤器。
如果是处理controller前后,既可以使用拦截器也可以使用过滤器。
如果是处理dispaterServlet前后,只能使用过滤器。
Interceptor和Filter的不同点:
1)使用范围不同,filter是servlet规范规定的,只能用于web程序中,而Interceptor既可以用于web程序中,也可以用于application、swing程序中
2)规范不同:filter是在servlet规范中定义的,servlet支持,而拦截器是spring容器内的,是spring框架支持的。感觉就是一个是javaweb级别的,一个是spring级别的
3)深度不同:filter只在servlet前后起作用,而interceptor能够深入到方法前后、异常抛出前后等。因此interceptor的使用具有更大的弹性。所以在spring框架中应该优先使用拦截器
4)使用的资源不同,interceptor可以使用spring中的任何资源、对象等,而filter不能
两种方式:
1、使用spring boot提供的FilterRegistrationBean注册Filter
2、使用原生servlet注解定义Filter
两种方式的本质都是一样的,都是去FilterRegistrationBean注册自定义Filter
①、先定义Filter:
package com.hwm.filter; import javax.servlet.*; import java.io.IOException; public class MyFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { // do something 处理request 或response System.out.println("filter1"); // 调用filter链中的下一个filter filterChain.doFilter(servletRequest,servletResponse); } @Override public void destroy() { } }
②、注册自定义Filter
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean registrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter());
filterRegistrationBean.addUrlPatterns("/*");
return filterRegistrationBean;
}
}
// 注入spring容器 @Component // 定义filterName 和过滤的url @WebFilter(filterName = "my2Filter" ,urlPatterns = "/*") public class My2Filter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("filter2"); } @Override public void destroy() { } }
然后在启动类上添加注解@ServletComponentScan,该注解用于自动扫描指定包下(默认是与启动类同包下)的WebFilter/WebServlet/WebListener等特殊类。
定义一个Interceptor 非常简单方式也有几种,我这里简单列举两种
1、类要实现Spring 的HandlerInterceptor 接口
2、类继承实现了HandlerInterceptor 接口的类,例如 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;
void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;
void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;
** * 这里注意如果implement HandlerInterceptor的话,就必须实现它下面的三个方法。 * 但我们只需要使用preHandle()方法的话, 就没必要只需要extends方法 * 然后进行方法的重载即可。 * @Description TODO * @Author Mr.Wu * @Date 2019/6/4 15:02 * @Version 1.0 **/ @Component @EnableConfigurationProperties(JwtProperties.class) public class LoginInterceptor extends HandlerInterceptorAdapter { @Autowired private JwtProperties jwtProperties; private static final ThreadLocal<UserInfo> THREAD_LOCAL =new ThreadLocal<>(); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //获取cookie中的token String token = CookieUtils.getCookieValue(request, this.jwtProperties.getCookieName()); //解析token,获取用户信息。 UserInfo userInfo = JwtUtils.getInfoFromToken(token, this.jwtProperties.getPublicKey()); if(userInfo==null){ return false; } //把userInfo放入线程局部变量。 THREAD_LOCAL.set(userInfo); return true; }
其实以前都是继承WebMvcConfigurerAdapter类 不过springBoot2.0以上 WebMvcConfigurerAdapter 方法过时,有两种替代方案:
1、继承WebMvcConfigurationSupport
2、实现WebMvcConfigurer
但是继承WebMvcConfigurationSupport会让Spring-boot对mvc的自动配置失效。根据项目情况选择。现在大多数项目是前后端分离,并没有对静态资源有自动配置的需求所以继承WebMvcConfigurationSupport也未尝不可。
@Configuration public class WebAppConfigurer implements WebMvcConfigurer { /** * 通过@Bean注解,将我们定义的拦截器注册到Spring容器 * @return */ @Bean public LoginInterceptor loginInterceptor(){ return new LoginInterceptor(); } /** * 重写接口中的addInterceptors方法,添加自定义拦截器 * @param registry */ @Override public void addInterceptors(InterceptorRegistry registry) { // 通过registry来注册拦截器,通过addPathPatterns来添加拦截路径 registry.addInterceptor(this.loginInterceptor()).addPathPatterns("/**"); } .... }
其实下面还有很多方法我这里就省略了,过滤器可以添加多个,可以指定Path,这里的/**是对所有的请求都做拦截。
参考:https://blog.csdn.net/zxd1435513775/article/details/80556034
https://blog.csdn.net/heweimingming/article/details/79993591
正常流程:
异常流程:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。