# 3.6 控制器开发 :::tip 概述 控制器是 HTTP 请求的入口,负责参数获取、调用 Logic 层、返回 JSON 响应。通过 `#[Permission]` 和 `#[Log]` 注解实现权限校验和操作日志。 ::: ## 控制器文件位置 ```text app/controller/ExampleController.php ``` ## 完整代码(来自项目实际代码) ```php logic = new ExampleLogic(); } // ... 以下为各接口方法 } ``` :::tip 控制器模式 每个控制器遵循固定模式: 1. `initialize()` 中实例化 Logic 2. 每个方法标注 `#[Log]` 和 `#[Permission]` 注解 3. 简单调用 `parent::_index()` / `_detail()` / `_add()` 等通用方法 4. 复杂操作(如导入导出)自行处理并 try-catch ::: ```php /** * 案例演示分页列表 * * GET /example/page * 对应权限:sys:example:page * * 调用 BaseController::_index(),内部流程: * 1. 合并分页参数(pageNo/pageSize)和普通参数 * 2. 调用 ExampleLogic::pageList() * 3. 返回标准分页响应 * * @return Json */ #[Log('案例演示-查询分页记录', Log::TYPE_QUERY)] #[Permission('sys:example:page', '案例演示分页')] public function page(): Json { return parent::_index($this->logic); } /** * 案例演示列表 * * GET /example/list * 返回全量数据(不分页),适用于下拉选择等场景。 * * @return Json */ #[Log('案例演示-查询列表', Log::TYPE_QUERY)] public function list(): Json { return parent::_list($this->logic); } /** * 案例演示详情 * * GET /example/detail/{id} * * 调用 BaseController::_detail(),内部流程: * 1. 调用 ExampleLogic::detail($id) * 2. 查询为空返回 404 * 3. 自动补全文件字段域名、枚举显示名 * 4. 触发 afterDetail 钩子 * * @param int $id 案例演示ID * @return Json */ #[Log('案例演示-查询详情', Log::TYPE_QUERY, '查询案例演示ID:{id}')] public function detail(int $id): Json { return parent::_detail($this->logic, $id); } /** * 添加案例演示 * * POST /example/add * 对应权限:sys:example:add * * 调用 BaseController::_add(),内部流程: * 1. 调用 ExampleLogic::add($data) * 2. 触发 beforeAdd/afterAdd 钩子 * 3. 返回新记录 ID * * @return Json */ #[Log('案例演示-新增记录', Log::TYPE_ADD, '新增案例演示:{name}')] #[Permission('sys:example:add', '添加案例演示')] public function add(): Json { // getJsonBody() 获取前端 POST 提交的 JSON 数据 return parent::_add($this->logic, $this->getJsonBody()); } /** * 更新案例演示 * * PUT /example/update * 对应权限:sys:example:update * * 从 JSON 请求体中读取 id,若缺失则直接返回失败。 * * @return Json */ #[Log('案例演示-修改记录', Log::TYPE_UPDATE, '修改案例演示ID:{id}')] #[Permission('sys:example:update', '修改案例演示')] public function update(): Json { $data = $this->getJsonBody(); $id = $data['id'] ?? 0; // 校验 ID 参数 if (empty($id)) { return $this->fail('缺少id参数'); } return parent::_edit($this->logic, $id, $data); } /** * 删除案例演示 * * DELETE /example/delete/{id} * 对应权限:sys:example:delete * * 调用 BaseController::_remove(),内部流程: * 1. 调用 ExampleLogic::delete($id) * 2. 触发 beforeDelete/afterDelete 钩子 * 3. 设置 is_delete=1(软删除) * * @param int $id 案例演示ID * @return Json */ #[Log('案例演示-删除记录', Log::TYPE_DELETE, '删除案例演示ID:{id}')] #[Permission('sys:example:delete', '删除案例演示')] public function delete(int $id): Json { return parent::_remove($this->logic, $id); } /** * 批量删除案例演示 * * DELETE /example/batchDelete * 对应权限:sys:example:delete * * 从 JSON 请求体中读取 ids 数组。 * * @return Json */ #[Log('案例演示-批量删除记录', Log::TYPE_DELETE)] #[Permission('sys:example:delete', '删除案例演示')] public function batchDelete(): Json { $ids = $this->getJsonBody()['ids'] ?? []; return parent::_batchRemove($this->logic, $ids); } /** * 导入案例演示 * * POST /example/import * 对应权限:sys:example:import * * 处理流程: * 1. 从请求中获取上传文件 * 2. 校验文件扩展名(仅 xls、xlsx) * 3. 调用 ExampleLogic::import() 解析并导入 * * @return Json */ #[Log('案例演示-导入数据', Log::TYPE_IMPORT)] #[Permission('sys:example:import', '导入案例演示')] public function import(): Json { $file = $this->request->file('file'); if (!$file) { return $this->fail('请选择文件'); } $ext = strtolower($file->getOriginalExtension()); if (!in_array($ext, ['xls', 'xlsx'])) { return $this->fail('仅支持 xls、xlsx 格式的文件'); } try { $result = $this->logic->import($file->getRealPath()); $msg = empty($result['errors']) ? "成功导入 {$result['count']} 条数据" : "成功导入 {$result['count']} 条,失败 " . count($result['errors']) . " 条"; return $this->success($result, $msg); } catch (\Exception $e) { return $this->fail('导入失败: ' . $e->getMessage()); } } /** * 导出案例演示 * * GET /example/export * 对应权限:sys:example:export * * @return Json */ #[Log('案例演示-导出数据', Log::TYPE_EXPORT)] #[Permission('sys:example:export', '导出案例演示')] public function export(): Json { try { $filePath = $this->logic->export($this->getParams()); return $this->success($filePath, '导出成功'); } catch (\Exception $e) { return $this->fail('导出失败: ' . $e->getMessage()); } } } ``` ## 注解说明 ### #[Log] 操作日志注解 ```php #[Log('案例演示-新增记录', Log::TYPE_ADD, '新增案例演示:{name}')] // │ │ │ // │ │ └── 描述(支持 {param} 占位符) // │ └── 操作类型 // └── 操作标题 ``` ### #[Permission] 权限注解 ```php #[Permission('sys:example:add', '添加案例演示')] // │ │ // │ └── 权限名称 // └── 权限编码 ``` ## BaseController 通用方法 | 方法 | 用途 | 内部调用 | |------|------|----------| | `_index($logic)` | 分页查询 | `$logic->pageList()` | | `_list($logic)` | 全量列表 | `$logic->allList()` | | `_detail($logic, $id)` | 详情查询 | `$logic->detail($id)` | | `_add($logic, $data)` | 新增 | `$logic->add($data)` | | `_edit($logic, $id, $data)` | 修改 | `$logic->update($id, $data)` | | `_remove($logic, $id)` | 删除 | `$logic->delete($id)` | | `_batchRemove($logic, $ids)` | 批量删除 | `$logic->batchDelete($ids)` |