user-app更改.md 7.7 KB

[17 tools called]

先修改 user-app 的数据源 key,然后新增租户数据源管理类和租户切换过滤器,最后编译+写文档。

[22 tools called]

下面是这次对 C 端 fs-user-app 的 SaaS 改造情况、用法和说明。


一、这次具体改了什么(代码层面)

1. 数据源 key 统一为字符串(MASTER/SLAVE)

  • 文件com.fs.framework.config.DataSourceConfig
  • 改动:将原来用枚举作为 key 的写法统一为字符串 key: java targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource); targetDataSources.put(DataSourceType.SLAVE.name(), slaveDataSource); - 原因DynamicDataSourceContextHolder.setDataSourceType() 传的是字符串(如 "MASTER"),以前 targetDataSources 用的是 DataSourceType.MASTER(枚举),两者不相等,后面做动态切库会出问题,所以先把 key 统一成字符串。 #### 2. 新增租户数据源管理类 TenantDataSourceManager - 文件com.fs.framework.datasource.TenantDataSourceManager - 作用: - 根据主库里的 TenantInfotenant_info 表)动态创建租户库的数据源(DruidDataSource); - 把新数据源挂到当前 DynamicDataSourceresolvedDataSources 上; - 调用 DynamicDataSourceContextHolder.setDataSourceType("tenant:{tenantId}") 把当前线程切到对应租户库; - 提供 clear() 方法在请求结束时清理 ThreadLocal,避免线程复用串库。 - 实现要点: - 内部用 TENANT_DS_CACHE 缓存租户数据源,避免重复创建连接池; - 用反射访问 AbstractRoutingDataSource.resolvedDataSources,运行时追加数据源; - 租户 key 统一为 tenant:{id},和 admin/company 一致; - 注释里已经详细解释了用途和注意点。 #### 3. 新增租户切换过滤器 AppTenantSwitchFilter - 文件com.fs.framework.filter.AppTenantSwitchFilter - 注解@Component@Order(5),继承 OncePerRequestFilter。 - 入口约定: - 使用请求头 X-Tenant-Code 作为 C 端的租户标识(和 admin 的 tenantCode 含义一致)。 - 前端 app / H5 / 小程序只要在请求头上带上这个租户编码,本次改造就会按该租户切库并加载租户配置。 - 过滤逻辑(按请求): 1. 从请求头读取 X-Tenant-Code: - 为空:直接放行,不做任何租户切换,兼容老逻辑(单库)。 2. 切到主库 MASTER: - DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MASTER.name()); 3. 用 TenantInfoService 在主库根据 tenantCodetenant_info: - 找不到 / 状态不为启用 / 已过期:记录日志,放行但不切库(保持单库行为)。 4. 对有效租户调用 tenantDataSourceManager.switchTenant(tenant) 切到该租户库: - 如无数据源则创建一个 DruidDataSource 并挂到 DynamicDataSource; - 当前线程的数据源 key 变为 tenant:{id}。 5. 在租户库中查询租户级项目配置: - SysConfig cfg = sysConfigMapper.selectConfigByConfigKey("projectConfig"); - 若有值:TenantConfigContext.set(JSONObject.parseObject(cfg.getConfigValue())); - 然后调用 ProjectConfig.loadTenantConfigsFromContext(),让 Wx/支付等配置指向当前租户。 6. 调用 filterChain.doFilter(request, response),后面的 Controller/Service/Mapper 就跑在该租户库上,并使用该租户的项目配置。 7. finally 中清理上下文: - ProjectConfig.clearTenantConfigs(); - TenantConfigContext.clear(); - tenantDataSourceManager.clear();(内部清除数据源标记)。 - 兼容性: - 不带 X-Tenant-Code:一切照旧(单库)。 - 错误/禁用/过期租户:仅打日志,不中断请求,退回单库行为(你可以后面再根据需要调整为直接返回错误)。 --- ### 二、C 端前端需要怎么配合(非常关键) 1. 每个 C 端请求都带上 X-Tenant-Code: - header 名:X-Tenant-Code; - 值:你的租户编码(主库 tenant_info.tenant_code)。 2. 包括以下类型的请求: - 登录接口(/app/app/login/store/app/app/login 等); - 用户信息、课程、订单、SOP 等所有业务接口; - 登出(如有)等。 3. 租户编码获取方式(你可以按业务决定): - 用户进入 app 之前选择医院/企业; - 二级域名解析(如 tenantA.xxx.comtenantCode=tenantA),前端启动时就把这个值带在 header 里。 只要 header 带得上,多租户这层就自动生效。 --- ### 三、现有登录 / Token / Redis 行为说明 - user-app 目前的登录逻辑(AppLoginController / AppLoginScrmController没有改: - 还是用 JwtUtils.generateToken(userId) 生成 APPToken; - 还是把 token 存到 Redis 的 userToken:{userId}; - 鉴权还是用 header 里的 APPToken 解出 userId。 - 这次的 SaaS 改造: - 不改 token 结构,不强行在 token 里塞 tenantId; - 按请求头的 X-Tenant-Code 切库,把“用户归属哪个租户”的责任交给前端来决定; - Redis 这块暂时也不按租户做前缀,保证旧逻辑无感知(如果后面你要对 C 端 Redis 也做租户隔离,可以再单独一轮改造)。 --- ### 四、如何自测 user-app C 端的多租户 你可以用 Postman 或直接在 app 上做几组简单验证: 1. 多租户切库验证 - 在主库的 tenant_info 中配置两个租户 A / B,对应不同业务库,两个库中插入不同的测试数据; - 调用同一个 C 端接口(比如课程列表),分别带: - X-Tenant-Code: A - X-Tenant-Code: B - 确认两个请求看到的是各自库中的数据(比如医院名/课程名不同)。 2. 租户配置隔离验证 - 在租户 A/B 的各自库的 sys_config.projectConfig 里,配置不同的微信 / 支付参数(可以改一个明显的字段); - 调用依赖这些配置的接口(如微信登录、支付相关接口),看是否按不同租户配置生效。 3. 兼容性验证 - 不带 X-Tenant-Code 调接口,确保行为与改造前一致(不报错,不异常,仍然能正常访问)。 4. 异常租户验证 - 用一个不存在的 X-Tenant-Code 请求,观察日志里有告警(租户不存在 / 禁用 / 过期),同时请求不会抛异常,只是退回用主库。 --- ### 五、user-app 模块改造说明文档 我已经帮你在项目里生成了一个专门的文档: - 路径docs/user-app模块SaaS改造说明.md 里面详细写了: - 本次改造的目标、原则; - DataSourceConfig 的改动; - TenantDataSourceManagerAppTenantSwitchFilter 的设计与实现细节; - 前端如何带 X-Tenant-Code; - 推荐的自测场景。 你可以直接把这个文档发给前端和其他后端同事,对接起来会更顺畅。 --- ### 六、总结(给你一个操作要点版) - 后端: - 已经支持通过 X-Tenant-Code 切换到对应租户库,并加载该租户的 projectConfig。 - 老逻辑兼容,不带头还是单库。 - 前端需要做的一件事: - 所有 user-app 请求(含登录)统一加上请求头: - X-Tenant-Code: <对应的租户编码>。 如果你希望下一步把 C 端的 Token 和 Redis 也做成像 admin/company 那种“token 里带 tenantId、Redis key 按租户隔离”的模式,我也可以再帮你设计一套不影响现有用户的渐进改法。