1、过滤器和拦截器触发时机不一样,过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。

2、拦截器可以获取IOC容器中的各个bean,而过滤器就不行,因为拦截器是spring提供并管理的,spring的功能可以被拦截器使用,在拦截器里注入一个service,可以调用业务逻辑。而过滤器是JavaEE标准,只需依赖servlet api ,不需要依赖spring。

3、过滤器的实现基于回调函数。而拦截器(代理模式)的实现基于反射

4、Filter是依赖于Servlet容器,属于Servlet规范的一部分,而拦截器则是独立存在的,可以在任何情况下使用。

5、Filter的执行由Servlet容器回调完成,而拦截器通常通过动态代理(反射)的方式来执行。

6、Filter的生命周期由Servlet容器管理,而拦截器则可以通过IoC容器来管理,因此可以通过注入等方式来获取其他Bean的实例,因此使用会更方便。

过滤器和拦截器非常相似,但是它们有很大的区别
最简单明了的区别就是**过滤器可以修改request,而拦截器不能
过滤器需要在servlet容器中实现,拦截器可以适用于javaEE,javaSE等各种环境
拦截器可以调用IOC容器中的各种依赖,而过滤器不能
过滤器只能在请求的前后使用,而拦截器可以详细到每个方法**
区别很多,大家可以去查下

总的来说
过滤器就是筛选出你要的东西,比如requeset中你要的那部分
拦截器在做安全方面用的比较多,比如 权限验证

下面是拦截器的例子:

拦截器定义:

实现HandleInterceptor接口

自定义拦截器类实现HandleInterceptor接口,并使用@Component注解标注为一个组件。

@Component注解 是为了 注入spring其他组件方便, 如果没有这个注解,自动注入为空

@Autowired
    UserService userService;

public class MySelfInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("在业务处理器处理请求之前被调用");//可以进行权限校验,安全控制MyRequestWrapper requestWrapper = new MyRequestWrapper (request);// 读取请求内容BufferedReader br = requestWrapper.getReader();String line = null;StringBuilder sb = new StringBuilder();while ((line = br.readLine()) != null) {sb.append(line);}// 将json字符串转换为json对象JSONObject body = JSONObject.parseObject(sb.toString());//业务处理return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("在业务处理器处理请求执行完成后,生成视图之前执行");//可以对返回来的ModelAndView进行处理,这个时候还未渲染视图}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("在DispatcherServlet完全处理完请求后被调用");//请求已经完成,页面已经渲染,数据已经返回。这个时候可以做一些资源清理,或者记录请求调用时间,做性能监控}
}

继承HandleInterceptorAdapter类

自定义拦截器类继承HandleInterceptor接口的实现类HandleInterceptorAdapter来定义,并使用@Component注解标注为一个组件。可以根据需要覆盖一些方法

@Component
public class MyInterceptor extends HandlerInterceptorAdapter {public SingleLoginInterceptor() {super();}@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return super.preHandle(request, response, handler);}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {super.postHandle(request, response, handler, modelAndView);}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {super.afterCompletion(request, response, handler, ex);}@Overridepublic void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {super.afterConcurrentHandlingStarted(request, response, handler);}
}

可以看到HandlerInterceptorAdapter类底层是实现了HandlerInterceptor接口,多了两个方法,要比
实现HandlerInterceptor接口的方式功能强大。
这两个方法都是HandlerInterceptorAdapter类实现的org.springframework.web.servlet.AsyncHandlerInterceptor接口提供的,而AsyncHandlerInterceptor接口又继承了HandlerInterceptor接口,所以HandlerInterceptorAdapter底层是实现类HandlerInterceptor接口。

自定义拦截器类实现WebRequestInterceptor接口,并使用@Component注解标注为一个组件。

@Component
public class MyInterceptor implements WebRequestInterceptor {@Overridepublic void preHandle(WebRequest webRequest) throws Exception {}@Overridepublic void postHandle(WebRequest webRequest, ModelMap modelMap) throws Exception {}@Overridepublic void afterCompletion(WebRequest webRequest, Exception e) throws Exception {}
}

两个实现接口方式的异同点 相同点 都可以实现controller层的拦截请求 不同点
1.WebRequestInterceptor的入参WebRequest是包装了HttpServletRequest 和HttpServletResponse的,通过WebRequest获取Request中的信息更简便。
2.WebRequestInterceptor的preHandle是没有返回值的,说明该方法中的逻辑并不影响后续的方法执行,所以这个接口实现就是为了获取Request中的信息,或者预设一些参数供后续流程使用。
3.HandlerInterceptor的功能更强大也更基础,可以在preHandle方法中就直接拒绝请求进入controller方法。

实现RequestInterceptor接口

此方式为微服务Feign调用的自定义拦截器,实现各个微服务之间的参数传递。

@Configuration
public class CenterinsRequestInterceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate requestTemplate) {}
}

拦截器的注册

创建一个自定义类,继承WebMvcConfigurerAdapter类重写addInterceptors方法。

@Configuration
public class WebCofiguration extends WebMvcConfigurerAdapter {@BeanMyInterceptor getMyInterceptor (){return new MyInterceptor ();}public void addInterceptors(InterceptorRegistry registry) {// 将自己定义的拦截器注入进来进行拦截操作//registry.addInterceptor(new MySelfInterceptor ()) // 如果是new 出来的对象 会导致 拦截器中自动装配为空registry.addInterceptor(getMyInterceptor ()).addPathPatterns("/**").excludePathPatterns("/logout");//过滤器可以添加多个,这里的addPathPatterns的/**是对所有的请求都做拦截。//excludePathPatterns代表排除url的拦截路径,即不拦截}
}

此类在SpringBoot2.0以后已经废除,但仍可使用。推荐使用以下两种方式来代替此方式。

1. 创建一个自定义类继承WebMvcConfigurationSupport类,实现addInterceptors。

@Configuration
public class MyInterceptorConfig extends WebMvcConfigurationSupport {@Overrideprotected void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");super.addInterceptors(registry);}
}

此方式会导致默认的静态资源被拦截,这就需要我们手动将静态资源放开。
除了重写方法外还需要重写addResourceHandlers方法来释放静态资源

@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");super.addResourceHandlers(registry);
}

此方式:一个容器内只能有一个WebMvcConfigurationSupport的实现类,也就是说不能有多个继承类,否则只有一个生效,会造成未知的错误,如果想在已有实现类的基础上(基础jar包中存在webConfig)还想继续添加拦截器,可以选择继承WebConfig,但是要super.addInterceptors,避免丢失注册

原因:在WebMvcAutoConfiguration 中 WebMvcConfigurationSupport 是  @ConditionalOnMissingBean 原来SpringBoot做了这个限制,只有当WebMvcConfigurationSupport类不存在的时候才会生效WebMvc自动化配置

2. 实现WebMvcConfigurer接口

@Configuration
public class MyInterceptorConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 实现WebMvcConfigurer不会导致静态资源被拦截registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**");}
}

----------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------------------

另外可以写个配置注解,根据注解拦截需要的方法

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogData {}

在controller中需要拦截的方法上加上 @LogData

@LogData
public ResponseMessage getUserList(@RequestParam Long id) {return ResponseMessage.ok();}

可以在拦截器中

