项目要存在用户信息,由于这种关键信息不适合传参的方式,前端将用户信息封装到header里,后台通过拦截器获取,考虑项目没有使用多线程的情况,就用户信息存储在ThreadLocal里,方便拿去,也可以通过全局变量的方式。
1.创建一个userUtils
public class UserUtils {
private UserUtils(){}
// 这里是ThreadLocal,需要有user实体
private static final ThreadLocal<User> USER_INFO = new ThreadLocal<User>();
public static void set(User userInfo) {
USER_INFO.set(userInfo);
}
public static User get() {
return USER_INFO.get();
}
// 方便使用后移除ThreadLocal
public static void remove() {
USER_INFO.remove();
}
public static String getUserName() {
return USER_INFO.get().getUserName();
}
public static String getUserId() {
return USER_INFO.get().getUserId();
}
public static int getUserType() {
return USER_INFO.get().getType();
}
}
2.拦截器
定义好拦截器,有需要service要写,没有用到就不用。preHandle里处理,记得最后要返回true,不然请求就断了。
@Slf4j
@Configuration
public class OpsRequestInterceptor implements HandlerInterceptor {
// 用来保存用户信息的,不需要的话,就不用设置service
OpsUserService opsUserService;
public OpsRequestInterceptor(OpsUserService opsUserService) {
this.opsUserService = opsUserService;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
springboot跨域请求 放行OPTIONS请求
//if(request.getMethod().toUpperCase().equals("OPTIONS")){
// return true;//通过所有OPTION请求
//}
// 前端URL编码,这里要解码,注意中文编码设置utf-8
LOGGER.info("用户信息:{"+request.getHeader("userId")+URLDecoder.decode(request.getHeader("userName"), StandardCharsets.UTF_8.name())+request.getHeader("userType")+"}");
if(StringUtils.isBlank(request.getHeader("userId"))
|| request.getHeader("userId").equalsIgnoreCase("null")){
return false;
}
User User = new User();
// 获取请求头中的参数 参数要跟前端的设置一样
String userName = URLDecoder.decode(request.getHeader("userName"), StandardCharsets.UTF_8.name());
String userId = URLDecoder.decode(request.getHeader("userId"), StandardCharsets.UTF_8.name());
String userType = request.getHeader("userType");
String mobile = request.getHeader("mobile");
userId = userType+"_"+userId;
User.setUserId(userId);
User.setUserName(userName);
User.setType(Integer.parseInt(userType));
User.setMobile(mobile);
UserUtils.set(User);
LOGGER.info("拦截请求并将用户{"+User.getUserName()+"}的相关信息存入ThreadLocal");
return true;
}
/**
* 目录方法执行后
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
/**
* 最后清理
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
LOGGER.info("移除用户信息的ThreadLocal");
UserUtils.remove();
}
}
注册拦截器,可以多个都写进来,填写要拦截的路径。
@Configuration
public class HandlerWebConfig implements WebMvcConfigurer {
// 通过addInterceptor,addPathPatterns拦截类和路径,excludePathPatterns允许路径
@Autowired
OpsUserService opsUserService;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getVerifySignInterceptor()).order(2).addPathPatterns("/anno/ops/rest/**");
// 没有用相关的service要删掉
registry.addInterceptor(new OpsRequestInterceptor(opsUserService)).order(3)
.addPathPatterns("/anno/ops/rest/**"); //要拦截的路径
//.excludePathPatterns("/","/login","/css/**","fonts/**","/images/**","/js/**"); //避免拦截的路径
}
}
具体使用的话,例如UserUtils.getUserId()就可以拿到用户ID了