springboot之拦截器

 

转载来至简书(https://www.jianshu.com/p/59fc39ad946e)

 

一,怎么玩

1,引入的pom.xml

  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

2,自定义拦截器

//方式一
public class InterceptorM1 implements HandlerInterceptor {

    private final Logger logger = LoggerFactory.getLogger(this.getClass().getCanonicalName());

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
        logger.info("{}:在请求处理之前进行调用(Controller方法调用之前)", this.getClass().getSimpleName());
        return true;//只有返回true才会继续向下执行,返回false取消当前请求
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object o, ModelAndView modelAndView) throws Exception {
        logger.info("{}:请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)", this.getClass().getSimpleName());
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) throws Exception {
        logger.info("{}:在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)", this.getClass().getSimpleName());
    }
}
//方式二
public class InterceptorM2 extends HandlerInterceptorAdapter {

    private final Logger logger = LoggerFactory.getLogger(this.getClass().getCanonicalName());

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
        logger.info("{}:在请求处理之前进行调用(Controller方法调用之前)", this.getClass().getSimpleName());
        return true;//只有返回true才会继续向下执行,返回false取消当前请求
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object o, ModelAndView modelAndView) throws Exception {
        logger.info("{}:请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)", this.getClass().getSimpleName());
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) throws Exception {
        logger.info("{}:在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)", this.getClass().getSimpleName());
    }
}

3,JavaConfig形式的配置

@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter{

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new InterceptorM1()).addPathPatterns("/**");//用于添加拦截规则
        registry.addInterceptor(new InterceptorM2()).addPathPatterns("/**");
        // 多个拦截器组成一个拦截器链
        // excludePathPatterns 用户排除拦截
    }
}

4,控制器模拟

@RestController
public class Rest {

    @GetMapping("/m1/{id}")
    public String m1(@PathVariable("id") String id) {
        return id;
    }

    @GetMapping("/m2/{id}")
    public String m2(@PathVariable("id") String id) {
        return id;
    }
}

5,项目启动

二,嘛意思

1,HandlerInterceptorAdapter和HandlerInterceptor嘛关系

public abstract class HandlerInterceptorAdapter implements AsyncHandlerInterceptor {

    /**
     * This implementation always returns {@code true}.这个实现总是返回true
         */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {

        return true;
    }

    /**
     * This implementation is empty.这是一个空实现
     */
    @Override
    public void postHandle(
            HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception {
    }

    /**
     * This implementation is empty.这是一个空实现
     */
    @Override
    public void afterCompletion(
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
    }

    /**
     * This implementation is empty.这是一个空实现
     */
    @Override
    public void afterConcurrentHandlingStarted(
            HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
    }

}
public interface AsyncHandlerInterceptor extends HandlerInterceptor {

    void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception;

}
public interface HandlerInterceptor {


    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;
}

总结:HandlerInterceptorAdapter实现了的HandlerInterceptor接口得子接口,那我们在开发时是实现接口的HandlerInterceptor呢还是继承类HandlerInterceptorAdapter,当让了有的时候我们只是实现一个方法,那我们就继承类HandlerInterceptorAdapter,如果全部实现实现接口的HandlerInterceptor

2,拦截执行顺序

  一个,正常流程(拦截器拦截到任何都成功)

 InterceptorM2--preHandle:在请求处理之前进行调用(Controller方法调用之前)
 Controller
 InterceptorM2--postHandle:请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
 InterceptorM1--postHandle:请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
 InterceptorM2--afterCompletion:在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)
 InterceptorM1--afterCompletion:在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)

  B,中断流程(M2失败了)

InterceptorM1--preHandle:在请求处理之前进行调用(Controller方法调用之前)
InterceptorM2--preHandle:在请求处理之前进行调用(Controller方法调用之前)
InterceptorM1--afterCompletion:在整个请求结束之后被调用,也就是在DispatcherServlet 渲染了对应的视图之后执行(主要是用于进行资源清理工作)

如果有3个拦截器第2个中断,第三个就不执行了。

3,源码学习

