2025/12/31 16:41:22
网站建设
项目流程
宜昌网站建设兼职,wordpress菜单不现实,住房和城乡建设部的网站,wordpress 美化登录从零实现“默认给 SQL 查询语句加上租户条件”的功能#xff0c;本质上是利用 MyBatis Plus 的插件机制配合 ThreadLocal 上下文来实现的。
我们需要构建一条完整的 “数据 - 规则 - 执行” 的链路。以下是标准化的 5 步实现指南#xff1a;第一步#xff1a;准备“…从零实现“默认给 SQL 查询语句加上租户条件”的功能本质上是利用MyBatis Plus的插件机制配合ThreadLocal上下文来实现的。我们需要构建一条完整的“数据 - 规则 - 执行”的链路。以下是标准化的5 步实现指南第一步准备“背包” (定义上下文容器)你需要一个地方在当前线程中存储“当前租户是谁”。代码核心利用ThreadLocal。publicclassTenantContextHolder{// 存放当前租户IDprivatestaticfinalThreadLocalLongTENANT_IDnewTransmittableThreadLocal();publicstaticvoidsetTenantId(LongtenantId){TENANT_ID.set(tenantId);}publicstaticLonggetTenantId(){returnTENANT_ID.get();}publicstaticvoidclear(){TENANT_ID.remove();}}第二步制定“规则” (实现 Handler 接口)你需要告诉 MyBatis Plus 具体的过滤逻辑租户ID是多少列名叫什么哪些表不需要加代码核心实现TenantLineHandler接口。ComponentpublicclassMyTenantLineHandlerimplementsTenantLineHandler{// 1. 告诉 MP当前租户ID是多少 (从背包里拿)OverridepublicExpressiongetTenantId(){LongtenantIdTenantContextHolder.getTenantId();// 如果没拿到ID比如没登录返回 NullValue 可能会导致报错或查不到数据// 通常这里会做判空或者返回默认值returnnewLongValue(tenantId);}// 2. 告诉 MP数据库里租户列的名字叫什么OverridepublicStringgetTenantIdColumn(){returntenant_id;}// 3. 告诉 MP哪些表需要忽略 (白名单)OverridepublicbooleanignoreTable(StringtableName){// A. 全局白名单系统表(字典、菜单)不需要隔离if(sys_dict.equals(tableName)||sys_menu.equals(tableName)){returntrue;}// B. 动态白名单配合 TenantIgnore 注解使用if(TenantContextHolder.isIgnore()){returntrue;}// 默认必须加过滤条件returnfalse;}}第三步组装“引擎” (配置 MyBatis 拦截器)有了规则Handler你需要把它交给执行者Interceptor并把执行者放入 MyBatis 的插件链中。代码核心配置MybatisPlusInterceptorBean。ConfigurationpublicclassMybatisConfig{BeanpublicMybatisPlusInterceptormybatisPlusInterceptor(MyTenantLineHandlertenantLineHandler){MybatisPlusInterceptorinterceptornewMybatisPlusInterceptor();// 核心动作创建租户拦截器并注入上面的规则 Handler// ⚠️注意建议放在分页插件之前interceptor.addInnerInterceptor(newTenantLineInnerInterceptor(tenantLineHandler));// 添加分页插件interceptor.addInnerInterceptor(newPaginationInnerInterceptor(DbType.MYSQL));returninterceptor;}}第四步数据“注入” (配置 Web 过滤器)引擎装好了但还得有人把燃料租户ID塞进第一步的“背包”里。通常是在请求刚进来时处理。代码核心实现Filter或HandlerInterceptor。ComponentpublicclassTenantContextFilterimplementsFilter{OverridepublicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain){try{// 1. 从请求头 Header 获取 tenant-idHttpServletRequestreq(HttpServletRequest)request;StringtenantIdStrreq.getHeader(tenant-id);if(tenantIdStr!null){// 2. 塞进 ThreadLocal 背包TenantContextHolder.setTenantId(Long.valueOf(tenantIdStr));}// 3. 放行执行后续业务逻辑 (Service - Mapper - SQL拦截器)chain.doFilter(request,response);}finally{// 4. 【重要】请求结束清空背包防止线程污染TenantContextHolder.clear();}}} 总结这一套下来发生了什么请求进来Filter 从 Header 拿到tenant_id1存入TenantContextHolder。业务查询你写了userMapper.selectList(null)。拦截改写TenantLineInnerInterceptor拦截 SQL调用MyTenantLineHandler。读取规则Handler 从TenantContextHolder拿到1。SQL 变身SQL 被自动拼接为SELECT * FROM user WHERE tenant_id 1。请求结束Filter 清空TenantContextHolder。这就是实现“全自动多租户隔离”的完整标准流程。