ThreadLocal的使用

ThreadLocal 一般不会单独使用,基本上都是 放在一个工具类中,然后在拦截器中去使用(至少存储 Token 的时候是这样的)

这里为了更加还原真实的线上环境,直接就用了 拦截器+统一返回+全局异常捕获+ThreadLocal,项目还是比较完整的

首先创建一个项目 启动后看项目是否能跑通 这个就很简单了,直接略过

创建 ThreadlLocal 的工具类

public class TokenUtils {
    // 通过 ThreadLocal 存储 token
    private static final ThreadLocal<String> tokenThreadLocal = new ThreadLocal<>();

    // 设置 token
    public static void setToken(String token) {
        tokenThreadLocal.set(token);
    }

    // 获取 token
    public static String getToken() {
        return tokenThreadLocal.get();
    }

    // 清除 token
    public static void clearToken() {
        tokenThreadLocal.remove();
    }
}

编写拦截器 并注册到 容器中

//一个拦截器,拦截请求,把请求的时间记录下来,并将请求头中的 token 拿出来
public class MyInterceptor implements HandlerInterceptor {

    @Override//在请求处理之前进行调用(Controller方法调用之前)
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //记录请求时间
        long startTime = System.currentTimeMillis();
        request.setAttribute("startTime", startTime);
        //将请求头中的 token 拿出来
//        String token = request.getHeader("token");
        //从 Authorization 中获取 token 并去除 Bearer 字符串
        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
        }

        //将 token 放入 ThreadLocal 中
        TokenUtils.setToken(token);
        return true;
    }

    @Override//请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        //获取请求时间
        long startTime = (long) request.getAttribute("startTime");
        //计算请求处理时间
        long endTime = System.currentTimeMillis();
        System.out.println("本次请求处理时间为:" + (endTime - startTime) + "ms");
    }

    @Override//在整个请求结束之后被调用,也就是在 DispatcherServlet 渲染了对应的视图之后执行
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //移除 ThreadLocal 中的 token
        System.out.println("清除 token" );
        TokenUtils.clearToken();
    }
}

注意,HandlerInterceptor 并不能让你 对返回值进行一些处理和修改,如果你想对返回值做处理和修改,你需要去了解的是 ResponseBodyAdvice

@Configuration
public class MyWebConfig implements WebMvcConfigurer {

    //注册 MyInterceptor 拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**")
                .excludePathPatterns("/public/**"); // 排除"/public"下的所有请求
    }
}

创建一个类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class MyStudent
{
    private String name;
    private int age;
}

统一的返回值

@Data
// 统一返回类
public class UnifiedReturn<T> {

    private int code;// 状态码  200正常  各种异常 需要在 枚举里面定义
    private String msg;// 返回信息
    private T data;// 返回数据

    public UnifiedReturn(T data) {
        this.data = data;
    }

    //success
    public static <T> UnifiedReturn<T> success(T data) {
        UnifiedReturn<T> aReturn = new UnifiedReturn<>(data);
        aReturn.setCode(UnifiedReturnEnum.SUCCESS.getCode());
        aReturn.setMsg(UnifiedReturnEnum.SUCCESS.getMsg());
        return aReturn;
    }

    //error
    public static <T> UnifiedReturn<T> error(int code, String msg) {
        UnifiedReturn<T> aReturn = new UnifiedReturn<>(null);
        aReturn.setCode(code);
        aReturn.setMsg(msg);
        return aReturn;
    }
}

返回值的枚举

// 统一返回 枚举
public enum UnifiedReturnEnum {

    SUCCESS(200, "成功"),
    FAIL(500, "失败"),
    NO_PERMISSION(403, "无权限"),
    NOT_FOUND(404, "未找到"),
    PARAM_ERROR(400, "参数错误");

    private int code;
    private String msg;

    UnifiedReturnEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

统一的 异常捕获

@ControllerAdvice//全局异常处理
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    @ResponseBody  //返回json  这边是一定要加的
    public UnifiedReturn<String> exceptionHandler(Exception e) {
        return UnifiedReturn.error(UnifiedReturnEnum.FAIL.getCode(), e.getMessage());
    }
}

控制器

@RestController
@RequestMapping("/basic")
public class BasicController {

    @GetMapping("/hello")
    public UnifiedReturn<MyStudent> hello() {
        String token = TokenUtils.getToken();//该方法想在哪里用都可以,只要在同一个线程中 都能获取到 token
        System.out.println("token: " + token);
        return UnifiedReturn.success(new MyStudent("theonefx", 18));
    }

    //测试异常处理--这里测试的是 运行时异常
    @GetMapping("/exception")
    public UnifiedReturn<String> exception() {
       int i = 1/0;
       return UnifiedReturn.success("success");//不会执行到这里
    }

    @GetMapping("/exception2")//这里测试的是 主动抛出的异常
    public UnifiedReturn<String> test() {
       throw new RuntimeException("test exception");
    }

}

请求看一下

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 10
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值