ThreadLocal 一般不会单独使用,基本上都是 放在一个工具类中,然后在拦截器中去使用(至少存储 Token 的时候是这样的)
这里为了更加还原真实的线上环境,直接就用了 拦截器+统一返回+全局异常捕获+ThreadLocal,项目还是比较完整的
首先创建一个项目 启动后看项目是否能跑通 这个就很简单了,直接略过
创建 ThreadlLocal 的工具类
public class TokenUtils {// 通过 ThreadLocal 存储 tokenprivate static final ThreadLocal<String> tokenThreadLocal = new ThreadLocal<>();// 设置 tokenpublic static void setToken(String token) {tokenThreadLocal.set(token);}// 获取 tokenpublic static String getToken() {return tokenThreadLocal.get();}// 清除 tokenpublic 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 中的 tokenSystem.out.println("清除 token" );TokenUtils.clearToken();}
}
注意,HandlerInterceptor 并不能让你 对返回值进行一些处理和修改,如果你想对返回值做处理和修改,你需要去了解的是 ResponseBodyAdvice
@Configuration
public class MyWebConfig implements WebMvcConfigurer {//注册 MyInterceptor 拦截器@Overridepublic 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;}//successpublic 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;}//errorpublic 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();//该方法想在哪里用都可以,只要在同一个线程中 都能获取到 tokenSystem.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");}}
请求看一下