解决了公司要求的多租户的一个功能,有些涉及的点,作为一个系列记录哈。
前端统一在header里添加tenantId字段后,后端统一获取
@Component
public class ControllerInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String tenantId = request.getHeader(ThreadLocalUtil.TENANT_ID);
ThreadLocalUtil.set(ThreadLocalUtil.TENANT_ID,tenantId);
return true;
}
// 后处理方法,在处理器执行之后,但是页面跳转之前执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
ThreadLocalUtil.remove();
ThreadLocalUtil.remove(false);
}
}
ThreadLocal存储当前线程的变量
public class ThreadLocalUtil {
/**
* 允许父子线程数据传递
*/
private static final ThreadLocal<Map<String,Object>> transmit = new TransmittableThreadLocal<>();
/**
* 不允许父子线程传递
*/
private static final ThreadLocal<Map<String,Object>> unTransmit = new ThreadLocal<>();
public static final String TENANT_ID = "tenantId";
public static void remove(){
transmit.remove();
}
public static Object get(String key){
return getContext(true).get(key);
}
public static void set(String key,Object value){
getContext(true).put(key,value);
}
private static Map<String,Object> getContext(boolean isTrue){
Map<String,Object> map = null;
if(isTrue){
map = transmit.get();
if(map==null){
map = new HashMap<>();
transmit.set(map);
}
}else {
map = unTransmit.get();
if(map==null){
map = new HashMap<>();
unTransmit.set(map);
}
}
return map;
}
public static Object get(String key,boolean isTrue){
return getContext(isTrue).get(key);
}
public static void set(String key,Object value,boolean isTrue){
getContext(isTrue).put(key,value);
}
public static void remove(boolean isTrue){
if(isTrue){
transmit.remove();
}else {
unTransmit.remove();
}
}
private ThreadLocalUtil() {
}
}
unTransmit = new ThreadLocal<>() 是jdk提供的,可以保存当前线程的变量
transmit = new TransmittableThreadLocal<>(); 是阿里提供的,父子线程共用一个map,父线程设置后可以在子线程使用;但是在多线程情况下,两个线程存储的同一个变量是会混淆的。