am_demo 全流程走读
2026/10/26大约 3 分钟
am_demo 全流程走读
官方示例插件 am-serve/plugin/am_demo/ 是脚手架产出的标准形态,逐文件走一遍就能看懂"一个完整插件由哪些零件组成"。
目录一览
plugin/am_demo/
├── manifest.json # 清单
├── Plugin.php # 生命周期 Hook(继承 BasePlugin)
├── install.sql # 首次安装 SQL(建表 + 顶级入口菜单)
├── config/
│ ├── app.php / view.php / static.php / route.php
├── app/
│ ├── controller/AppController.php # 双入口 + 公开接口
│ ├── controller/TestController.php
│ └── view/app/index.html、manage.html # 前台/管理入口视图
└── public/
├── logo.png
├── assets/ # 前端构建产物落位处
└── widget/AppWidget.vue # 可被基座远程加载的小部件manifest.json
{
"name": "am_demo", "title": "插件示例",
"version": "1.0.0", "support_version": "1.0.1",
"icon": "/app/am_demo/logo.png",
"type": 1, "open_mode": "micro",
"entry": "/app/am_demo", "manage_entry": "/app/am_demo/manage",
"path": "plugin/am_demo", "view_root": "view",
"is_dev": 1,
"composer": { "require": { "voku/stop-words": "^2.0", "doctrine/inflector": "^2.0" } },
"hook": "plugin\\am_demo\\Plugin"
}support_version决定与当前基座的兼容性判定,字段语义见清单 manifest。composer.require演示插件自带 Composer 依赖:安装时基座按此装包、卸载时清理(composer_enabled开关)。
双入口控制器 AppController.php
#[RouteGroup('/app/am_demo')]
class AppController
{
protected array $noNeedLogin = ['index', 'manage', 'info', 'publicPosts', 'publicDetail'];
public function index(): Response { return view('app/index', ['title' => '插件示例']); } // 前台入口
public function manage(): Response { return view('app/manage', ['title' => '插件示例']); } // 管理入口
#[Get('/public/posts')] // GET /app/am_demo/public/posts:前台公开,白名单内,无登录态也拉得到数据
public function publicPosts(): Response { /* ... */ }
#[Get('/info')] // GET /app/am_demo/info:本例也放白名单,返回插件基本信息
public function info(): Response { /* ... */ }
}要点:
- 类级
RouteGroup定前缀、方法级Get/Post定子路径,前缀自动拼接——新增接口不用重写前缀。 - 页面入口
index/manage在config/route.php手动注册(无尾斜杠),业务接口不在此注册。 publicPosts演示"前台入口只调白名单接口",浏览器直访/app/am_demo无需登录即可渲染。鉴权三姿势详见控制器与路由。
config/route.php
Route::get('/app/am_demo', [AppController::class, 'index']);
Route::get('/app/am_demo/manage', [AppController::class, 'manage']);只注册两个无尾斜杠页面入口,其余走注解。
Plugin.php
class Plugin extends BasePlugin
{
public function boot(array $plugin = []): void { /* 每进程装配:注册 provider/事件等 */ }
public function backupTables(array $plugin = []): array { return []; } // 声明纳入备份的业务表(须 am_demo_ 前缀)
}boot() 是唯一每 worker 进程重复执行的钩子,静态注册都写这里。钩子全貌见生命周期。
install.sql
首次安装执行。示例内置了"管理入口"顶级菜单的幂等 INSERT:
INSERT INTO `__PREFIX__system_menu` (...)
SELECT 0, '{{APP_NAME}}', 'app:entry:{{APP_NAME}}', '{{APP_NAME}}', 2,
'/plugin-app/{{APP_NAME}}', 'plugin/app', '', 100, ...
WHERE NOT EXISTS (SELECT 1 FROM `__PREFIX__system_menu` m WHERE m.`code` = 'app:entry:{{APP_NAME}}');__PREFIX__是表前缀占位符;{{APP_NAME}}是安装期占位符,由DatabaseService::executeInstallSql替换成插件标识。- 入口菜单
code用保留前缀app:entry:{name}、path指向宿主路由/plugin-app/{name}(不含记录 id,可随备份迁移)。 - 建业务表时表名须以
am_demo_前缀。菜单/入口/纯插件规则见双入口、安装升级。
public/widget/AppWidget.vue
一个小部件示例,基座可用远程小部件机制按 /app/am_demo/widget/AppWidget.vue 加载它。
从装配到打开
- 基座后台「创建自定义插件」生成后端骨架(本例的 manifest/控制器/视图/install.sql 即其产物);
- Vue3 形态:
node am_frontends/create-plugin.mjs am_demo装配前端 →pnpm build回写public/assets与双视图(见Vue3 脚手架); - 扫描 → 安装 → 启用;
- 后台点入口菜单经 qiankun 免登打开管理入口;前台直访
/app/am_demo。
