场景:
接手一个项目,用户信息是用Feign调用用户中心获取,方法之间相互调用使用用户信息很麻烦(1,通过接口传参,2,再次调用Feign)。所以使用ThreadLocal存放用户信息
1,定义用户实体:
@ApiModel("登录用户信息")
@Data
public class FeginUser implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "用户ID")
private String id;
@ApiModelProperty(value = "用户名")
private String name;
@ApiModelProperty(value = "密码")
@JsonIgnore
private String upass;
}
2,定义工具类操作ThreadLocal(存放,获取,删除用户信息)
public class ThreadLocalUtil {
/**
* 保存用户对象的ThreadLocal 在拦截器操作 添加、删除相关用户数据
*/
private static final ThreadLocal<FeginUser> userThreadLocal = new ThreadLocal<FeginUser>();
/**
* 添加当前登录用户方法 在拦截器方法执行前调用设置获取用户
* @param user
*/
public static void addCurrentUser(FeginUser user){
userThreadLocal.set(user);
}
/**
* 获取当前登录用户方法
*/
public static FeginUser getCurrentUser(){
return userThreadLocal.get();
}
/**
* 删除当前登录用户方法 在拦截器方法执行后 移除当前用户对象
*/
public static void remove(){
userThreadLocal.remove();
}
}
3,拦截器:1,访问接口时将用户信息放入ThreadLocal,2,访问结束时候删除ThreadLocal中信息(线程放入线程池并不一定会销毁)
@Component
@Slf4j
public class UserInfoInterceptor implements HandlerInterceptor {
@Autowired
private UserInfoUtil userInfoUtil;
/**
* 请求执行前执行的,将用户信息放入ThreadLocal
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
FeginUser user;
try{
user = userInfoUtil.getUser();
}catch (CustomException e){
log.info("***************************用户未登录, ThreadLocal无信息***************************");
return true;
}
if (null!=user) {
log.info("***************************用户已登录,用户信息放入ThreadLocal***************************");
ThreadLocalUtil.addCurrentUser(user);
return true;
}
log.info("***************************用户未登录, ThreadLocal无信息***************************");
return true;
}
/**
* 接口访问结束后,从ThreadLocal中删除用户信息
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("***************************接口调用结束, 从ThreadLocal删除用户信息***************************");
ThreadLocalUtil.remove();
}
4,配置拦截器。
@Configuration
@ComponentScan
public class MyAppConfigurer extends WebMvcConfigurationSupport {
@Autowired
private UserInfoInterceptor userInfoInterceptor;
/**
* 拦截器,将用户信息放入threadLocal
*
* @param registry
*/
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(this.userInfoInterceptor).addPathPatterns("/**");
super.addInterceptors(registry);
}
}
5,定义用户信息具体操作接口:
为了类实现接口后直接使用(不定义为基础类,是因为类单继承)
public interface IBaseUserInfo {
default Boolean isLogin() {
return ThreadLocalUtil.getCurrentUser() != null;
}
default FeginUser getUser() {
return ThreadLocalUtil.getCurrentUser();
}
default String getUserId() {
if (ThreadLocalUtil.getCurrentUser() != null) {
return ThreadLocalUtil.getCurrentUser().getId();
}
return null;
}
}
6,使用:(代码中第二种使用方法,不需要定义接口)
@Service
public class ApplylServiceImpl implements IBaseUserInfo {
public void applyUserInfo() {
/**
* 1,实现接口后,直接使用
*/
FeginUser user1 = getUser();
/**
* 2,不实现接口,调用ThreadLocalUtil
*/
FeginUser user2 = ThreadLocalUtil.getCurrentUser();
}
}
总结
这种获取用户基础信息的场景非常多,比如项目当中某一个新增接口或者修改接口,需要保存操作日志,那么肯定需要操作人的编码和姓名,那么这个编码和姓名可以放在前端的Cookies中,每次请求的时候携带在请求头中,然后后端接收到后通过ThreadLocal进行一个用户基础信息的保存,然后在整个请求链路当中都是一个线程,那么随时都可以通过这个ThreadLocal进行用户基础信息的访问,很方便,也很直观,现在所在公司也是用的这种方法。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/105992.html