我们希望在 controller 中不需要每次都自己解析token, 再从里面获取id, mobile
因此可以在 请求进入controller前 提前解析好这些信息并 封装到User对象 然后存到 ThreadLocal . 同时, 过高的请求量可能会导致ThreadLocal内存溢出. 所以我们还需要在 每次请求结束后 清除threadLocal中存的东西
因此技术选型: 拦截器InterCeptor
拦截器
package com.tanhua.server.interceptor;
import com.tanhua.commons.utils.JwtUtils;
import com.tanhua.model.domain.User;
import io.jsonwebtoken.Claims;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class TokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//从请求头获取token
String token = request.getHeader("Authorization");
//验证token是否有效
boolean checked = JwtUtils.verifyToken(token);
//响应数据
if (!checked) {
response.setStatus(401); //token不合法:使用401状态码拦截
return false;
} else {
//token正常可用则放行
//解析token并将User对象存入threadLocal
Claims claims = JwtUtils.getClaims(token);
String mobile = (String) claims.get("mobile");//获取qq号码
Integer id = (Integer) claims.get("id");//获取用户id
User user = new User();
user.setMobile(mobile);
user.setId(Long.valueOf(id));
UserHolder.set(user);//在拦截器中把合法token中包含的用户信息设置到threadLocal中
return true;
}
}
/**
* 当前线程结束后 删除线程中存储的User对象 防止内存溢出
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
UserHolder.remove();
}
}
拦截器可以很简单在请求进入controller之前和从controller中出来之后操作request和response
工具类
package com.tanhua.server.interceptor;
import com.tanhua.model.domain.User;
/**
* 向threadLocal存储数据的工具类
*/
public class UserHolder {
private static ThreadLocal<User> tl = new ThreadLocal<>();
/**
* 将用户对象存入threadLocal
*/
public static void set(User user) {
tl.set(user);
}
/**
* 从当前线程获取到user
*/
public static User get() {
return tl.get();
}
/**
* 获取当前线程的User对象中存储的id
*/
public static Long getUserId(){
return tl.get().getId();
}
/**
* 从当前线程中获取User的联系方式(由于token中的qq已被处理过 所以返回的是真实qq 如482734085)
*/
public static String getMobile() {
return tl.get().getMobile();
}
/**
* 请求完毕后删除当前线程的数据
* 防止内存溢出
*/
public static void remove() {
tl.remove();
}
}