就拿用户上下文信息保存来说。
场景:
现在有一个场景,客户端请求新建一个短链接的分组,用户只需要输入一个分组名,然后确认即可创建分组。(全局唯一的分组 ID 这些都是由后端进行处理的)。如下请求:
而且,我们分组和用户名要进行关联,不然我们怎么知道某个用户下的分组有哪些,或者说短链接分组的归属是谁?
- 然后呢,问题来了,我们这个用户名参数是由前端传递嘛,那前端浏览器总不能一直存储用户信息吧,不安全。
- 或者说让用户手动传递用户名,然后后端验证是否是同一个用户然后再执行请求?这对用户的体验肯定非常不好,(我就是创建个分组而已,你连我是谁都不知道?)
解决方法:
这就可以使用 ThreadLocal 对象,在用户发第一次请求时,拦截器拦截后的处理中,就可以把用户信息作为 value,当前线程 ID 作为 key 存储在 ThreadLocalMap 中,这个 ThreadLocalMap 是封装在 ThreadLocal 中的一个 map 结构,其类似 HashMap,可以存储用户信息对象。
之后在需要获取用户名的时候,只要用用户上下文对象,通过 get 拿到要用的用户信息。
如下是封装的一个 UserContext 类,包含 set,get,remove等
方法。
package org.ktpro.shortlink.admin.common.biz.user;
import com.alibaba.ttl.TransmittableThreadLocal;
import java.util.Optional;
/**
* 用户上下文
*/
public final class UserContext {
//实现ThreadLoal泛型
private static final ThreadLocal<UserInfoDTO> USER_THREAD_LOCAL = new TransmittableThreadLocal<>();
/**
* 设置用户至上下文
*
* @param user 用户详情信息
*/
public static void setUser(UserInfoDTO user) {
USER_THREAD_LOCAL.set(user);
}
/**
* 获取上下文中用户 ID
*
* @return 用户 ID
*/
public static String getUserId() {
UserInfoDTO userInfoDTO = USER_THREAD_LOCAL.get();
return Optional.ofNullable(userInfoDTO).map(UserInfoDTO::getUserId).orElse(null);
}
/**
* 获取上下文中用户名称
*
* @return 用户名称
*/
public static String getUsername() {
UserInfoDTO userInfoDTO = USER_THREAD_LOCAL.get();
return Optional.ofNullable(userInfoDTO).map(UserInfoDTO::getUsername).orElse(null);
}
/**
* 获取上下文中用户真实姓名
*
* @return 用户真实姓名
*/
public static String getRealName() {
UserInfoDTO userInfoDTO = USER_THREAD_LOCAL.get();
return Optional.ofNullable(userInfoDTO).map(UserInfoDTO::getRealName).orElse(null);
}
/**
* 清理用户上下文
*/
public static void removeUser() {
USER_THREAD_LOCAL.remove();
}
}