public class HandlerExecutionChain {
   /**
     * Apply preHandle methods of registered interceptors.
     * @return {@code true} if the execution chain should proceed with the
     * next interceptor or the handler itself. Else, DispatcherServlet assumes
     * that this interceptor has already dealt with the response itself.
     */
    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for (int i = 0; i < interceptors.length; i++) {
                HandlerInterceptor interceptor = interceptors[i];
             // interceptorIndex默认是-1,如果n 个拦截器失败了,就n-1执行triggerAfterCompletion(request, response, null);
                if (!interceptor.preHandle(request, response, this.handler)) {
                    triggerAfterCompletion(request, response, null);
                    return false;
                }
                this.interceptorIndex = i;
            }
        }
        return true;
    }
         /**
     * Apply postHandle methods of registered interceptors.
     */
    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
            throws Exception {

        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for (int i = interceptors.length - 1; i >= 0; i--) {
                HandlerInterceptor interceptor = interceptors[i];
                interceptor.postHandle(request, response, this.handler, mv);
            }
        }
    }

    /**
     * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
     * Will just invoke afterCompletion for all interceptors whose preHandle invocation
     * has successfully completed and returned true.
     */
    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
            throws Exception {

        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for (int i = this.interceptorIndex; i >= 0; i--) {
                HandlerInterceptor interceptor = interceptors[i];
                try {
                    interceptor.afterCompletion(request, response, this.handler, ex);
                }
                catch (Throwable ex2) {
                    logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
                }
            }
        }
    }

    /**
     * Apply afterConcurrentHandlerStarted callback on mapped AsyncHandlerInterceptors.
     */
    void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) {
        HandlerInterceptor[] interceptors = getInterceptors();
        if (!ObjectUtils.isEmpty(interceptors)) {
            for (int i = interceptors.length - 1; i >= 0; i--) {
                if (interceptors[i] instanceof AsyncHandlerInterceptor) {
                    try {
                        AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptors[i];
                        asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler);
                    }
                    catch (Throwable ex) {
                        logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", ex);
                    }
                }
            }
        }
    }
  
}

三,干嘛用

1,性能监控(kaitao)

/**
 * 性能监控
 */
public class PermHandlerInterceptor extends HandlerInterceptorAdapter {

    private final Logger logger = LoggerFactory.getLogger(this.getClass().getCanonicalName());
    //Spring提供的一个命名的ThreadLocal实现
    private NamedThreadLocal<Long> currentTimeThreadLocal = new NamedThreadLocal<>("startTime");

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        PermIgnore annotation;
        if (handler instanceof HandlerMethod){
            annotation = ((HandlerMethod) handler).getMethodAnnotation(PermIgnore.class);
        }else {
            return true;
        }
        //如果有PermIgnore注解,则不性能检测
        if (annotation != null) {
            return true;
        }
        long startTime = System.currentTimeMillis();
        currentTimeThreadLocal.set(startTime);

        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

        PermIgnore annotation;
        if (handler instanceof HandlerMethod){
            annotation = ((HandlerMethod) handler).getMethodAnnotation(PermIgnore.class);
        }else {
            return;
        }
        //如果有PermIgnore注解,则不性能检测
        if (annotation != null) {
            return;
        }
        long endTime = System.currentTimeMillis();
        long startTime = currentTimeThreadLocal.get();
        long useTime = endTime - startTime;
        if (useTime > 1) {
            logger.info("[{}] use {} ms]", request.getRequestURI(), useTime);
        }
    }
}
/**
 * 忽略性能监控,默认有
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PermIgnore {
}
@RestController
public class Rest {

    private final Logger logger = LoggerFactory.getLogger(this.getClass().getCanonicalName());

    @GetMapping("/api/{id}")
    @PermIgnore
    public String m1(@PathVariable("id") String id) {
        logger.info("{}", this.getClass().getSimpleName());
        return id;
    }

    @GetMapping("/api2/{id}")
    public String m2(@PathVariable("id") String id) {
        logger.info("{}", Thread.currentThread().getStackTrace()[1].getMethodName());
        return id;
    }

}
m2
[/api2/2] use 53 ms]
Rest

2,登录检测(人人-fastplus)

@Component
public class AuthorizationInterceptor extends HandlerInterceptorAdapter {
    @Autowired
    private SysUserTokenService tokenService;

    public static final String USER_KEY = "userId";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        AuthIgnore annotation;
        if (handler instanceof HandlerMethod) {
            annotation = ((HandlerMethod) handler).getMethodAnnotation(AuthIgnore.class);
        } else {
            return true;
        }

        //如果有@IgnoreAuth注解,则不验证token
        if (annotation != null) {
            return true;
        }

        //从header中获取token
        String token = request.getHeader("token");
        //如果header中不存在token,则从参数中获取token
        if (StringUtils.isBlank(token)) {
            token = request.getParameter("token");
        }

        //token为空
        if (StringUtils.isBlank(token)) {
            throw new RRException("token不能为空");
        }

        //查询token信息
        SysUserTokenEntity tokenEntity = tokenService.queryByToken(token);
        if (tokenEntity == null || tokenEntity.getExpireTime().getTime() < System.currentTimeMillis()) {
            throw new RRException("token失效,请重新登录", 520);
        }

        //设置userId到request里,后续根据userId,获取用户信息
        request.setAttribute(USER_KEY, tokenEntity.getUserId());

        return true;
    }
}

 

来源:以下
作者:的我女友漏气了
链接:HTTPS://www.jianshu.com/p/59fc39ad946e
来源:书繁简

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值