ThreadLocal在拦截器中的使用
前置过滤捕获,写入context中,后置删除
每个request请求都有自己线程独享的数据,所以用到了ThreadLocal
1.添加拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new IdentityInterceptor())
.addPathPatterns("/**");
}
}
2.拦截器定义
@Slf4j
@Component
public class IdentityInterceptor implements HandlerInterceptor {
/*
根据HttpHeader中的roleType判断用户身份
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
var identityStr = request.getHeader("roleType");
var loginContext = LoginContext.getLoginContext();
var pin = loginContext != null ? loginContext.getPin() : null;
Identity identity;
if (Strings.isNullOrEmpty(identityStr) ||
!Enums.getIfPresent(IdentityType.class, identityStr).isPresent()) {
log.warn("Identity:[{}] not found,use default identity instead.url:{}, User:{}", identityStr, request.getRequestURL(), pin);
identity = Identity.DEFAULT_IDENTITY;
} else {
identity = new Identity(identityStr);
}
Identity.setIdentity(identity); // 核心是这个,写入用户角色身份上下文
log.info("RoleType:[{}],user:[{}]-Identity:[{}] for url:{}. ", identityStr, pin, identity.getIdentityType(), request.getRequestURL());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
log.info("remove Identity for [{}] from url {}"
, Identity.getIdentity() == null ? "null" : Identity.getIdentity().getIdentityType()
, request.getRequestURL());
Identity.remove(); // 删除用户角色上下文数据
}
}
3.Identity用户身份定义
package delta.service.session;
import com.alibaba.fastjson.JSON;
import com.jd.jsf.gd.util.RpcContext;
import org.apache.logging.log4j.util.Strings;
/**
* 用户身份信息
*
* @author zhoulun
* @date 2023-03-28 15:53
*/
public class Identity implements java.io.Serializable {
/**
* 序列化兼容
*/
private static final long serialVersionUID = 1L;
/**
* 用户身份属性在Session中的Key
*/
public static final String IDENTITY_CONTEXT_KEY = "delta-identity";
/**
* 用户身份 线程缓存
*/
private static final ThreadLocal<Identity> HOLDER = new ThreadLocal<>();
/**
* 默认构造函数
*
* @param identityTypeStr 用户身份类型
*/
public Identity(String identityTypeStr,String pin) {
//判断枚举项中是否存在该值
this.identityType = IdentityType.valueOf(identityTypeStr);
this.pin = pin;
}
/**
* 默认用户身份
*/
public static final Identity DEFAULT_IDENTITY = new Identity(IdentityType.COMMON_USER.name(),"AnonymousUser");
/**
* 用户身份类型
*/
private final IdentityType identityType;
/**
* 设置当前用户身份
*
* @param id 用户身份
*/
public static void setIdentity(Identity id) {
HOLDER.set(id);
//序列化为String再放Session中
RpcContext
.getContext()
.setSessionAttribute(
IDENTITY_CONTEXT_KEY,
JSON.toJSONString(id));
}
/**
* @return 获取当前用户身份
*/
public IdentityType getIdentityType() {
return identityType;
}
/** 用户pin */
private String pin;
public String getPin() {
return pin;
}
public void setPin(String pin) {
this.pin = pin;
}
/**
* 请求结束时清理用户身份信息
*/
public static void remove() {
HOLDER.remove();
RpcContext.getContext().clearSession();
}
/**
* @return 获取当前用户身份
*/
public static Identity getIdentity() {
Identity identity = HOLDER.get();
if (identity == null) {
String identityStr = (String) RpcContext.getContext().getSessionAttribute(IDENTITY_CONTEXT_KEY);
if (Strings.isNotEmpty(identityStr)) {
identity = JSON.parseObject(identityStr, Identity.class);
HOLDER.set(identity);
}
}
return identity;
}
@Override
public String toString() {
return "Identity{" +
"identityType=" + identityType +
", pin='" + pin + '\'' +
'}';
}
}
原创:做时间的朋友
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示