删除功能(以租户为例)
项目内置功能较多,会存在一些你可能用不到的功能。一般的情况下,建议通过设置该功能对应的菜单为【禁用】,实现功能的“删除”。如下图所示:

后续,如果你又需要使用到该功能,只需要设置该功能对应的菜单为【开启】即可。
🙂 当然,如果你希望彻底删除功能,那么就需要采用删除代码的方式。整个过程如下:
① 【菜单】第一步,使用管理后台的菜单管理,删除对应的菜单、按钮。
② 【数据库表】第二步,删除对应的数据库表。
③ 【后端代码】第三步,删除对应的 Controller、Service、数据库实体等后端代码;然后启动后端项目,若存在代码报错,则继续删除相关联的代码,之后如此反复,直到成功。
④ 【前端代码】第四步,删除对应的 View 和 API 等前端代码;然后启动前端项目,若存在代码报错,则继续删除相关联的代码,之后如此反复,直到成功。
🤖 推荐:借助 AI Agent 来删除功能
随着 AI Agent 的出现,删除功能这种“范围广、易遗漏”的体力活,非常适合交给 AI 来做。目前一般建议使用 Claude Code (opens new window)、Cursor (opens new window) 等 AI 编程工具来辅助生成代码。
推荐的协作方式是:
- 先让 AI 阅读项目,生成一份删除 plan(计划),或者沉淀为一个 skill(技能);
- 由你自己评审确认 plan / skill 是否正确、是否有遗漏或风险(尤其是会删到业务逻辑的地方);
- 确认无误后,再让 AI 按 plan / skill 执行删除,最后人工跑一遍编译与测试验收。
下面是一个使用 Kiro 为本项目生成的「删除多租户」skill 示例,可作为参考(你也可以基于它让 AI 生成其它功能的删除 skill):
点击展开:删除多租户的 skill 示例(SKILL.md)
---
name: delete-tenant
description: 删除 ruoyi-vue-pro(芋道)项目中的「多租户(SaaS Tenant)」功能。当用户希望移除多租户能力、不再需要 SaaS 字段隔离、想精简单租户部署,或提到“删除租户/去掉多租户/tenant 删除”时使用本技能。覆盖菜单、数据库表、后端代码、前端代码的完整删除步骤与验收。
---
# 删除「多租户」功能(以租户为例)
本技能指导如何从 ruoyi-vue-pro(芋道)项目中彻底删除多租户(SaaS Tenant)功能,
参考官方文档「删除功能(以租户为例)」https://doc.iocoder.cn/delete-code/ 的五步法,
并结合本仓库的真实结构做了落地说明。
> 重要:删除多租户是不可逆的破坏性操作,会影响数据库表、后端框架装配与前端页面。
> 执行前务必:
> 1. 在新分支上操作,先 `git status` 确认工作区干净;
> 2. 备份数据库(尤其是 `system_tenant`、`system_tenant_package` 及各业务表的 `tenant_id` 字段);
> 3. 与团队确认确实不再需要 SaaS 多租户隔离。
>
> 如果你只是想“临时关闭”多租户,不要删除代码,直接在 `yudao-server/src/main/resources/application.yaml`
> 中设置 `yudao.tenant.enable: false` 即可(见文末「替代方案」)。
整体顺序:**菜单 → 数据库表 → 后端代码 → 前端代码 → 测试验收**。
---
## 第一步:删除菜单
删除菜单是为了让前端不再显示「租户管理」「租户套餐」等入口。
涉及的菜单(`system_menu` 表,MySQL 种子数据见 `sql/mysql/ruoyi-vue-pro.sql`):
| 菜单 ID | 名称 | 权限标识 |
| --- | --- | --- |
| 1224 | 租户管理(目录) | - |
| 1138 | 租户列表 | - |
| 1139 | 租户查询 | system:tenant:query |
| 1140 | 租户创建 | system:tenant:create |
| 1141 | 租户更新 | system:tenant:update |
| 1142 | 租户删除 | system:tenant:delete |
| 1143 | 租户导出 | system:tenant:export |
| 1225 | 租户套餐 | - |
| 1226 | 租户套餐查询 | system:tenant-package:query |
| 1227 | 租户套餐创建 | system:tenant-package:create |
| 1228 | 租户套餐更新 | system:tenant-package:update |
| 1229 | 租户套餐删除 | system:tenant-package:delete |
| 5010 | 租户切换 | - |
操作方式(二选一):
- 推荐:在管理后台「系统管理 → 菜单管理」中,删除「租户管理」目录及其子菜单。
- 或直接在数据库执行(请同时同步 `sql/` 下你所用数据库方言的种子文件,避免重新初始化时菜单复活):
```sql
-- 删除运行库中的菜单(按需替换表前缀)
DELETE FROM system_menu WHERE id IN (1224, 1138, 1139, 1140, 1141, 1142, 1143, 1225, 1226, 1227, 1228, 1229, 5010);
-- 清理角色与菜单的关联
DELETE FROM system_role_menu WHERE menu_id IN (1224, 1138, 1139, 1140, 1141, 1142, 1143, 1225, 1226, 1227, 1228, 1229, 5010);
```
> 注意:`system_tenant_package` 的 `menu_ids` 字段中也会引用这些菜单 ID,删除套餐表后此引用自然失效,无需单独处理。
---
## 第二步:删除数据库表
删除租户相关的数据库表,并去除业务表中的多租户字段。
### 2.1 删除租户专属表
```sql
DROP TABLE IF EXISTS system_tenant;
DROP TABLE IF EXISTS system_tenant_package;
```
### 2.2 处理业务表的 tenant_id 字段(关键且影响最大)
多租户采用「字段隔离」:几乎所有业务表都带有 `tenant_id` 字段,由
`TenantDatabaseInterceptor` 自动拼接 `WHERE tenant_id = ?`。删除多租户后:
- 若**保留** `tenant_id` 字段:最省事,字段闲置不影响使用,推荐保留。
- 若**彻底删除** `tenant_id` 字段:需要对每张含该字段的表执行
`ALTER TABLE xxx DROP COLUMN tenant_id;`。这一步范围极广、风险高,
仅在确有必要时进行,且务必先备份。
> 建议:第一次删除多租户时**保留** `tenant_id` 字段,只删租户表 + 关闭框架逻辑。
> 这样最小化风险,后续确认无误再考虑清字段。
同步更新 `sql/` 目录下你所使用数据库方言的初始化脚本,移除 `system_tenant`、
`system_tenant_package` 两张表的建表与 INSERT 语句(涉及文件示例:
`sql/mysql/ruoyi-vue-pro.sql`、`sql/postgresql/ruoyi-vue-pro.sql`、
`sql/dm/ruoyi-vue-pro-dm8.sql`、`sql/kingbase/ruoyi-vue-pro.sql`、
`sql/opengauss/ruoyi-vue-pro.sql` 等)。
---
## 第三步:删除后端代码
后端分两部分:① 删除 `yudao-module-system` 中租户的业务代码;② 移除 `yudao-framework`
中的多租户框架 starter 及各模块对它的依赖。
### 3.1 删除 system 模块的租户业务代码
删除以下文件 / 目录(路径基于 `yudao-module-system/src/main/java/cn/iocoder/yudao/module/system`):
- `controller/admin/tenant/`(`TenantController`、`TenantPackageController` 及其 `vo/`)
- `controller/app/tenant/`(`AppTenantController` 及其 `vo/`)
- `service/tenant/`(`TenantService`、`TenantServiceImpl`、`TenantPackageService`、
`TenantPackageServiceImpl`、`handler/TenantInfoHandler`、`handler/TenantMenuHandler`)
- `dal/dataobject/tenant/`(`TenantDO`、`TenantPackageDO`)
- `dal/mysql/tenant/`(`TenantMapper`、`TenantPackageMapper`)
- `convert/tenant/`(`TenantConvert`)
- `api/tenant/`(`TenantApiImpl`)
对应测试代码:`yudao-module-system/src/test/java/cn/iocoder/yudao/module/system/service/tenant/`。
同时删除 `framework` 中对外暴露的租户 API 接口:
- `yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/biz/system/tenant/TenantCommonApi.java`
> 删除后用全局搜索处理编译错误,重点检查对 `TenantApiImpl`、`TenantCommonApi`、
> `TenantService`、`TenantDO` 的引用,逐一移除或改写。
### 3.2 删除多租户框架 starter
删除整个模块目录:
- `yudao-framework/yudao-spring-boot-starter-biz-tenant/`
并从 `yudao-framework/pom.xml` 的 `<modules>` 中移除:
```xml
<module>yudao-spring-boot-starter-biz-tenant</module>
```
从 `yudao-dependencies/pom.xml` 中移除 `yudao-spring-boot-starter-biz-tenant` 的
`<dependencyManagement>` 声明。
### 3.3 移除各模块对租户 starter 的依赖
以下 `pom.xml` 都依赖了 `yudao-spring-boot-starter-biz-tenant`,逐个删除该 `<dependency>` 块:
- `yudao-module-system/pom.xml`
- `yudao-module-infra/pom.xml`
- `yudao-module-bpm/pom.xml`
- `yudao-module-crm/pom.xml`
- `yudao-module-pay/pom.xml`
- `yudao-module-member/pom.xml`
- `yudao-module-mp/pom.xml`
- `yudao-module-ai/pom.xml`
- `yudao-module-report/pom.xml`
- `yudao-module-iot/yudao-module-iot-biz/pom.xml`
- `yudao-module-mall/yudao-module-promotion/pom.xml`
- `yudao-module-mall/yudao-module-statistics/pom.xml`
- `yudao-module-mall/yudao-module-trade/pom.xml`
- `yudao-framework/yudao-spring-boot-starter-websocket/pom.xml`(`scope` 为 `provided`)
> 用 `grep -r "yudao-spring-boot-starter-biz-tenant" --include=pom.xml .` 复核,确保无遗漏。
### 3.4 清理框架特性的代码引用
删除 starter 后,全项目对以下类型的引用都会编译失败,需要逐处清理:
- `TenantContextHolder`(获取/设置当前租户)
- `TenantUtils.execute(...)` / `TenantUtils.executeIgnore(...)`(在指定/忽略租户上下文执行逻辑)
- `TenantUtils.addTenantHeader(...)`(RPC/HTTP 调用时注入 `tenant-id` 请求头)
- `@TenantIgnore`(忽略租户拦截的注解,类级/方法级/Mapper 方法级)
- `@TenantJob`(标记定时任务遍历所有租户执行)
- `TenantBaseDO`
#### ⚠️ 关键:`TenantUtils` 的删除——什么时候要保留里面的代码
`TenantUtils.execute(tenantId, () -> {...})`、`TenantUtils.executeIgnore(() -> {...})`
的参数是一个 `Runnable` / `Callable` **lambda,业务逻辑就写在 lambda 体里面**。
这类调用**绝对不能整段删掉**,否则会把真正的业务逻辑一起删除。正确做法是
**“拆壳保芯”:去掉 `TenantUtils.xxx(...)` 这层包装,保留 lambda 内部的代码**。
它的本质只是“临时切换/忽略租户上下文执行一段逻辑”。删除多租户后,这层上下文切换
不再需要,但里面的业务逻辑必须原样保留。
改写规则:
1. **`Runnable` 形式(无返回值)**——展开 lambda 体:
```java
// 删除前
TenantUtils.execute(tenant.getId(), () -> {
Long roleId = createRole(tenantPackage);
createUser(roleId, createReqVO);
});
// 删除后(去掉包装,保留内部逻辑)
Long roleId = createRole(tenantPackage);
createUser(roleId, createReqVO);
```
2. **`Callable` 形式(有返回值)**——把 lambda 里的 `return` 提到外层:
```java
// 删除前
TenantUtils.execute(refreshTokenDO.getTenantId(),
() -> accessTokenDO.setUserInfo(buildUserInfo(userId, userType)));
// 删除后
accessTokenDO.setUserInfo(buildUserInfo(userId, userType));
```
若内部依赖 `tenantId` 变量(如把它写入 DO),删除后该字段可直接去掉或保留默认值。
3. **`executeIgnore(...)`** 同理:它只是“忽略租户隔离执行一段查询/写入”,删除多租户后
隔离本就不存在,直接保留内部逻辑即可。
4. **`addTenantHeader(headers, tenantId)`**——这是给 RPC/HTTP 请求注入 `tenant-id` 头,
可整行删除(不含业务逻辑)。
> 排查方式:`grep -rn "TenantUtils" --include=*.java .` 逐处确认是 `execute/executeIgnore`
> (需拆壳保留内部逻辑)还是 `addTenantHeader`(可整行删除)。
#### `@TenantIgnore`
被很多 system 模块的 DO / Mapper 使用(如 `MenuDO`、`DictDataDO`、`DictTypeDO`、
`OAuth2ClientDO`、`SmsTemplateDO`、`MailTemplateDO`、`NotifyTemplateDO`,以及
`OAuth2AccessTokenMapper`、`OAuth2RefreshTokenMapper` 的方法级注解等)。
**只删注解本身,DO / Mapper 方法及其逻辑全部保留。**
#### `@TenantJob`
原本带该注解的 Job 会遍历所有租户各执行一次,删除注解后改为普通执行一次。
**只删注解,`execute(...)` 方法体保留。** 参考 `yudao-module-system/.../job/DemoJob.java`
及各模块定时任务。注意方法体里若用到 `TenantContextHolder.getTenantId()` 之类(如 DemoJob
的打印),需一并清理这些引用,但其余业务逻辑保留。
#### `TenantContextHolder`
读取/设置当前租户上下文的工具。删除多租户后相关读写都失去意义:
- 取值后仅用于赋给 `tenantId` 字段/变量的,连同该字段处理一起去掉;
- 取值后参与业务判断的(少见),需结合上下文改写为单租户语义,**不要盲删导致逻辑缺失**。
> 总原则:**框架包装(上下文切换、忽略隔离、注解、请求头注入)删掉,被包装的业务逻辑保留。**
### 3.5 清理配置
从 `yudao-server/src/main/resources/application.yaml` 中删除 `yudao.tenant` 整段配置:
```yaml
tenant: # 多租户相关配置项
enable: true
ignore-urls: ...
ignore-visit-urls: ...
ignore-tables: ...
ignore-caches: ...
```
同时检查多环境配置文件(`application-local.yaml`、`application-dev.yaml` 等)是否有同名片段。
---
## 第四步:删除前端代码
> 注意:本仓库的 `yudao-ui/yudao-ui-admin-vue3` 已被精简,租户相关前端文件可能不存在。
> 以下为标准前端(Vue3 / Vben / Vue2)中租户文件的常规位置,按你实际使用的前端工程处理。
Vue3(`yudao-ui-admin-vue3`):
- 删除视图目录:`src/views/system/tenant/`、`src/views/system/tenantPackage/`
- 删除 API:`src/api/system/tenant/`、`src/api/system/tenantPackage/`
- 删除登录页/请求中携带 `tenant-id`、租户切换相关逻辑(搜索 `tenant`、`tenantId`、
`tenant-id`、`getTenantId`、`useTenantStore` 等关键字)
- 检查 `src/utils/request`、登录逻辑、`store` 中与租户相关的拦截/缓存
Vben(`yudao-ui-admin-vben`)、Vue2(`yudao-ui-admin-vue2`)类似:搜索 `tenant` 关键字,
删除对应 `views`、`api`、请求头注入与租户选择组件。
---
## 第五步:测试验收
1. 后端编译:在仓库根目录执行
```bash
mvn -q -T 1C clean install -DskipTests
```
确保无编译错误(重点是 `TenantXxx`、`@TenantIgnore`、`@TenantJob` 的残留引用)。
2. 启动 `yudao-server`,确认应用正常启动,无 `YudaoTenantAutoConfiguration` 相关报错。
3. 验证核心接口:登录、获取菜单、用户列表等可正常访问(不再要求携带 `tenant-id` 请求头)。
4. 前端启动后,确认菜单中无「租户管理 / 租户套餐」,相关页面与请求无报错。
5. 跑一遍关键单元测试(如保留测试框架)。
6. 全局复核:
```bash
grep -rn "tenant" --include=*.java yudao-module-system yudao-framework | grep -iv "//"
grep -rn "yudao-spring-boot-starter-biz-tenant" --include=pom.xml .
```
---
## 替代方案:只关闭不删除
如果目标只是「单租户运行」,强烈建议不要删代码,改为关闭开关:
```yaml
# yudao-server/src/main/resources/application.yaml
yudao:
tenant:
enable: false
```
`YudaoTenantAutoConfiguration` 上的 `@ConditionalOnProperty(prefix = "yudao.tenant", value = "enable")`
会在 `enable=false` 时整体不装配多租户的 AOP / 拦截器 / 过滤器 / MQ / 缓存逻辑,
既保留了代码可回退性,又达到关闭多租户的效果。
提醒:AI 生成的删除方案不一定 100% 准确,务必人工评审。尤其要注意
TenantUtils这类“包装类”——只删外层包装,里面的业务逻辑必须保留(详见下文第三步第 ⑨ 点)。
下面,我们来举一些例子。
# 👍 相关视频教程
# 删除「多租户」功能
- 对应功能的文档:多租户
- 对应的关键字是
tenant
# 第一步,删除菜单
删除“租户管理“下的所有菜单,从最里层的按钮开始。如下图所示:

