用springboot复习springmvc的拦截器(interceptor)

一、怎么玩

1、引入pom.xml
  
    org.springframework.boot
    spring-boot-starter-web
  
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、Controller模拟
@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、拦截执行顺序
  a、正常流程(拦截器拦截到任何都成功)
 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 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、登录检测(renren-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;
    }
}

你可能感兴趣的:(用springboot复习springmvc的拦截器(interceptor))