ai-engineering-init 1.3.4 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/hooks/skill-forced-eval.js +2 -0
- package/.claude/settings.json +3 -3
- package/.claude/skills/add-skill/SKILL.md +79 -32
- package/.claude/skills/api-development/SKILL.md +83 -377
- package/.claude/skills/architecture-design/SKILL.md +138 -632
- package/.claude/skills/backend-annotations/SKILL.md +134 -506
- package/.claude/skills/banana-image/SKILL.md +10 -3
- package/.claude/skills/brainstorm/SKILL.md +103 -535
- package/.claude/skills/bug-detective/SKILL.md +147 -1097
- package/.claude/skills/bug-detective/references/error-patterns.md +242 -0
- package/.claude/skills/code-patterns/SKILL.md +116 -426
- package/.claude/skills/code-patterns/references/leniu-code-patterns.md +87 -0
- package/.claude/skills/crud-development/SKILL.md +64 -304
- package/.claude/skills/data-permission/SKILL.md +105 -412
- package/.claude/skills/data-permission/references/custom-data-scope.md +90 -0
- package/.claude/skills/file-oss-management/SKILL.md +106 -714
- package/.claude/skills/file-oss-management/references/entities.md +105 -0
- package/.claude/skills/file-oss-management/references/service-impl.md +104 -0
- package/.claude/skills/leniu-api-development/SKILL.md +142 -626
- package/.claude/skills/leniu-api-development/references/real-examples.md +273 -0
- package/.claude/skills/leniu-architecture-design/SKILL.md +176 -391
- package/.claude/skills/leniu-backend-annotations/SKILL.md +132 -519
- package/.claude/skills/leniu-brainstorm/SKILL.md +132 -541
- package/.claude/skills/leniu-brainstorm/references/business-scenarios.md +162 -0
- package/.claude/skills/leniu-crud-development/SKILL.md +232 -938
- package/.claude/skills/leniu-crud-development/references/templates.md +597 -0
- package/.claude/skills/leniu-customization-location/SKILL.md +410 -0
- package/.claude/skills/leniu-data-permission/SKILL.md +70 -0
- package/.claude/skills/leniu-java-entity/SKILL.md +76 -590
- package/.claude/skills/leniu-java-entity/references/templates.md +237 -0
- package/.claude/skills/leniu-java-export/SKILL.md +94 -379
- package/.claude/skills/leniu-java-logging/SKILL.md +106 -709
- package/.claude/skills/leniu-java-logging/references/data-mask.md +46 -0
- package/.claude/skills/leniu-java-logging/references/logging-scenarios.md +113 -0
- package/.claude/skills/leniu-java-mybatis/SKILL.md +73 -446
- package/.claude/skills/leniu-java-mybatis/references/report-mapper.md +88 -0
- package/.claude/skills/leniu-report-customization/SKILL.md +111 -365
- package/.claude/skills/leniu-report-customization/references/table-fields.md +93 -0
- package/.claude/skills/leniu-report-standard-customization/SKILL.md +111 -334
- package/.claude/skills/leniu-report-standard-customization/references/analysis-module.md +64 -0
- package/.claude/skills/leniu-report-standard-customization/references/table-fields.md +113 -0
- package/.claude/skills/leniu-security-guard/SKILL.md +133 -347
- package/.claude/skills/mysql-debug/SKILL.md +364 -0
- package/.claude/skills/openspec-apply-change/SKILL.md +10 -1
- package/.claude/skills/openspec-archive-change/SKILL.md +9 -1
- package/.claude/skills/openspec-bulk-archive-change/SKILL.md +9 -1
- package/.claude/skills/openspec-continue-change/SKILL.md +9 -1
- package/.claude/skills/openspec-explore/SKILL.md +10 -1
- package/.claude/skills/openspec-ff-change/SKILL.md +9 -1
- package/.claude/skills/openspec-new-change/SKILL.md +9 -1
- package/.claude/skills/openspec-onboard/SKILL.md +15 -130
- package/.claude/skills/openspec-sync-specs/SKILL.md +9 -1
- package/.claude/skills/openspec-verify-change/SKILL.md +9 -1
- package/.claude/skills/performance-doctor/SKILL.md +110 -434
- package/.claude/skills/redis-cache/SKILL.md +89 -595
- package/.claude/skills/redis-cache/references/listeners.md +23 -0
- package/.claude/skills/scheduled-jobs/SKILL.md +88 -407
- package/.claude/skills/security-guard/SKILL.md +137 -532
- package/.claude/skills/security-guard/references/encrypt-config.md +103 -0
- package/.claude/skills/security-guard/references/sensitive-strategies.md +42 -0
- package/.claude/skills/sms-mail/SKILL.md +116 -574
- package/.claude/skills/sms-mail/references/mail-config.md +88 -0
- package/.claude/skills/sms-mail/references/sms-config.md +74 -0
- package/.claude/skills/social-login/SKILL.md +112 -514
- package/.claude/skills/social-login/references/provider-configs.md +118 -0
- package/.claude/skills/tenant-management/SKILL.md +129 -444
- package/.claude/skills/tenant-management/references/tenant-scenarios.md +91 -0
- package/.claude/skills/test-development/SKILL.md +86 -540
- package/.claude/skills/test-development/references/parameterized-examples.md +119 -0
- package/.claude/skills/utils-toolkit/SKILL.md +52 -305
- package/.claude/skills/utils-toolkit/references/redis-utils-api.md +56 -0
- package/.claude/skills/websocket-sse/SKILL.md +105 -550
- package/.claude/skills/workflow-engine/SKILL.md +147 -502
- package/.codex/skills/add-skill/SKILL.md +79 -32
- package/.codex/skills/api-development/SKILL.md +172 -599
- package/.codex/skills/architecture-design/SKILL.md +138 -504
- package/.codex/skills/backend-annotations/SKILL.md +134 -496
- package/.codex/skills/banana-image/SKILL.md +10 -3
- package/.codex/skills/brainstorm/SKILL.md +103 -535
- package/.codex/skills/bug-detective/SKILL.md +147 -1097
- package/.codex/skills/bug-detective/references/error-patterns.md +242 -0
- package/.codex/skills/code-patterns/SKILL.md +120 -282
- package/.codex/skills/code-patterns/references/leniu-code-patterns.md +87 -0
- package/.codex/skills/crud-development/SKILL.md +64 -292
- package/.codex/skills/data-permission/SKILL.md +108 -407
- package/.codex/skills/data-permission/references/custom-data-scope.md +90 -0
- package/.codex/skills/database-ops/SKILL.md +8 -154
- package/.codex/skills/error-handler/SKILL.md +10 -0
- package/.codex/skills/file-oss-management/SKILL.md +106 -714
- package/.codex/skills/file-oss-management/references/entities.md +105 -0
- package/.codex/skills/file-oss-management/references/service-impl.md +104 -0
- package/.codex/skills/git-workflow/SKILL.md +27 -5
- package/.codex/skills/leniu-api-development/SKILL.md +142 -626
- package/.codex/skills/leniu-api-development/references/real-examples.md +273 -0
- package/.codex/skills/leniu-architecture-design/SKILL.md +176 -391
- package/.codex/skills/leniu-backend-annotations/SKILL.md +132 -519
- package/.codex/skills/leniu-brainstorm/SKILL.md +132 -541
- package/.codex/skills/leniu-brainstorm/references/business-scenarios.md +162 -0
- package/.codex/skills/leniu-crud-development/SKILL.md +232 -938
- package/.codex/skills/leniu-crud-development/references/templates.md +597 -0
- package/.codex/skills/leniu-customization-location/SKILL.md +410 -0
- package/.codex/skills/leniu-data-permission/SKILL.md +70 -0
- package/.codex/skills/leniu-java-code-style/SKILL.md +510 -0
- package/.codex/skills/leniu-java-entity/SKILL.md +76 -590
- package/.codex/skills/leniu-java-entity/references/templates.md +237 -0
- package/.codex/skills/leniu-java-export/SKILL.md +94 -379
- package/.codex/skills/leniu-java-logging/SKILL.md +106 -709
- package/.codex/skills/leniu-java-logging/references/data-mask.md +46 -0
- package/.codex/skills/leniu-java-logging/references/logging-scenarios.md +113 -0
- package/.codex/skills/leniu-java-mybatis/SKILL.md +73 -446
- package/.codex/skills/leniu-java-mybatis/references/report-mapper.md +88 -0
- package/.codex/skills/leniu-report-customization/SKILL.md +111 -365
- package/.codex/skills/leniu-report-customization/references/table-fields.md +93 -0
- package/.codex/skills/leniu-report-standard-customization/SKILL.md +111 -334
- package/.codex/skills/leniu-report-standard-customization/references/analysis-module.md +64 -0
- package/.codex/skills/leniu-report-standard-customization/references/table-fields.md +113 -0
- package/.codex/skills/leniu-security-guard/SKILL.md +133 -347
- package/.codex/skills/mysql-debug/SKILL.md +364 -0
- package/.codex/skills/openspec-apply-change/SKILL.md +10 -1
- package/.codex/skills/openspec-archive-change/SKILL.md +9 -1
- package/.codex/skills/openspec-bulk-archive-change/SKILL.md +9 -1
- package/.codex/skills/openspec-continue-change/SKILL.md +9 -1
- package/.codex/skills/openspec-explore/SKILL.md +10 -1
- package/.codex/skills/openspec-ff-change/SKILL.md +9 -1
- package/.codex/skills/openspec-new-change/SKILL.md +9 -1
- package/.codex/skills/openspec-onboard/SKILL.md +15 -130
- package/.codex/skills/openspec-sync-specs/SKILL.md +9 -1
- package/.codex/skills/openspec-verify-change/SKILL.md +9 -1
- package/.codex/skills/performance-doctor/SKILL.md +110 -434
- package/.codex/skills/project-navigator/SKILL.md +20 -1
- package/.codex/skills/redis-cache/SKILL.md +93 -589
- package/.codex/skills/redis-cache/references/listeners.md +23 -0
- package/.codex/skills/scheduled-jobs/SKILL.md +88 -407
- package/.codex/skills/security-guard/SKILL.md +141 -527
- package/.codex/skills/security-guard/references/encrypt-config.md +103 -0
- package/.codex/skills/security-guard/references/sensitive-strategies.md +42 -0
- package/.codex/skills/sms-mail/SKILL.md +116 -574
- package/.codex/skills/sms-mail/references/mail-config.md +88 -0
- package/.codex/skills/sms-mail/references/sms-config.md +74 -0
- package/.codex/skills/social-login/SKILL.md +112 -514
- package/.codex/skills/social-login/references/provider-configs.md +118 -0
- package/.codex/skills/store-pc/SKILL.md +258 -383
- package/.codex/skills/tenant-management/SKILL.md +129 -444
- package/.codex/skills/tenant-management/references/tenant-scenarios.md +91 -0
- package/.codex/skills/test-development/SKILL.md +86 -540
- package/.codex/skills/test-development/references/parameterized-examples.md +119 -0
- package/.codex/skills/ui-pc/SKILL.md +350 -387
- package/.codex/skills/utils-toolkit/SKILL.md +52 -283
- package/.codex/skills/utils-toolkit/references/redis-utils-api.md +56 -0
- package/.codex/skills/websocket-sse/SKILL.md +105 -550
- package/.codex/skills/workflow-engine/SKILL.md +147 -502
- package/.cursor/hooks/cursor-skill-eval.js +53 -1
- package/.cursor/hooks.json +3 -3
- package/.cursor/skills/add-skill/SKILL.md +79 -32
- package/.cursor/skills/api-development/SKILL.md +83 -377
- package/.cursor/skills/architecture-design/SKILL.md +138 -632
- package/.cursor/skills/backend-annotations/SKILL.md +134 -506
- package/.cursor/skills/banana-image/SKILL.md +10 -3
- package/.cursor/skills/brainstorm/SKILL.md +103 -535
- package/.cursor/skills/bug-detective/SKILL.md +147 -1097
- package/.cursor/skills/bug-detective/references/error-patterns.md +242 -0
- package/.cursor/skills/code-patterns/SKILL.md +116 -426
- package/.cursor/skills/code-patterns/references/leniu-code-patterns.md +87 -0
- package/.cursor/skills/crud-development/SKILL.md +64 -304
- package/.cursor/skills/data-permission/SKILL.md +105 -412
- package/.cursor/skills/data-permission/references/custom-data-scope.md +90 -0
- package/.cursor/skills/file-oss-management/SKILL.md +106 -714
- package/.cursor/skills/file-oss-management/references/entities.md +105 -0
- package/.cursor/skills/file-oss-management/references/service-impl.md +104 -0
- package/.cursor/skills/git-workflow/SKILL.md +27 -5
- package/.cursor/skills/leniu-api-development/SKILL.md +142 -626
- package/.cursor/skills/leniu-api-development/references/real-examples.md +273 -0
- package/.cursor/skills/leniu-architecture-design/SKILL.md +176 -391
- package/.cursor/skills/leniu-backend-annotations/SKILL.md +132 -519
- package/.cursor/skills/leniu-brainstorm/SKILL.md +132 -541
- package/.cursor/skills/leniu-brainstorm/references/business-scenarios.md +162 -0
- package/.cursor/skills/leniu-crud-development/SKILL.md +232 -938
- package/.cursor/skills/leniu-crud-development/references/templates.md +597 -0
- package/.cursor/skills/leniu-customization-location/SKILL.md +410 -0
- package/.cursor/skills/leniu-data-permission/SKILL.md +70 -0
- package/.cursor/skills/leniu-java-code-style/SKILL.md +510 -0
- package/.cursor/skills/leniu-java-entity/SKILL.md +76 -590
- package/.cursor/skills/leniu-java-entity/references/templates.md +237 -0
- package/.cursor/skills/leniu-java-export/SKILL.md +94 -379
- package/.cursor/skills/leniu-java-logging/SKILL.md +106 -709
- package/.cursor/skills/leniu-java-logging/references/data-mask.md +46 -0
- package/.cursor/skills/leniu-java-logging/references/logging-scenarios.md +113 -0
- package/.cursor/skills/leniu-java-mybatis/SKILL.md +73 -446
- package/.cursor/skills/leniu-java-mybatis/references/report-mapper.md +88 -0
- package/.cursor/skills/leniu-report-customization/SKILL.md +111 -365
- package/.cursor/skills/leniu-report-customization/references/table-fields.md +93 -0
- package/.cursor/skills/leniu-report-standard-customization/SKILL.md +111 -334
- package/.cursor/skills/leniu-report-standard-customization/references/analysis-module.md +64 -0
- package/.cursor/skills/leniu-report-standard-customization/references/table-fields.md +113 -0
- package/.cursor/skills/leniu-security-guard/SKILL.md +133 -347
- package/.cursor/skills/mysql-debug/SKILL.md +364 -0
- package/.cursor/skills/openspec-apply-change/SKILL.md +10 -1
- package/.cursor/skills/openspec-archive-change/SKILL.md +9 -1
- package/.cursor/skills/openspec-bulk-archive-change/SKILL.md +9 -1
- package/.cursor/skills/openspec-continue-change/SKILL.md +9 -1
- package/.cursor/skills/openspec-explore/SKILL.md +10 -1
- package/.cursor/skills/openspec-ff-change/SKILL.md +9 -1
- package/.cursor/skills/openspec-new-change/SKILL.md +9 -1
- package/.cursor/skills/openspec-onboard/SKILL.md +15 -130
- package/.cursor/skills/openspec-sync-specs/SKILL.md +9 -1
- package/.cursor/skills/openspec-verify-change/SKILL.md +9 -1
- package/.cursor/skills/performance-doctor/SKILL.md +110 -434
- package/.cursor/skills/redis-cache/SKILL.md +89 -595
- package/.cursor/skills/redis-cache/references/listeners.md +23 -0
- package/.cursor/skills/scheduled-jobs/SKILL.md +88 -407
- package/.cursor/skills/security-guard/SKILL.md +137 -532
- package/.cursor/skills/security-guard/references/encrypt-config.md +103 -0
- package/.cursor/skills/security-guard/references/sensitive-strategies.md +42 -0
- package/.cursor/skills/sms-mail/SKILL.md +116 -574
- package/.cursor/skills/sms-mail/references/mail-config.md +88 -0
- package/.cursor/skills/sms-mail/references/sms-config.md +74 -0
- package/.cursor/skills/social-login/SKILL.md +112 -514
- package/.cursor/skills/social-login/references/provider-configs.md +118 -0
- package/.cursor/skills/tenant-management/SKILL.md +129 -444
- package/.cursor/skills/tenant-management/references/tenant-scenarios.md +91 -0
- package/.cursor/skills/test-development/SKILL.md +86 -540
- package/.cursor/skills/test-development/references/parameterized-examples.md +119 -0
- package/.cursor/skills/utils-toolkit/SKILL.md +52 -305
- package/.cursor/skills/utils-toolkit/references/redis-utils-api.md +56 -0
- package/.cursor/skills/websocket-sse/SKILL.md +105 -550
- package/.cursor/skills/workflow-engine/SKILL.md +147 -502
- package/package.json +1 -1
|
@@ -1,140 +1,50 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: tenant-management
|
|
3
3
|
description: |
|
|
4
|
-
|
|
4
|
+
多租户数据隔离开发指南。基于 MyBatis-Plus 租户插件,自动 SQL/Redis/Cache 隔离。
|
|
5
5
|
|
|
6
6
|
触发场景:
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
7
|
+
- 为业务表添加租户隔离
|
|
8
|
+
- 临时忽略租户过滤查询全量数据
|
|
9
|
+
- 切换到其他租户执行操作
|
|
10
|
+
- 配置排除租户过滤的表
|
|
11
|
+
- 定时任务遍历所有租户
|
|
12
12
|
|
|
13
|
-
触发词:多租户、租户隔离、TenantEntity、TenantHelper
|
|
13
|
+
触发词:多租户、租户隔离、TenantEntity、TenantHelper、tenantId、跨租户、ignore租户、动态租户、租户切换、SaaS、数据隔离
|
|
14
14
|
---
|
|
15
15
|
|
|
16
16
|
# 多租户开发指南
|
|
17
17
|
|
|
18
|
-
>
|
|
18
|
+
> **模块**:`ruoyi-common-tenant` | **核心类**:`TenantHelper`、`TenantEntity`
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## 一、Entity 规范
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
**核心特性**:
|
|
25
|
-
- ✅ 自动 SQL 过滤(无需手动添加 tenant_id 条件)
|
|
26
|
-
- ✅ Redis 缓存自动隔离(Key 前缀自动添加租户)
|
|
27
|
-
- ✅ Spring Cache 租户隔离
|
|
28
|
-
- ✅ Sa-Token 会话租户隔离
|
|
29
|
-
- ✅ 支持临时忽略租户、动态切换租户
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## 一、多租户架构原理
|
|
34
|
-
|
|
35
|
-
### 1.1 数据隔离流程
|
|
36
|
-
|
|
37
|
-
```
|
|
38
|
-
┌─────────────┐ 请求头携带租户ID ┌─────────────┐
|
|
39
|
-
│ 前端请求 │ ───────────────────────→ │ 后端服务 │
|
|
40
|
-
└─────────────┘ └─────────────┘
|
|
41
|
-
│
|
|
42
|
-
┌────────────┴────────────┐
|
|
43
|
-
│ TenantHelper │
|
|
44
|
-
│ 获取当前租户ID │
|
|
45
|
-
└────────────┬────────────┘
|
|
46
|
-
│
|
|
47
|
-
┌──────────────────────────────────┼──────────────────────────────────┐
|
|
48
|
-
│ │ │
|
|
49
|
-
▼ ▼ ▼
|
|
50
|
-
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
51
|
-
│ MyBatis-Plus │ │ Redis 缓存 │ │ Spring Cache │
|
|
52
|
-
│ 自动追加条件 │ │ Key 前缀隔离 │ │ 缓存名隔离 │
|
|
53
|
-
│ WHERE tenant_id │ │ {tenantId}:key │ │ {tenantId}::xxx │
|
|
54
|
-
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### 1.2 自动 SQL 改写
|
|
58
|
-
|
|
59
|
-
原始 SQL:
|
|
60
|
-
```sql
|
|
61
|
-
SELECT * FROM sys_user WHERE status = '1'
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
自动改写后:
|
|
65
|
-
```sql
|
|
66
|
-
SELECT * FROM sys_user WHERE status = '1' AND tenant_id = '000000'
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## 二、Entity 继承规范
|
|
72
|
-
|
|
73
|
-
### 2.1 TenantEntity 基类
|
|
74
|
-
|
|
75
|
-
**位置**:`org.dromara.common.tenant.core.TenantEntity`
|
|
22
|
+
### 继承 TenantEntity
|
|
76
23
|
|
|
77
24
|
```java
|
|
78
|
-
|
|
79
|
-
* 租户基类
|
|
80
|
-
*/
|
|
81
|
-
@Data
|
|
82
|
-
@EqualsAndHashCode(callSuper = true)
|
|
83
|
-
public class TenantEntity extends BaseEntity {
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* 租户编号
|
|
87
|
-
*/
|
|
88
|
-
private String tenantId;
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### 2.2 继承关系
|
|
94
|
-
|
|
95
|
-
```
|
|
96
|
-
TenantEntity
|
|
97
|
-
└── BaseEntity
|
|
98
|
-
├── createDept // 创建部门
|
|
99
|
-
├── createBy // 创建者
|
|
100
|
-
├── createTime // 创建时间
|
|
101
|
-
├── updateBy // 更新者
|
|
102
|
-
├── updateTime // 更新时间
|
|
103
|
-
└── params // 请求参数
|
|
104
|
-
```
|
|
25
|
+
import org.dromara.common.tenant.core.TenantEntity;
|
|
105
26
|
|
|
106
|
-
|
|
27
|
+
// TenantEntity 继承关系:TenantEntity → BaseEntity
|
|
28
|
+
// TenantEntity 额外字段:tenantId
|
|
29
|
+
// BaseEntity 字段:createDept, createBy, createTime, updateBy, updateTime, params
|
|
107
30
|
|
|
108
|
-
```java
|
|
109
|
-
import org.dromara.common.tenant.core.TenantEntity;
|
|
110
|
-
import com.baomidou.mybatisplus.annotation.TableId;
|
|
111
|
-
import com.baomidou.mybatisplus.annotation.TableName;
|
|
112
|
-
import lombok.Data;
|
|
113
|
-
import lombok.EqualsAndHashCode;
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* 业务实体(需要租户隔离)
|
|
117
|
-
*/
|
|
118
31
|
@Data
|
|
119
32
|
@EqualsAndHashCode(callSuper = true)
|
|
120
33
|
@TableName("biz_order")
|
|
121
34
|
public class BizOrder extends TenantEntity {
|
|
122
|
-
|
|
123
35
|
@TableId(value = "id")
|
|
124
36
|
private Long id;
|
|
125
|
-
|
|
126
37
|
private String orderNo;
|
|
127
|
-
|
|
128
38
|
private String status;
|
|
129
39
|
}
|
|
130
40
|
```
|
|
131
41
|
|
|
132
|
-
###
|
|
42
|
+
### 数据库表必须含 tenant_id
|
|
133
43
|
|
|
134
44
|
```sql
|
|
135
45
|
CREATE TABLE biz_order (
|
|
136
46
|
id BIGINT(20) NOT NULL COMMENT '主键ID',
|
|
137
|
-
tenant_id VARCHAR(20) DEFAULT '000000' COMMENT '租户ID', --
|
|
47
|
+
tenant_id VARCHAR(20) DEFAULT '000000' COMMENT '租户ID', -- 必须有
|
|
138
48
|
order_no VARCHAR(64) NOT NULL COMMENT '订单号',
|
|
139
49
|
status CHAR(1) DEFAULT '0' COMMENT '状态',
|
|
140
50
|
create_dept BIGINT(20) DEFAULT NULL COMMENT '创建部门',
|
|
@@ -144,263 +54,137 @@ CREATE TABLE biz_order (
|
|
|
144
54
|
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
145
55
|
del_flag CHAR(1) DEFAULT '0' COMMENT '删除标志',
|
|
146
56
|
PRIMARY KEY (id),
|
|
147
|
-
KEY idx_tenant_id (tenant_id)
|
|
148
|
-
)
|
|
57
|
+
KEY idx_tenant_id (tenant_id)
|
|
58
|
+
);
|
|
149
59
|
```
|
|
150
60
|
|
|
151
61
|
---
|
|
152
62
|
|
|
153
|
-
##
|
|
63
|
+
## 二、TenantHelper 工具类
|
|
154
64
|
|
|
155
65
|
**位置**:`org.dromara.common.tenant.helper.TenantHelper`
|
|
156
66
|
|
|
157
|
-
###
|
|
67
|
+
### API 速查
|
|
158
68
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
69
|
+
| 方法 | 说明 | 返回值 |
|
|
70
|
+
|------|------|--------|
|
|
71
|
+
| `isEnable()` | 租户功能是否启用 | boolean |
|
|
72
|
+
| `getTenantId()` | 获取当前租户ID(优先动态租户) | String |
|
|
73
|
+
| `ignore(Runnable)` | 忽略租户执行(无返回值) | void |
|
|
74
|
+
| `ignore(Supplier<T>)` | 忽略租户执行(有返回值) | T |
|
|
75
|
+
| `dynamic(tenantId, Runnable)` | 切换租户执行(无返回值) | void |
|
|
76
|
+
| `dynamic(tenantId, Supplier<T>)` | 切换租户执行(有返回值) | T |
|
|
77
|
+
| `setDynamic(tenantId)` | 手动设置动态租户(需配合 clearDynamic) | void |
|
|
78
|
+
| `setDynamic(tenantId, true)` | 设置全局动态租户(跨请求,存 Redis) | void |
|
|
79
|
+
| `clearDynamic()` | 清除动态租户 | void |
|
|
169
80
|
|
|
170
|
-
|
|
81
|
+
### 核心用法
|
|
171
82
|
|
|
172
|
-
|
|
173
|
-
TenantHelper
|
|
174
|
-
// 此代码块内的 SQL 不会追加 tenant_id 条件
|
|
175
|
-
List<SysUser> allUsers = userMapper.selectList(null);
|
|
176
|
-
});
|
|
83
|
+
```java
|
|
84
|
+
import org.dromara.common.tenant.helper.TenantHelper;
|
|
177
85
|
|
|
178
|
-
//
|
|
86
|
+
// 1. 忽略租户(查全量数据)
|
|
179
87
|
List<SysUser> allUsers = TenantHelper.ignore(() -> {
|
|
180
|
-
return userMapper.selectList(null);
|
|
88
|
+
return userMapper.selectList(null); // 不追加 tenant_id 条件
|
|
181
89
|
});
|
|
182
90
|
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
// 5. 在指定租户中执行(无返回值)
|
|
91
|
+
// 2. 切换到指定租户(推荐用法)
|
|
186
92
|
TenantHelper.dynamic("000001", () -> {
|
|
187
|
-
//
|
|
188
|
-
userMapper.insert(user);
|
|
93
|
+
userMapper.insert(user); // 使用租户 000001
|
|
189
94
|
});
|
|
190
95
|
|
|
191
|
-
//
|
|
192
|
-
List<SysUser> tenant001Users = TenantHelper.dynamic("000001", () -> {
|
|
193
|
-
return userMapper.selectList(null);
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
// ========== 手动管理动态租户 ==========
|
|
197
|
-
|
|
198
|
-
// 7. 设置动态租户(需手动清理)
|
|
96
|
+
// 3. 手动管理(复杂场景)
|
|
199
97
|
TenantHelper.setDynamic("000001");
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
//
|
|
204
|
-
|
|
205
|
-
// ... 多次请求都使用该租户 ...
|
|
206
|
-
TenantHelper.clearDynamic();
|
|
98
|
+
try {
|
|
99
|
+
userMapper.insert(user);
|
|
100
|
+
} finally {
|
|
101
|
+
TenantHelper.clearDynamic(); // 必须清理!
|
|
102
|
+
}
|
|
207
103
|
```
|
|
208
104
|
|
|
209
|
-
### 3.2 方法速查表
|
|
210
|
-
|
|
211
|
-
| 方法 | 说明 | 使用场景 |
|
|
212
|
-
|------|------|---------|
|
|
213
|
-
| `isEnable()` | 检查租户是否启用 | 条件判断 |
|
|
214
|
-
| `getTenantId()` | 获取当前租户ID | 业务逻辑 |
|
|
215
|
-
| `ignore(Runnable)` | 忽略租户执行(无返回值) | 查询全量数据 |
|
|
216
|
-
| `ignore(Supplier<T>)` | 忽略租户执行(有返回值) | 查询全量数据 |
|
|
217
|
-
| `dynamic(tenantId, Runnable)` | 切换租户执行(无返回值) | 跨租户操作 |
|
|
218
|
-
| `dynamic(tenantId, Supplier<T>)` | 切换租户执行(有返回值) | 跨租户查询 |
|
|
219
|
-
| `setDynamic(tenantId)` | 手动设置动态租户 | 复杂场景 |
|
|
220
|
-
| `setDynamic(tenantId, true)` | 设置全局动态租户 | 跨请求场景 |
|
|
221
|
-
| `getDynamic()` | 获取动态租户 | 调试/检查 |
|
|
222
|
-
| `clearDynamic()` | 清除动态租户 | 配合 setDynamic |
|
|
223
|
-
|
|
224
105
|
---
|
|
225
106
|
|
|
226
|
-
##
|
|
227
|
-
|
|
228
|
-
### 4.1 启用多租户
|
|
107
|
+
## 三、配置
|
|
229
108
|
|
|
230
109
|
```yaml
|
|
231
110
|
# application.yml
|
|
232
111
|
tenant:
|
|
233
|
-
# 是否开启多租户
|
|
234
112
|
enable: true
|
|
235
|
-
#
|
|
236
|
-
|
|
237
|
-
-
|
|
238
|
-
-
|
|
239
|
-
-
|
|
113
|
+
excludes: # 不追加 tenant_id 条件的表
|
|
114
|
+
- sys_menu
|
|
115
|
+
- sys_dict_type
|
|
116
|
+
- sys_dict_data
|
|
117
|
+
- sys_oss_config
|
|
118
|
+
- sys_config
|
|
240
119
|
```
|
|
241
120
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
以下类型的表通常需要排除:
|
|
245
|
-
- **系统配置表**:所有租户共享的配置
|
|
246
|
-
- **字典表**:公共字典数据
|
|
247
|
-
- **地区表**:省市区数据
|
|
248
|
-
- **代码生成表**:gen_table、gen_table_column(框架自动排除)
|
|
249
|
-
|
|
250
|
-
### 4.3 自动配置的组件
|
|
121
|
+
**自动配置组件**(`tenant.enable=true` 时生效):
|
|
251
122
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
|
255
|
-
|
|
256
|
-
|
|
|
257
|
-
|
|
|
258
|
-
| 缓存管理器 | `TenantSpringCacheManager` | Spring Cache 租户隔离 |
|
|
259
|
-
| Sa-Token DAO | `TenantSaTokenDao` | 会话数据租户隔离 |
|
|
123
|
+
| 组件 | 功能 |
|
|
124
|
+
|------|------|
|
|
125
|
+
| `TenantLineInnerInterceptor` | SQL 自动追加租户条件 |
|
|
126
|
+
| `TenantKeyPrefixHandler` | Redis Key 自动添加租户前缀 |
|
|
127
|
+
| `TenantSpringCacheManager` | Spring Cache 租户隔离 |
|
|
128
|
+
| `TenantSaTokenDao` | Sa-Token 会话租户隔离 |
|
|
260
129
|
|
|
261
130
|
---
|
|
262
131
|
|
|
263
|
-
##
|
|
132
|
+
## 四、常见场景
|
|
264
133
|
|
|
265
|
-
###
|
|
134
|
+
### 场景 1:管理员查看所有租户数据
|
|
266
135
|
|
|
267
136
|
```java
|
|
268
|
-
@
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
private final SysUserMapper userMapper;
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* 管理员查看所有租户的用户(需要超级管理员权限)
|
|
276
|
-
*/
|
|
277
|
-
@SaCheckRole("superadmin")
|
|
278
|
-
public List<SysUserVo> listAllTenantUsers() {
|
|
279
|
-
// 忽略租户过滤,查询所有数据
|
|
280
|
-
return TenantHelper.ignore(() -> {
|
|
281
|
-
return userMapper.selectVoList(null);
|
|
282
|
-
});
|
|
283
|
-
}
|
|
137
|
+
@SaCheckRole("superadmin")
|
|
138
|
+
public List<SysUserVo> listAllTenantUsers() {
|
|
139
|
+
return TenantHelper.ignore(() -> userMapper.selectVoList(null));
|
|
284
140
|
}
|
|
285
141
|
```
|
|
286
142
|
|
|
287
|
-
###
|
|
143
|
+
### 场景 2:跨租户数据同步
|
|
288
144
|
|
|
289
145
|
```java
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
// 1. 获取所有租户ID
|
|
301
|
-
List<String> tenantIds = TenantHelper.ignore(() -> {
|
|
302
|
-
return tenantMapper.selectList(null)
|
|
303
|
-
.stream()
|
|
304
|
-
.map(SysTenant::getTenantId)
|
|
305
|
-
.collect(Collectors.toList());
|
|
146
|
+
public void syncConfigToAllTenants(SysConfig config) {
|
|
147
|
+
List<String> tenantIds = TenantHelper.ignore(() ->
|
|
148
|
+
tenantMapper.selectList(null).stream()
|
|
149
|
+
.map(SysTenant::getTenantId).collect(Collectors.toList())
|
|
150
|
+
);
|
|
151
|
+
for (String tenantId : tenantIds) {
|
|
152
|
+
TenantHelper.dynamic(tenantId, () -> {
|
|
153
|
+
SysConfig existing = configMapper.selectByKey(config.getConfigKey());
|
|
154
|
+
if (existing == null) configMapper.insert(config);
|
|
155
|
+
else configMapper.updateById(config);
|
|
306
156
|
});
|
|
307
|
-
|
|
308
|
-
// 2. 逐个租户同步
|
|
309
|
-
for (String tenantId : tenantIds) {
|
|
310
|
-
TenantHelper.dynamic(tenantId, () -> {
|
|
311
|
-
// 检查是否已存在
|
|
312
|
-
SysConfig existing = configMapper.selectByKey(config.getConfigKey());
|
|
313
|
-
if (existing == null) {
|
|
314
|
-
configMapper.insert(config);
|
|
315
|
-
} else {
|
|
316
|
-
configMapper.updateById(config);
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
157
|
}
|
|
321
158
|
}
|
|
322
159
|
```
|
|
323
160
|
|
|
324
|
-
###
|
|
161
|
+
### 场景 3:定时任务处理所有租户
|
|
325
162
|
|
|
326
|
-
|
|
327
|
-
@Service
|
|
328
|
-
@RequiredArgsConstructor
|
|
329
|
-
public class OrderCleanupJob {
|
|
330
|
-
|
|
331
|
-
private final OrderMapper orderMapper;
|
|
332
|
-
private final SysTenantMapper tenantMapper;
|
|
333
|
-
|
|
334
|
-
/**
|
|
335
|
-
* 清理所有租户的过期订单
|
|
336
|
-
*/
|
|
337
|
-
@Scheduled(cron = "0 0 2 * * ?") // 每天凌晨2点
|
|
338
|
-
public void cleanupExpiredOrders() {
|
|
339
|
-
// 1. 获取所有启用的租户
|
|
340
|
-
List<SysTenant> tenants = TenantHelper.ignore(() -> {
|
|
341
|
-
return tenantMapper.selectList(
|
|
342
|
-
Wrappers.<SysTenant>lambdaQuery()
|
|
343
|
-
.eq(SysTenant::getStatus, "0")
|
|
344
|
-
);
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
// 2. 逐个租户处理
|
|
348
|
-
for (SysTenant tenant : tenants) {
|
|
349
|
-
try {
|
|
350
|
-
TenantHelper.dynamic(tenant.getTenantId(), () -> {
|
|
351
|
-
// 删除30天前的已取消订单
|
|
352
|
-
orderMapper.delete(
|
|
353
|
-
Wrappers.<Order>lambdaQuery()
|
|
354
|
-
.eq(Order::getStatus, "CANCELLED")
|
|
355
|
-
.lt(Order::getCreateTime, DateUtils.addDays(new Date(), -30))
|
|
356
|
-
);
|
|
357
|
-
});
|
|
358
|
-
} catch (Exception e) {
|
|
359
|
-
log.error("清理租户 {} 订单失败: {}", tenant.getTenantId(), e.getMessage());
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
### 5.4 场景:统计所有租户数据
|
|
163
|
+
> 详细示例见 `references/tenant-scenarios.md`
|
|
367
164
|
|
|
368
165
|
```java
|
|
369
|
-
@
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
.groupBy("tenant_id")
|
|
385
|
-
).stream().map(map -> {
|
|
386
|
-
TenantOrderStats stats = new TenantOrderStats();
|
|
387
|
-
stats.setTenantId((String) map.get("tenant_id"));
|
|
388
|
-
stats.setOrderCount(((Number) map.get("order_count")).longValue());
|
|
389
|
-
stats.setTotalAmount((BigDecimal) map.get("total_amount"));
|
|
390
|
-
return stats;
|
|
391
|
-
}).collect(Collectors.toList());
|
|
392
|
-
});
|
|
166
|
+
@Scheduled(cron = "0 0 2 * * ?")
|
|
167
|
+
public void cleanupExpiredOrders() {
|
|
168
|
+
List<SysTenant> tenants = TenantHelper.ignore(() ->
|
|
169
|
+
tenantMapper.selectList(Wrappers.<SysTenant>lambdaQuery().eq(SysTenant::getStatus, "0"))
|
|
170
|
+
);
|
|
171
|
+
for (SysTenant tenant : tenants) {
|
|
172
|
+
try {
|
|
173
|
+
TenantHelper.dynamic(tenant.getTenantId(), () -> {
|
|
174
|
+
orderMapper.delete(Wrappers.<Order>lambdaQuery()
|
|
175
|
+
.eq(Order::getStatus, "CANCELLED")
|
|
176
|
+
.lt(Order::getCreateTime, DateUtils.addDays(new Date(), -30)));
|
|
177
|
+
});
|
|
178
|
+
} catch (Exception e) {
|
|
179
|
+
log.error("清理租户 {} 订单失败: {}", tenant.getTenantId(), e.getMessage());
|
|
180
|
+
}
|
|
393
181
|
}
|
|
394
182
|
}
|
|
395
183
|
```
|
|
396
184
|
|
|
397
185
|
---
|
|
398
186
|
|
|
399
|
-
##
|
|
400
|
-
|
|
401
|
-
### 6.1 自动隔离原理
|
|
402
|
-
|
|
403
|
-
框架通过 `TenantKeyPrefixHandler` 自动为 Redis Key 添加租户前缀:
|
|
187
|
+
## 五、Redis 缓存隔离
|
|
404
188
|
|
|
405
189
|
```
|
|
406
190
|
原始 Key: user:info:1001
|
|
@@ -408,9 +192,7 @@ public class StatisticsServiceImpl implements IStatisticsService {
|
|
|
408
192
|
实际 Key: 000001:user:info:1001 (租户 000001)
|
|
409
193
|
```
|
|
410
194
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
使用 `GlobalConstants.GLOBAL_REDIS_KEY` 前缀的 Key 不会添加租户前缀:
|
|
195
|
+
**全局 Key(不隔离)**:使用 `GlobalConstants.GLOBAL_REDIS_KEY` 前缀
|
|
414
196
|
|
|
415
197
|
```java
|
|
416
198
|
import org.dromara.common.core.constant.GlobalConstants;
|
|
@@ -419,185 +201,88 @@ import org.dromara.common.core.constant.GlobalConstants;
|
|
|
419
201
|
String globalKey = GlobalConstants.GLOBAL_REDIS_KEY + "config:site_name";
|
|
420
202
|
RedisUtils.setCacheObject(globalKey, "网站名称");
|
|
421
203
|
|
|
422
|
-
//
|
|
423
|
-
|
|
424
|
-
RedisUtils.setCacheObject(tenantKey, userInfo);
|
|
204
|
+
// 租户隔离缓存(自动添加前缀)
|
|
205
|
+
RedisUtils.setCacheObject("user:info:" + userId, userInfo);
|
|
425
206
|
```
|
|
426
207
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
在 `TenantHelper.ignore()` 中操作的缓存不会添加租户前缀:
|
|
430
|
-
|
|
431
|
-
```java
|
|
432
|
-
TenantHelper.ignore(() -> {
|
|
433
|
-
// 此处的 Redis 操作不添加租户前缀
|
|
434
|
-
RedisUtils.setCacheObject("global:data", data);
|
|
435
|
-
});
|
|
436
|
-
```
|
|
208
|
+
> `TenantHelper.ignore()` 中的 Redis 操作不添加租户前缀。
|
|
437
209
|
|
|
438
210
|
---
|
|
439
211
|
|
|
440
|
-
##
|
|
212
|
+
## 六、常见错误
|
|
441
213
|
|
|
442
|
-
###
|
|
214
|
+
### 1. 忘记继承 TenantEntity
|
|
443
215
|
|
|
444
216
|
```java
|
|
445
|
-
// ❌
|
|
446
|
-
|
|
447
|
-
@EqualsAndHashCode(callSuper = true)
|
|
448
|
-
public class BizOrder extends BaseEntity {
|
|
449
|
-
// 没有 tenantId,数据无法隔离!
|
|
450
|
-
}
|
|
217
|
+
// ❌ 继承 BaseEntity,没有 tenantId
|
|
218
|
+
public class BizOrder extends BaseEntity { }
|
|
451
219
|
|
|
452
|
-
// ✅
|
|
453
|
-
|
|
454
|
-
@EqualsAndHashCode(callSuper = true)
|
|
455
|
-
public class BizOrder extends TenantEntity {
|
|
456
|
-
// 自动包含 tenantId 字段
|
|
457
|
-
}
|
|
220
|
+
// ✅ 继承 TenantEntity
|
|
221
|
+
public class BizOrder extends TenantEntity { }
|
|
458
222
|
```
|
|
459
223
|
|
|
460
|
-
###
|
|
224
|
+
### 2. 数据库表缺少 tenant_id
|
|
461
225
|
|
|
462
226
|
```sql
|
|
463
|
-
-- ❌
|
|
464
|
-
CREATE TABLE biz_order (
|
|
465
|
-
id BIGINT(20) NOT NULL,
|
|
466
|
-
order_no VARCHAR(64)
|
|
467
|
-
);
|
|
227
|
+
-- ❌ 表没有 tenant_id
|
|
228
|
+
CREATE TABLE biz_order (id BIGINT NOT NULL, order_no VARCHAR(64));
|
|
468
229
|
|
|
469
|
-
-- ✅
|
|
470
|
-
CREATE TABLE biz_order (
|
|
471
|
-
id BIGINT(20) NOT NULL,
|
|
472
|
-
tenant_id VARCHAR(20) DEFAULT '000000', -- 必须有
|
|
473
|
-
order_no VARCHAR(64)
|
|
474
|
-
);
|
|
230
|
+
-- ✅ 添加 tenant_id
|
|
231
|
+
CREATE TABLE biz_order (id BIGINT NOT NULL, tenant_id VARCHAR(20) DEFAULT '000000', order_no VARCHAR(64));
|
|
475
232
|
```
|
|
476
233
|
|
|
477
|
-
###
|
|
234
|
+
### 3. setDynamic 后忘记 clearDynamic
|
|
478
235
|
|
|
479
236
|
```java
|
|
480
|
-
// ❌
|
|
237
|
+
// ❌ 租户ID泄漏到其他请求
|
|
481
238
|
TenantHelper.setDynamic("000001");
|
|
482
239
|
userMapper.insert(user);
|
|
483
|
-
// 忘记 clearDynamic()
|
|
240
|
+
// 忘记 clearDynamic()
|
|
484
241
|
|
|
485
|
-
// ✅
|
|
486
|
-
TenantHelper.
|
|
487
|
-
try {
|
|
488
|
-
userMapper.insert(user);
|
|
489
|
-
} finally {
|
|
490
|
-
TenantHelper.clearDynamic();
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
// ✅ 正确方式2:使用 dynamic() 方法(推荐)
|
|
494
|
-
TenantHelper.dynamic("000001", () -> {
|
|
495
|
-
userMapper.insert(user);
|
|
496
|
-
});
|
|
242
|
+
// ✅ 推荐使用 dynamic() 方法(自动清理)
|
|
243
|
+
TenantHelper.dynamic("000001", () -> userMapper.insert(user));
|
|
497
244
|
```
|
|
498
245
|
|
|
499
|
-
###
|
|
246
|
+
### 4. 事务中切换租户
|
|
500
247
|
|
|
501
248
|
```java
|
|
502
|
-
// ❌
|
|
249
|
+
// ❌ 事务内切换租户导致数据错乱
|
|
503
250
|
@Transactional
|
|
504
251
|
public void wrongMethod() {
|
|
505
|
-
orderMapper.insert(order);
|
|
506
|
-
TenantHelper.dynamic("000001", () ->
|
|
507
|
-
logMapper.insert(log); // 使用租户 000001
|
|
508
|
-
});
|
|
509
|
-
// 事务提交时可能出现问题!
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
// ✅ 正确:避免在事务中切换租户,或使用独立事务
|
|
513
|
-
public void correctMethod() {
|
|
514
|
-
// 先处理当前租户
|
|
515
|
-
saveOrder(order);
|
|
516
|
-
|
|
517
|
-
// 再处理其他租户(独立事务)
|
|
518
|
-
saveLogToOtherTenant("000001", log);
|
|
252
|
+
orderMapper.insert(order);
|
|
253
|
+
TenantHelper.dynamic("000001", () -> logMapper.insert(log));
|
|
519
254
|
}
|
|
520
255
|
|
|
256
|
+
// ✅ 使用独立事务
|
|
521
257
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
|
522
258
|
public void saveLogToOtherTenant(String tenantId, Log log) {
|
|
523
|
-
TenantHelper.dynamic(tenantId, () ->
|
|
524
|
-
logMapper.insert(log);
|
|
525
|
-
});
|
|
259
|
+
TenantHelper.dynamic(tenantId, () -> logMapper.insert(log));
|
|
526
260
|
}
|
|
527
261
|
```
|
|
528
262
|
|
|
529
|
-
###
|
|
263
|
+
### 5. 排除表配置不当
|
|
530
264
|
|
|
531
265
|
```yaml
|
|
532
|
-
# ❌
|
|
266
|
+
# ❌ 业务表不应排除
|
|
533
267
|
tenant:
|
|
534
268
|
excludes:
|
|
535
|
-
- biz_order
|
|
269
|
+
- biz_order
|
|
536
270
|
|
|
537
|
-
# ✅
|
|
271
|
+
# ✅ 只排除共享的系统表
|
|
538
272
|
tenant:
|
|
539
273
|
excludes:
|
|
540
|
-
- sys_menu
|
|
541
|
-
- sys_dict_type
|
|
542
|
-
- sys_config # 系统配置(共享)
|
|
543
|
-
```
|
|
544
|
-
|
|
545
|
-
---
|
|
546
|
-
|
|
547
|
-
## 八、API 速查表
|
|
548
|
-
|
|
549
|
-
### TenantHelper 方法
|
|
550
|
-
|
|
551
|
-
| 方法 | 说明 | 返回值 |
|
|
552
|
-
|------|------|--------|
|
|
553
|
-
| `isEnable()` | 租户功能是否启用 | boolean |
|
|
554
|
-
| `getTenantId()` | 获取当前租户ID | String |
|
|
555
|
-
| `ignore(Runnable)` | 忽略租户执行 | void |
|
|
556
|
-
| `ignore(Supplier<T>)` | 忽略租户执行 | T |
|
|
557
|
-
| `dynamic(tenantId, Runnable)` | 动态租户执行 | void |
|
|
558
|
-
| `dynamic(tenantId, Supplier<T>)` | 动态租户执行 | T |
|
|
559
|
-
| `setDynamic(tenantId)` | 设置动态租户 | void |
|
|
560
|
-
| `setDynamic(tenantId, global)` | 设置全局动态租户 | void |
|
|
561
|
-
| `getDynamic()` | 获取动态租户 | String |
|
|
562
|
-
| `clearDynamic()` | 清除动态租户 | void |
|
|
563
|
-
|
|
564
|
-
### Entity 继承
|
|
565
|
-
|
|
566
|
-
| 基类 | 说明 | 包含字段 |
|
|
567
|
-
|------|------|---------|
|
|
568
|
-
| `BaseEntity` | 基础实体 | createDept, createBy, createTime, updateBy, updateTime |
|
|
569
|
-
| `TenantEntity` | 租户实体 | tenantId + BaseEntity 所有字段 |
|
|
570
|
-
|
|
571
|
-
---
|
|
572
|
-
|
|
573
|
-
## 九、配置参考
|
|
574
|
-
|
|
575
|
-
### 完整配置示例
|
|
576
|
-
|
|
577
|
-
```yaml
|
|
578
|
-
# application.yml
|
|
579
|
-
tenant:
|
|
580
|
-
# 是否开启多租户
|
|
581
|
-
enable: true
|
|
582
|
-
# 排除表(不追加租户条件的表)
|
|
583
|
-
excludes:
|
|
584
|
-
- sys_menu # 菜单表
|
|
585
|
-
- sys_dict_type # 字典类型
|
|
586
|
-
- sys_dict_data # 字典数据
|
|
587
|
-
- sys_oss_config # OSS 配置
|
|
588
|
-
- sys_config # 系统配置
|
|
274
|
+
- sys_menu
|
|
275
|
+
- sys_dict_type
|
|
589
276
|
```
|
|
590
277
|
|
|
591
278
|
---
|
|
592
279
|
|
|
593
|
-
##
|
|
280
|
+
## 七、参考代码位置
|
|
594
281
|
|
|
595
282
|
| 类型 | 位置 |
|
|
596
283
|
|------|------|
|
|
597
|
-
| 租户基类 | `ruoyi-common/ruoyi-common-tenant
|
|
598
|
-
| 租户助手 | `ruoyi-common/ruoyi-common-tenant
|
|
599
|
-
| 租户处理器 | `ruoyi-common/ruoyi-common-tenant
|
|
600
|
-
| Redis Key 处理 | `ruoyi-common/ruoyi-common-tenant
|
|
601
|
-
| 租户配置类 | `ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java` |
|
|
602
|
-
| 租户属性 | `ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/properties/TenantProperties.java` |
|
|
284
|
+
| 租户基类 | `ruoyi-common/ruoyi-common-tenant/.../core/TenantEntity.java` |
|
|
285
|
+
| 租户助手 | `ruoyi-common/ruoyi-common-tenant/.../helper/TenantHelper.java` |
|
|
286
|
+
| 租户处理器 | `ruoyi-common/ruoyi-common-tenant/.../handle/PlusTenantLineHandler.java` |
|
|
287
|
+
| Redis Key 处理 | `ruoyi-common/ruoyi-common-tenant/.../handle/TenantKeyPrefixHandler.java` |
|
|
603
288
|
| 配置文件 | `ruoyi-admin/src/main/resources/application.yml` |
|