多租户实现(1)controller层拦截器和ThreadLocal

该文章介绍了如何解决公司的多租户需求,通过前端在Header中添加tenantId字段,后端使用ControllerInterceptor拦截器获取并利用ThreadLocal存储,确保请求上下文中的tenantId可用。其中,使用了阿里提供的TransmittableThreadLocal实现父子线程间的变量传递,同时讨论了线程安全问题。
摘要由CSDN通过智能技术生成

解决了公司要求的多租户的一个功能,有些涉及的点,作为一个系列记录哈。

前端统一在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,父线程设置后可以在子线程使用;但是在多线程情况下,两个线程存储的同一个变量是会混淆的。

ThreadLocal是Java中的一个类,用于在多线程环境下保存线程私有的数据。每个线程都有自己独立的ThreadLocal实例,可以在其中存储和获取数据,而不会对其他线程产生影响。 拦截器是一种在请求处理过程中进行预处理和后处理的机制。它可以用来拦截请求并进行一些通用的处理,例如身份验证、日志记录等。在Java Web开发中,拦截器通常被用于对请求进行过滤和控制。 在上述引用中,ThreadLocal被用于在拦截器中保存当前登录用户的信息。通过将用户信息存储在ThreadLocal中,可以在后续的处理中方便地获取用户信息,同时确保线程间的安全性。当用户需要获取自己的信息时,可以直接从ThreadLocal中获取,而无需传递用户信息作为参数。 在拦截器中,可以通过创建一个UserUtils类来实现对用户信息的存取。这个类使用ThreadLocal来保存用户信息,并提供了相应的方法来获取和移除存储在ThreadLocal中的用户信息。通过这种方式,可以在拦截器中方便地获取用户信息,而不需要在每个请求中传递用户信息。 综上所述,ThreadLocal拦截器在Java Web开发中常常搭配使用。ThreadLocal可以用于在多线程环境下保存线程私有的数据,而拦截器可以用于对请求进行过滤和控制。通过在拦截器中使用ThreadLocal来保存用户信息,可以方便地在后续的处理中获取用户信息,并确保线程间的安全性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [拦截器以及添加拦截器以及拦截安全问题-----ThreadLocal](https://blog.csdn.net/weixin_52263247/article/details/127562538)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [Springboot中的拦截器以及ThreadLocal使用](https://blog.csdn.net/qq453660983/article/details/125276544)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值