示例应用
hello 是平台唯一的示例应用,在 wujies/wujies-plugins/wujies-hello/。
它的用途不是提供业务功能,而是一次安装就看完整条链路:
后端接口、开放接口、定时任务、跨应用依赖、前端远程产物、共享 Vue / Element Plus 单例。
早期的示例是一个纯前端远程应用
demo-app。它已经从应用目录里去掉 —— 生成器(deploy/tools/gen-app-catalog-sql.mjs的EXCLUDED_APPS)不再分发它, 存量部署跑script/sql/update/app_market_demo_app_remove.sql清理, 示例应用的位置由hello独占。
它为什么存在
在把真实业务模块抽成插件之前,先用最小的一份产物验证:
@RestController路由是否被注册(PluginHandlerMapping);- Mapper 能否从插件里加载(含无 XML、只用内置方法的 Mapper);
@Scheduled与 SnailJob 两类定时任务是否注册;- 前端远程产物能不能被运行期
import()起来; - 共享依赖(Vue / Element Plus)是不是同一份实例;
- 应用之间的依赖怎么声明、没装时怎么被拦住。
仓库里还有两个同类的对照物:后端探针模块(不得被启动模块依赖)与图床、财务等真实应用。
hello 与它们的分工见 跟着 hello 读源码。
它长什么样
wujies/wujies-plugins/
├── wujies-hello/ 后端插件(自包含:实体 / Mapper / Service 都在这里)
│ ├── app.json ★ 清单:唯一真相来源(编码 / 菜单树 / 产物路径 / dependencies)
│ ├── pom.xml 平台依赖一律 provided
│ ├── migrations/ 建表 + 种子数据 + 站点配置,随包执行
│ └── src/main/java/cn/wujies/hello/
│ ├── controller/ 探针、宿主调用、跨插件调用(import 了 member)
│ ├── open/ /open 开放接口
│ └── task/ @Scheduled 与 SnailJob 两种定时任务
└── frontend/hello-app/ 前端工程(与插件模块只差一个 `-app` 后缀)
├── app.json 清单的近重复副本:改清单时**两份一起改**
├── vite.config.ts defineRemoteApp({ appCode: 'hello' })
└── src/
├── index.ts install(runtime) + 视图键
├── runtime.ts 宿主运行时持有者
└── views/ DemoHome / DemoPluginDev / DemoAbout四个可以对照学习的点
1. 它是"全栈"形态的样本
清单里 assets 同时写了 backend 与 frontend:
"assets": {
"backend": "backend/wujies-hello-plugin-1.0.0.jar",
"frontend": "frontend/index.js"
}⚠️ 两条路径都是包内相对路径,前端那条必须带 frontend/ 前缀。
写成裸文件名(index.js)不会报错,但落位时整棵前端树都不会被释放
(后端 jar 照常落位,所以任务仍然"成功"),表现为菜单点开是"远程视图不可用"。
2. 视图键用 demo/ 前缀是刻意的
app.json 里三个页面菜单的 component 是 remote:hello/demo/home、
remote:hello/demo/plugin-dev、remote:hello/demo/about,
前端 src/index.ts 的 views 键就是 demo/home / demo/plugin-dev / demo/about。
demo 在这里只是视图键的命名空间(不是应用编码),与已去掉的 demo-app 无关。
前缀本身可以随便取,唯一硬要求是:remote:<appCode>/<视图键> 里的
<appCode> 必须等于清单 code、<视图键> 必须在前端真实注册过 ——
不一致就是悬空菜单,而且由清单声明,全新安装也会照建。
3. 它是声明了 dependencies 的样本
hello 的代码 import 了 member 的 IMemberService / MemberMapper,
所以清单必须声明:
"dependencies": [
{ "code": "member" }
]字段自洽性由打包/安装两道闸兜底:没装或没启用 member 时,安装与升级会被拦住并明确告诉你缺谁,
而不是等运行期抛 No qualifying bean。装机顺序因此是硬约束:被依赖的先装。
4. 「示例应用可以删除」
上架端对删除有白名单保护(后端的 AppConsoleController.DELETABLE_APP_CODES):
只有白名单里的编码能删,内置模块与已上架应用一律拒绝。
这是刻意的:真实应用删掉之后恢复成本很高,而示例应用本来就该能清掉。
自己写一个最小应用
想从零验证一遍链路,见 插件开发,特别是: