spring boot 2.X 实现自定义拦截器

一、什么是拦截器

       拦截器是spring aop思想的一种体现和运用,底层通过动态代理模式完成;拦截器不依赖于servlet容器,依赖于web框架,由于拦截器是基于web框架的调用,因此可以使用spring的依赖注入(DI)获取IOC容器中的各个bean;可以用来拦截一些非法的Action请求,或者是对Action请求进行一些预处理和请求后的一些处理等,使得我们业务更加符合实际需求,当然也可以在一定程度上保证系统的安全性。

二、拦截器的使用场景是什么

       1.Token令牌的验证:验证token是否过期,token数据是否被篡改

       2.日志记录:记录请求信息的日志,以便进行信息监控、信息统计等

       3.权限检查:如用户登录校验,如果用户登录则进行Action方法,否则直接返回登录页面

       4.性能监控:如检测方法的执行时间,在进入控制器之前记录开始时间,在处理完成后记录结束时间,得到请求处理总时间

三、spring boot 2.X实现自定义拦截器的方法

       spring boot 2.X和1.X版本在定义拦截器时有两点不同:

       1.spring boot 2.X和1.X在配置类上的定义方式不同

       1.X和2.X在拦截器的实现类上都是实现HandlerInterceptor接口,这点两者没有区别;但是在配置方式上有区别,1.X版本在  自定义拦截器配置类上是继承WebMvcConfigurerAdapter类,WebMvcConfigurerAdapter实际上是 WebMvcConfigurer接口的空实现类;
       在2.X版本中对应的是Spring5.x,而Spring5.0以后WebMvcConfigurerAdapter已经过时了,2.X版本的拦截器的配置类是实现WebMvcConfigurer接口,然后重写接口中的方法,这也是官方推荐使用的。在2.X版本中继续使用WebMvcConfigurerAdapter类也不是不可以,只是不推荐而已;

       2.spring boot 2.X和1.X在静态资源访问上不同

      1.X的resources/static目录下的静态资源可以直接访问,并且访问的时候不需要在路径上加static;如果有自定义的拦截器进  行拦截时,请求静态资源的路径也不会被拦截;

      2.X如果有自定义的拦截器时,访问静态资源的文件就会被拦截,解决方法是在拦截器的配置类上配置静态资源路径,使得拦截器不在进行拦截;

 2.X版本自定义拦截器并实现HandlerInterceptor接口,代码如下:

public class TokenInterceptor implements HandlerInterceptor
{
    
    /*
     * 进入controller层之前拦截请求
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("************TokenInterceptor preHandle executed**********");
        System.out.println("getContextPath:" + request.getContextPath());
        System.out.println("getServletPath:" + request.getServletPath());
        System.out.println("getRequestURI:" + request.getRequestURI());
        System.out.println("getRequestURL:" + request.getRequestURL());
        // 返回true,postHandler和afterCompletion方法才能执行
        // 否则false为拒绝执行,起到拦截器控制作用
        return true;
    }
    
    /*
     * 处理请求完成后视图渲染之前的处理操作,但只有preHandle方法返回true的时候才会执行
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception {
        System.out.println("************TokenInterceptor postHandle executed**********");
    }
    
    /*
     * 视图渲染之后的操作,同样需要preHandle返回true
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
       System.out.println("************TokenInterceptor afterCompletion executed**********");
    }
}
  • preHandler:业务处理器处理请求之前被调用,对用户的request进行处理,若返回值为true,则继续调用后续的拦截器和目标方法;若返回值为false,则终止请求;这里可以加上登录校验,权限拦截等;
  • postHandler:Controller执行以后,但是未返回视图前调用该方法,这里可以对模型数据在返回用户之前进行加工处理;
  • afterCompletion:Controller执行以后且返回视图后调用该方法,可以得到Controller时的异常信息,这里可以记录操作日志,资源清理等。

 2.X版本自定义配置类并实现WebMvcConfigurer接口,在该配置类中对2.X版本静态资源不能访问的问题进行修复,代码如下:

@Configuration
public class WebConfig implements WebMvcConfigurer
{
   
    @Autowired
    private InterceptorPathBean interceptorPathBean;


    // 以下WebMvcConfigurerAdapter 比较常用的重写接口
    // /** 解决跨域问题 **/
    // public void addCorsMappings(CorsRegistry registry);
    // /** 添加拦截器 **/
    // void addInterceptors(InterceptorRegistry registry);
    // /** 配置视图解析器 **/
    // void configureViewResolvers(ViewResolverRegistry registry);
    // /** 配置内容裁决的一些选项 **/
    // void configureContentNegotiation(ContentNegotiationConfigurer configurer);
    // /** 视图跳转控制器 **/
    // void addViewControllers(ViewControllerRegistry registry);
    // /** 静态资源处理 **/
    // void addResourceHandlers(ResourceHandlerRegistry registry);
    // /** 默认静态资源处理器 **/
    // void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer);
    
    /**
     * 表示这些配置的表示静态文件所处路径, 不用拦截
     * 注意:这段代码同时也指定了项目静态资源的访问路径,所以可以不用在application.yml文件中配置:spring.mvc.static-path-pattern=/static/**
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/");
        registry.addResourceHandler("/templates/**")
                .addResourceLocations("classpath:/templates/");
    }
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(tokenInterceptor())
                 // 设置需要拦截的路径
                 // 这里add"/**"(拦截所有请求),下面的exclude才起作用,且不管controller层是否能匹配客户端请求,拦截器都起作用拦截
                 .addPathPatterns(interceptorPathBean.getInclude())   //  拦截
                 .excludePathPatterns(interceptorPathBean.getExclude());  //  不拦截
    }
    @Bean
    public TokenInterceptor tokenInterceptor() {
        return new TokenInterceptor();
    }
}

 我这里是将拦截器需要拦截的路径和不需要拦截的路径在yml文件中进行了配置,然后注入InterceptorPathBean,获取需要拦截   的和不需要拦截的路径;

 在该配置类中重新了addResourceHandlers(ResourceHandlerRegistry registry)方法来实现静态资源的访问;

四、spring boot 注册多个拦截器以及拦截器的执行顺序

       如果需要同时注册多个拦截器,只需要在拦截器配置类中的addInterceptors(InterceptorRegistry registry)方法中依次注册就行,代码如下:

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(tokenInterceptor())
                 // 设置需要拦截的路径
                 // 这里add"/**"(拦截所有请求),下面的exclude才起作用,且不管controller层是否能匹配客户端请求,拦截器都起作用拦截
                 .addPathPatterns(interceptorPathBean.getInclude())   //  拦截
                 .excludePathPatterns(interceptorPathBean.getExclude());  //  不拦截
        registry.addInterceptor(loginInterceptor())
        .addPathPatterns(interceptorPathBean.getInclude())   //  拦截
        .excludePathPatterns(interceptorPathBean.getExclude());  //  不拦截
    }
    
    @Bean
    public TokenInterceptor tokenInterceptor() {
        return new TokenInterceptor();
    }
    
    @Bean
    public LoginInterceptor loginInterceptor() {
        return new LoginInterceptor();
    }

 多个拦截器注册时,执行顺序跟addInterceptor()这个方法添加拦截器的先后顺序有关,preHandle这个方法是先添加,先执行。   postHandle 和 afterCompletion 这两个方法是先添加后执行。

©️2020 CSDN 皮肤主题: 书香水墨 设计师:CSDN官方博客 返回首页