@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {//这个方法将在请求处理之前进行调用。注意:如果该方法的返回值为false ,将视为当前请求结束,不仅自身的拦截器会失效,还会导致其他的拦截器也不再执行。log.info("进入到拦截器中:preHandle() 方法");HandlerMethod handlerMethod = (HandlerMethod) handler;LogData loginVerify = handlerMethod.getMethodAnnotation(LogData .class);if (loginVerify == null) {log.info("不需要对该路径 进行拦截");return true;}else {log.info("对该路径 进行拦截");log.info("业务操作...");return true;}}

----------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------------------

拦截器中request请求被读取一次后,controller获取为空

继承HandleInterceptorAdapter类  和 实现HandleInterceptor接口  实现WebRequestInterceptor接口  自定义类实现RequestInterceptor接口

HttpServletRequest的输入流只能读取一次的原因
当我们调用getInputStream()方法获取输入流时得到的是一个InputStream对象,而实际类型是ServletInputStream,它继承与InputStream。

InputStream的read()方法内部有一个position,标志当前流被读取到的位置,每读取一次,该标志就会移动一次,如果读到最后,read()返回-1,表示已经读取完了,如果想要重新读取,则需要调用reset()方法,position就会移动到上次调用mark的位置,mark默认是0,所有就能重头再读了。调用reset()方法的前提是已经重写了reset()方法,当然能否reset也是有条件的,它取决于markSupported()方法是否返回true。

InputStream默认不实现reset(),并且markSupported()默认也是返回false

我们可以把流读取出来后用容器存起来,后面就可以多次利用了。JavaEE提供了一个HttpServletRequestWrapper类,它是一个http请求包装器,基于装饰者模式实现类HttpServletRequest界面。

继承HttpServletRequestWrapper,将请求体中的流copy一份,可以重写getinputStream()和getReader()方法,或自定义方法供外部使用

import dm.jdbc.e.e;
import dm.jdbc.util.StreamUtil;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import lombok.extern.slf4j.Slf4j;import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;/*** 重写 HttpServletRequestWrapper * */
@Slf4j
public class MyRequestWrapper extends HttpServletRequestWrapper {private byte[]  body; //用于保存读取body中数据public MyRequestWrapper (HttpServletRequest request) throws IOException {    super(request);//读取请求的数据保存到本类当中//body = StreamUtil.readBytes(request.getReader(), "UTF-8");StringBuilder stringBuilder = new StringBuilder();BufferedReader bufferedReader = null;InputStream inputStream = null;try{inputStream = request.getInputStream();if(inputStream != null){bufferedReader = new BufferedReader(new InputStreamReader(inputStream));char[] charBuffer = new char[128];int bytesRead =-1;while((bytesRead = bufferedReader.read(charBuffer)) >0){stringBuilder.append(charBuffer,0, bytesRead);}}else{stringBuilder.append("");}}catch (Exception e){}finally {if(inputStream != null){inputStream.close();}if(bufferedReader != null){bufferedReader.close();}}body = stringBuilder.toString().getBytes();}//覆盖(重写)父类的方法@SuppressFBWarnings("DM_DEFAULT_ENCODING")@Overridepublic BufferedReader getReader() throws IOException {    return new BufferedReader(new InputStreamReader(getInputStream()));    }    //覆盖(重写)父类的方法@Override    public ServletInputStream getInputStream() throws IOException {    final ByteArrayInputStream bais = new ByteArrayInputStream(body);return new ServletInputStream() {    @Override    public int read() throws IOException {    return bais.read();    }@Overridepublic boolean isFinished() {// TODO Auto-generated method stubreturn false;}@Overridepublic boolean isReady() {// TODO Auto-generated method stubreturn false;}@Overridepublic void setReadListener(ReadListener arg0) {// TODO Auto-generated method stub} };    }/*** 获取body中的数据* @return*/public byte[] getBody() {return body;}/*** 把处理后的参数放到body里面* @param body*/public void setBody(byte[] body) {this.body = body;}
}

定义过滤器

import lombok.extern.slf4j.Slf4j;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;/*** 过滤器* */
@Slf4j
@WebFilter(urlPatterns = "/*", filterName = "logSignDataFilter")
public class LogSignDataFilter implements Filter {@Overridepublic void destroy() {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {ServletRequest requestWrapper = null;if(request instanceof HttpServletRequest){requestWrapper = new MyRequestWrapper ((HttpServletRequest) request);}if(requestWrapper == null){filterChain.doFilter(request, response);}else{filterChain.doFilter(requestWrapper, response);}}@Overridepublic void init(FilterConfig config) throws ServletException {}}

SpringBoot 拦截器 过滤器相关推荐

  1. SpringBoot拦截器与过滤器

    一.拦截器与过滤器 在讲Spring boot之前,我们先了解一下过滤器和拦截器.这两者在功能方面很类似,但是在具体技术实现方面,差距还是比较大的.在分析两者的区别之前,我们先理解一下AOP的概念,A ...

  2. springboot拦截器与过滤器详解

    前言 不管是传统的ssm项目,还是springboot项目,拦截器和过滤器在项目开发中都离不开,比如说对于ssm框架类的项目来说,许多登录逻辑的前置校验,黑白名单的检查,以及部分请求的数据分析等依然需 ...

  3. 【SpringBoot】SpringBoot拦截器实战和 Servlet3.0自定义Filter、Listener

    =================6.SpringBoot拦截器实战和 Servlet3.0自定义Filter.Listener ============ 1.深入SpringBoot2.x过滤器Fi ...

  4. springboot拦截器 跳过_springboot创建拦截器过程图解

    springboot创建拦截器过程图解 这篇文章主要介绍了springboot创建拦截器过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一. ...

  5. springboot + 拦截器 + 注解 实现自定义权限验证

    springboot + 拦截器 + 注解 实现自定义权限验证 最近用到一种前端模板技术:jtwig,在权限控制上没有用springSecurity.因此用拦截器和注解结合实现了权限控制. 1.1 定 ...

  6. SpringBoot拦截器配置

    SpringBoot拦截器配置 自定义拦截器: com.example.mybatis2018.interceptor.MyInterCeptor package com.example.mybati ...

  7. Springboot 拦截器链 - 加载拦截器

    Springboot 拦截器链 - 加载拦截器 1.创建拦截器 // 创建拦截器需要实现 HandlerInterceptor 接口 @Slf4j public class HandleInterce ...

  8. Springboot拦截器实现IP黑名单

    Springboot拦截器实现IP黑名单 一·业务场景和需要实现的功能 以redis作为IP存储地址实现.业务场景:针对秒杀活动或者常规电商业务场景等,防止恶意脚本不停的刷接口.实现功能:写一个拦截器 ...

  9. SpringBoot 拦截器和AOP自定义注解进行数据拦截实例

    声明:本文纯属个人随手笔记,如果对您有参考价值我十分开心,如果有存在错误,或者有更好的解决办法也麻烦您留言告诉我,大家共同成长,切勿恶言相. 欢迎加入资源共享QQ群:275343679,一起发现知识. ...

最新文章

  1. Java爬取frame的课程表_从爬取湖北某高校hub教务系统课表浅谈Java信息抓取的实现 —— import java.*;...
  2. javaweb学习总结(七):HttpServletResponse对象(一)
  3. 前端学习(3237):react生命周期4
  4. CodeSmith终极玩法
  5. 离奇的xenapp客户端无法加载应用故障解决过程 ...
  6. 第十三节:易学又实用的新特性:for...of
  7. Laravel 日志权限问题
  8. Python机器学习:多项式回归与模型泛化006验证数据集与交叉验证
  9. 0-1总体分布下的参数假设检验示例一(SPSS实现)
  10. 130 MySQL字段完整性约束(重要)
  11. 线性规划问题及单纯形法-目标函数值极小大M法
  12. Python数据分析练习
  13. python人脸识别毕业设计-毕业论文:基于树莓派的人脸识别门禁系统本科毕业设计文章...
  14. excel随机数_Excel生成随机数、不重复随机数技巧,试验检测办公必备
  15. DreamweaverCS6 破解补丁和说明
  16. 1、Apache启动失败,请检查相关配置。2、MySQL5.1启动失败,请检查相关配置。
  17. guava深入理解(3)-字符串,实用方法,函数式编程
  18. MS17-010(永恒之蓝)漏洞复现和分析
  19. [转]中国大学计算机专业考研分析
  20. 中国新一代人工智能治理原则发布 | 发展负责任的人工智能

热门文章

  1. AppRTC服务器搭建
  2. 红米5plus刷android one,手机知识:红米5plus如何 红米5plus配置参数
  3. 题目: 哈夫曼编码大全
  4. 常见滤波汇总(KF、EKF、UKF和PF)
  5. 可扩展的分布式数据库架构 vs 传统关系数据库
  6. 使用计算机打印文字,Word打印出的文字与电脑上的显示不同怎么办
  7. 果然是WIFI引起局域网速度慢
  8. 腾讯高工保姆级“Java成长手册”,层层递进,全是精华!Github上都没有!
  9. AFNetworking 2.0
  10. Pytorch入门实战 | 第P2周:彩色图片识别