首页 > 其他分享 >SpringBoot 拦截器 & 过滤器

SpringBoot 拦截器 & 过滤器

时间:2023-01-17 16:37:16浏览次数:42  
标签:registrationBean 拦截器 SpringBoot Filter 过滤器 public 请求

拦截器

Java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了一种可以提取Action中可重用部分代码的方式,动态拦截Action调用的对象(也就是controller层)。
Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。

自定义拦截器

自定义一个拦截器,只需要实现HandlerInterceptor接口即可,该接口包含三个方法:

  • preHandle():该方法会在控制器方法前执行,其返回值表示是否知道如何写一个接口。中断后续操作。当其返回值为 true 时,表示继续向下执行;返回值为 false 时,会中断后续的所有操作(包括调用下一个拦截器和控制器类中的方法执行等)。
  • postHandle():该方法会在控制器方法调用之后,且解析视图之前执行。可以通过此方法对请求域中的模型和视图做出进一步的修改。
  • afterCompletion():该方法会在整个请求完成,即视图渲染之后执行。可以通过此方法实现一些资源清理、记录日志信息等工作。
@Component
public class SessionIntercepter implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("拦截器 preHandle");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    	// 设置字符编码
        response.setCharacterEncoding("UTF-8");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println(response.getCharacterEncoding());
    }
}

自定义拦截器生效

想要Spring Boot 拦截器生效很简单,只需要定义一个配置类,实现 WebMvcConfigurer 接口,实现其中的 addInterceptors() 方法即可。

@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Autowired
    private SessionIntercepter sessionIntercepter;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 拦截器拦截路径
        registry.addInterceptor(sessionIntercepter).addPathPatterns("/**");
    }
}

运用例子

  • 开发中可能会经常遇到短时间内由于用户的重复点击导致几秒之内重复的请求,可能就是这几秒之内由于各种问题,比如网络、事务的隔离性等等问题导致了数据的重复等问题,因此在日常开发中必须规避这类重复请求操作,这就可以使用拦截器来实现;
  • 开发中经常遇到用户的权限问题。可以在用户登录的时候将用户信息(包括权限信息)加密后放入jwt token中,在每次请求接口的时候拦截并判断该用户是否具有访问该接口的权限。

过滤器

Filter 也称为过滤器,它是Servlet技术中最实用的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如JSP,servlet,静态图片文件或静态HTML文件进行拦截,从而实现一些特殊功能。例如实现URL级别的权限控制、过滤敏感词汇、压缩响应信息等一些高级功能。

执行原理

当客户端发出Web资源的请求时,Web服务器根据应用程序配置文件设置的过滤规则进行检查,若客户请求满足过滤规则,则对请求/响应进行拦截,对请求头和请求数据进行检查或改动,并依次通过过滤器链,最后把请求/响应交给请求的Web资源处理。请求信息在过滤器链中可以被修改,也可以根据条件让请求不发往资源处理器,并直接向客户端返回一个响应。当资源处理器完成了对资源的处理后,响应信息将逐级逆向返回。同样在这个过程中,用户可以修改响应信息,从而完成一定的任务,如图:
在这里插入图片描述
服务器会按照过滤器定义的先后顺序组成一条链,然后一次执行其中的doFilter()方法。执行的顺序如图所示,执行第一个过滤器的chain.doFilter()之前的代码,第二个过滤器的chain.doFilter()之前的代码,请求的资源,第二个过滤器的chain.doFilter()之后的代码,第一个过滤器chain.doFilter()之后的代码,最后返回响应。
在这里插入图片描述

自定义 Filter

自定义 Filter,只需要实现 javax.servlet.Filter 接口,重写其中的方法即可。

@Component
public class WeFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 继续执行下一个 filter
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

配置 Filter

方法一
配置类中使用@Bean注入(推荐使用)

@Configuration
public class FilterConfig {

    @Autowired
    private WeFilter weFilter1;

    @Autowired
    private WeFilter weFilter2;

    @Bean
    public FilterRegistrationBean injectFilterOne() {
        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(weFilter1);
        registrationBean.addUrlPatterns("/*");
        registrationBean.setName("filter_one");
        // 优先级
        registrationBean.setOrder(1);
        return registrationBean;
    }

    @Bean
    public FilterRegistrationBean injectFilterTwo() {
        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(weFilter2);
        registrationBean.addUrlPatterns("/*");
        registrationBean.setName("filter_one");
        // 优先级
        registrationBean.setOrder(2);
        return registrationBean;
    }
}

注意:设置的优先级别决定了过滤器的执行顺序
方法二
使用@WebFilter,@WebFilter时Servlet3.0的一个注解,用于标注一个Filter,Spring Boot也是支持这种方式的,只需要在自定义的Filter上标注该注解即可。

@WebFilter(filterName = "filter_one", urlPatterns = {"/*"})
public class WeFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 继续执行下一个 filter
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

要想@WebFilter注解生效,需要在配置类上标注另外一个注解@ServletComponentScan用于扫描使其生效。

@SpringBootApplication
@ServletComponentScan(value = {"com.example.demo.filter"})
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

运用例子
对于前后端分离的项目来说跨越是一个难题,对于跨越问题有很多解决方案,比如JSONP,网关支持等。用过滤器也可以解决跨越问题,原理很简单,只需要在请求头中添加相应支持跨越的内容即可。

@Component
public class WeFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        // 继续执行下一个 filter
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

配置类中注入

@Configuration
public class FilterConfig {

    @Autowired
    private WeFilter weFilter;

    @Bean
    public FilterRegistrationBean injectFilterOne() {
        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(weFilter);
        registrationBean.addUrlPatterns("/*");
        registrationBean.setName("filter_one");
        // 优先级
        registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return registrationBean;
    }
}

过滤器的内容虽然简单,但是在实际开发中不可或缺,比如常用的权限控制框架Shiro,Spring Security,内部都是使用过滤器,了解一下对以后的深入学习有着固本的作用。

拦截器和过滤器的区别

  1. 拦截器是基于Java的反射机制,而过滤器是基于函数回调;
  2. 拦截器不依赖servlet容器,过滤器依赖servlet容器;
  3. 拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用;
  4. 拦截器可以访问action上下文、值栈里的对象,过滤器不能访问;
  5. 在action生命周期中,拦截器可以多次被调用,过滤器只能在容器初始化时被调用一次。

标签:registrationBean,拦截器,SpringBoot,Filter,过滤器,public,请求
From: https://www.cnblogs.com/wangms821/p/17058089.html

相关文章

  • Spring的OncePerRequestFilter 过滤器
    Spring的OncePerRequestFilter原文链接:https://blog.csdn.net/weixin_43944305/article/details/119923969Spring的OncePerRequestFilterOncePerRequestFilter顾名......
  • Springboot之OncePerRequestFilter 过滤器
    Springboot之OncePerRequestFilter过滤器原文链接:https://www.cnblogs.com/javalinux1/p/16389683.html类说明OncePerRequestFilter能够确保在一次请求只通过一次filte......
  • 小满nestjs(第十六章 nestjs 响应拦截器)
    拦截器拦截器具有一系列有用的功能,这些功能受面向切面编程(AOP)技术的启发。它们可以:在函数执行之前/之后绑定额外的逻辑转换从函数返回的结果转换从函数抛出的异常扩展基本函......
  • 小满nestjs(第十七章 nestjs 异常拦截器)
    上一章我们讲了全局响应拦截,这一章我们来讲一下全局异常拦截器common下面新建filter.ts让我们创建一个异常过滤器,它负责捕获作为​​HttpException​​​类实例的异常,并为它......
  • SpringBoot自定义starter
    SpringBoot自定义starter目录SpringBoot自定义starter1自定义starter1.1新建project和Module1.2对于starter-provider1.3install1.4对于starter-user1.5测试2执行......
  • 230116_50_SpringBoot入门
    指定自定义的配置文件bill.propertiesbill.properitesname=billage=11happy=falsebirth=2021/12/2通过@PropertySource注解指定自定义的配置文件@PropertyS......
  • 写一个 Hello SpringBoot2 项目
     项目目录:helloSpringBoot2、MainApplication、pom.xml  helloSpringBoot2逻辑类,标记@RestController/*@RestController的作用等同于@Controller+@ResponseB......
  • 过滤器Filter
       ......
  • yml文件配置了但是springboot读不到yml的内容的问题(已解决)
    在写项目时可能误操作加了这一句代码,结果就导致了系统读不到yml配置解决方法:删除pom.xml中的<packagin>pom</packagin>或者尝试 https://blog.csdn.net/qq_41555595/art......
  • 一个项目 多个拦截器
    1. addInterceptors方法中加多条   @ConfigurationpublicclassResourcesConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddInterce......