插件开发
一个应用由什么组成
<你的应用>/
├── app.json 清单:编码、版本、产物路径、菜单树
├── pom.xml 后端工程(不在平台 reactor 里)
├── migrations/ 数据库脚本(随包走,安装时自动执行)
│ ├── 01-create-xxx-tables.sql
│ └── 0N-create-xxx-seed-data.sql
└── src/main/java/... controller / service.impl / listener前端在另一个仓库:
plus-ui/app-market-poc/<code>-app/
├── vite.config.ts 唯一的工程配置文件
└── src/
├── index.ts 入口契约:导出 install(runtime)
└── views/ 页面对应的契约模块在平台里:
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-<name>-api/
├── src/main/java/.../domain/ 实体、BO、VO
│ ├── mapper/ Mapper 接口
│ └── service/ Service 接口
└── src/main/resources/mapper/ ★ Mapper XML 也在这里五个必须记住的约定
1. 契约与实现分家
- 实体 / BO / VO / Mapper 接口 与 Mapper XML / Service 接口 →
*-api(在 reactor 内) - controller / service.impl / listener →
plugins/ruoyi-<name>(不在任何<modules>里)
Mapper XML 放在 *-api 这条尤其重要:宿主的 mapperLocations 是用宿主类加载器扫描的, XML 留在插件 jar 里就永远扫不到 → 所有 SQL 静默失效。
2. 平台依赖一律 provided
xml
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-core</artifactId>
<scope>provided</scope>
</dependency>这些类由宿主类加载器提供。打进插件就会出现"同一个接口两个 Class 对象", 注入与类型判断全部失效。
3. 菜单只能通过清单声明
不要手写 INSERT INTO sys_menu。菜单走 app.json 的 menus,安装/升级时由平台 幂等 upsert,按 menu_key 复用既有 menu_id —— 这样租户已分配的权限不会失效。
type: "F" 的按钮也必须写进清单,否则全新部署装完没有按钮、 "彻底删除"时也删不掉它们。
4. 表结构随包走
不要手写 SQL、也不要让插件代码自己建表。把脚本放进 migrations/, 打包时自动进包,安装/升级时按文件名排序执行。
5. 平台依赖只能从父上下文取
插件能注入宿主,宿主不能注入插件。宿主侧要拿插件服务,走服务定位器代理。
不要在宿主上下文里注册与插件实现同类型的 bean(哪怕是个转发代理)—— 那会让插件的控制器启动时报 expected single matching bean but found 2。
快速导航
| 我想… | 看这里 |
|---|---|
搞清 app.json 每个字段 | 应用清单 app.json |
| 写后端工程 | 后端工程 |
| 写前端远程应用 | 前端远程应用 |
| 声明菜单与权限 | 菜单与权限 |
| 加表 / 改表 | 数据库迁移 |
| 让应用装完就有字典和配置 | 种子数据与站点配置 |
| 本地调试 | 本地联调 |
| 把一个宿主模块抽成应用 | 抽取 SOP |
| 改平台代码(贡献者) | 开发指南 / 必须遵守的不变量 |
从零做一个应用:最小步骤
powershell
# 1) 建契约模块 ruoyi-modules/ruoyi-<name>-api(进 reactor)
# 放 domain / mapper 接口 + XML / service 接口
# 2) 建实现工程 plugins/ruoyi-<name>(不进任何 <modules>)
# pom 的 parent 用 <relativePath>../../pom.xml</relativePath>
# 平台依赖全部 provided
# 3) 写 app.json(菜单树含 F 按钮)
# 4) 写建表脚本
# plugins/ruoyi-<name>/migrations/01-create-<name>-tables.sql
# 从库里 SHOW CREATE TABLE 导出 → 改成 CREATE TABLE IF NOT EXISTS
# 5) 建前端工程
# plus-ui/app-market-poc/<code>-app/
# vite.config.ts 抄 gallery 的,按实际用到裁剪白名单
# src/index.ts 默认导出 install(runtime)
# 6) 第一次用:生成签名密钥
powershell -NoProfile -ExecutionPolicy Bypass -File plugins\package.ps1 -Keygen
# 7) 打包 + 签名(脚本会自己构建前后端)
powershell -NoProfile -ExecutionPolicy Bypass -File plugins\package.ps1 `
-Plugin ruoyi-<name> -SigningKey plugins\keys\private.pem
# 8) 上架:安装包上传 → 保存版本 → 发布 → 上架 → 部署完整细节见各分节。
与宿主模块抽取的区别
如果你不是从零写,而是把宿主里已有的业务模块抽出来变成应用, 步骤不同(多了"改宿主消费方"与"存量迁移 SQL"两步):
进度:quote / enterprise / member / pay / exam / im / social / mall —— 八个已完成。
相关阅读
- 必须遵守的不变量 —— 改代码前扫一遍
- 应用清单 app.json
- 后端工程
- 前端远程应用