• 通过实现HandlerInterceptor接口实现一个拦截器


    1. 简介

    web应用开发中,拦截器的应用场景非常广泛,主要用于:

    1. 登陆验证:提取request中请求头携带的token信息;
    2. 鉴权:判断该用户是否有权限访问某个资源
    3. 日志记录:记录该handler的入 和 出
    4. 性能监控、通用行为等等一些其它的操作。

    2. spring中使用拦截器的方式

    spring为我们提供了一个接口:HandlerInterceptor,该接口提供了三个方法:

    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            return true;
    }
    
    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }
    
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    通过名字不难理解每个方法其中的意思:
    preHandler() 方法是调用我们程序中写的controller之前执行的;
    postHander() 方法是controller执行完毕之后,spring会调用该框架;
    afterCompletion() 方法是视图渲染完毕之后被执行。

    preHander()方法返回true时,表示可以进入咱们开发的handler中,否则不能进入。例如,在preHander中进行鉴权案例:

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String authHeader = AuthHeaderUtils.getBearerToken();
        String tenantId = AuthHeaderUtils.getTenantId();
        String userId = AuthHeaderUtils.getUserId();
    
        // 未携带token
        if (StringUtils.isBlank(authHeader)) {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, UNAUTHORIZED);
            return false;
        }
        AuthService authService = SpringUtil.getBean(AuthService.class);
        // 校验token
        TokenInfoDTO tokenInfoDTO = authService.checkToken(authHeader);
        if (Objects.isNull(tokenInfoDTO)) {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, UNAUTHORIZED);
            return false;
        }
        // 是否需要刷新token
        if (tokenInfoDTO.getRefresh()) {
            authHeader = authService.refreshToken(tenantId, userId);
        }
        // 获取用户
        UserDTO user = authService.getUser(authHeader);
        if (Objects.isNull(user)) {
            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, UNAUTHORIZED);
            return false;
        }
        // 将用户信息set到threadLocal中。
        VBPAppContext.setUserObj(user);
        
        response.setHeader(HEADER_AUTHORIZATION, authHeader);
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    上述代码中通过鉴权的用户将会被set到threadLocal中,虽然ThreadLocal中通过实现WeakReference接口进行弱引用防止内存泄漏,但是未被有效释放的对象仍然会占用内存,因此在一整个请求结束之后,最好及时remove一下,即:在拦截器的afterCompletion()方法中及时调用remove:

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        VBPAppContext.removeUserObj();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    淘宝详情api(获取主图)2023年11月20日最新版本
    Getx系列之Dialog
    3500字归纳总结:一名合格的软件测试工程师需要掌握的技能大全
    10个常见的Java面试问题及其答案
    JavaScript模块化:提高代码可维护性和可重用性的利器
    2022年数模国赛冲刺之模型复习1
    交换综合实验以及链路聚合和VRRP
    LVM分区空间扩充
    cc2530用中断程序控制led灯亮灭
    Zuul和GateWay小结
  • 原文地址:https://blog.csdn.net/wangheng673/article/details/133170388