# 第二步,删除数据库表
删除 system_tenant 和 system_tenant_package 表。如下图所示:

# 第三步,删除后端代码
① 删除 yudao-module-system-api 模块的 api/tenant (opens new window) 包。
② 删除 yudao-module-system-api 模块的 ErrorCodeConstants (opens new window) 类中,和租户、租户套餐相关的错误码。如下图所示:

如果想删除的更干净,可以把 system_error_code 表中,对应编号的错误码也都删除一下。
③ 删除 yudao-module-system 模块的如下包:
api/tenant(opens new window)controller/admin/tenant(opens new window)service/tenant(opens new window)test/service/tenant(opens new window)dal/dataobject/tenant(opens new window)dal/mysql/tenant(opens new window)convert/tenant(opens new window)
④ 删除 yudao-spring-boot-starter-biz-tenant (opens new window) 模块。
然后,使用 IDEA 搜索 yudao-spring-boot-starter-biz-tenant 关键字,删除 Maven 中所有对它的定义与引用。如下图所示:

之后,使用 IDEA 刷新下 Maven 依赖。如下图所示:

⑤ 运行 YudaoServerApplication 启动类,会报 cn.iocoder.yudao.framework.tenant.core.db 不存在的错误,需要将继承 TenantBaseDO 的数据库实体,都改成继承 BaseDO 基类。

