如何把 request 中的数据传递到 service 或者 controller, 甚至任何组件中?
案例:我们需要在 service 中获取 request.header 中的 token,可是 service 中无法访问 request 对象,何解?
此时, theadLocal 就派上了大用场。废话不说,先写出工具类来:
public class BaseContext {
public static final ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
public static void set(Integer id) {
threadLocal.set(id);
}
public static Long get() {
return threadLocal.get();
}
public static void remove() {
threadLocal.remove();
}
}
没错。就是这个工具类,创建一个 ThreadLocal对象,并可以设置,获取,移除其保存的值。而对于 web 应用而言,每一个请求,会创建一个单独的线程。我们可以在应用中访问这个线程,来得到或者修改其保存的值, Everywhere!
那一般情况下,我们都在拦截器中查看请求头是否包含了 jwt token。没有token, 拜拜,如果有,放行。此时,我们要额外做一件事,把 token 保存到 threadLocal 中。
代码:
@Component
public class JWTInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("token");
log.info("token:{}", token);
if (token == null) {
return false;
}
Integer currentUserId = JWTUtils.parseJWT(token);
if (currentUserId == null) {
return false;
}
BaseContext.set(empId);
return true;
}
}
然后就可以在任何地方获取这个值了,比如在 service 里面:
@Service
public class UserServcieImpl implements UserService {
public void createUser(UserDto dto){
// 获取当前登录的用户 id
Integer currentUserId = BaseContext.get()
User user = new User();
user.setCreatedBy(currentUserId);
...
}
}
初学者大多数情况下很讨厌 ThreadLocal,因为这东西可以很复杂,而且不知道有什么用。这下知道好用了吧?