我们希望在 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();
    }

}