⑥ 运行 YudaoServerApplication 启动类,会报 cn.iocoder.yudao.framework.tenant.core.aop 不存在的错误,需要去除对 @TenantIgnore 注解的使用。如下图所示:

⑦ 运行 YudaoServerApplication 启动类,会报 cn.iocoder.yudao.module.system.service.tenant 不存在的错误,需要去除对 TenantService 的使用。如下图所示:

⑧ 运行 YudaoServerApplication 启动类,会报 cn.iocoder.yudao.framework.tenant.core.context 不存在的错误,需要去除对 TenantContextHolder 的使用。如下图所示:

⑨ 删除使用 TenantUtils 调用的地方,只删除 TenantUtils 外层,里面的逻辑需要保留!!!
⑩ 运行 YudaoServerApplication 启动类,终于成功了!!!
ps:可以将 application.yaml 配置文件中,对应的 yudao.tenant 配置项给进一步删除。
# 第四步,删除前端代码
以 yudao-admin-ui 为示例~
① 删除 View 和 API 的前端代码:
views/system/tenant(opens new window)views/system/tenantPackage(opens new window)api/system/tenant.js(opens new window)api/system/tenantPackage.js(opens new window)
② 在 yudao-admin-ui 目录下,执行 npm run local 成功。访问登录页,结果访问白屏。需要清理 login.vue 页,涉及 tenant 关键字的代码。例如说:

刷新,成功访问登录界面。
③ 在 yudao-admin-ui 目录下,搜索 tenant 或 Tenant 关键字,可进一步清理多租户的代码。例如说:

# 第五步,测试验收
至此,我们已经完成了多租户的代码删除,还是蛮艰辛的~
后续,你可以简单测试一下,看看是不是删除代码,导致一些小问题。
# 更多...
如果你有其它功能想要删除,可以在 Issue (opens new window) 留言,可以不断补充到该文档。