# 3.6 控制器开发 :::tip 概述 控制器是 HTTP 请求的入口,负责参数获取、调用 Service、返回统一 JSON 响应。通过 `#[Permission]` 和 `#[OperationLog]` 注解实现权限校验和操作日志,配合基类快捷方法,单个接口通常只需几行代码。 ::: ## 控制器文件位置 ```text app/Http/Controllers/Api/ExampleController.php ``` ## 完整代码(来自项目实际代码) ```php _page($this->exampleService); } /** * 查询列表 * * 对应权限:sys:example:list,操作日志类型:查询。 * 返回不分页的完整列表,适合下拉选择等场景。 * * @return JsonResponse 列表数据 */ #[OperationLog('示例管理-查询列表', OperationLog::TYPE_QUERY)] #[Permission('sys:example:list', '示例列表')] public function list(): JsonResponse { return $this->_list($this->exampleService); } /** * 查询详情 * * 对应权限:sys:example:detail,操作日志类型:查询, * 日志模板中包含示例ID:{id}。 * * @param int $id 示例ID * @return JsonResponse 示例详情 */ #[OperationLog('示例管理-查询详情', OperationLog::TYPE_QUERY, '查询示例ID:{id}')] #[Permission('sys:example:detail', '示例详情')] public function detail(int $id): JsonResponse { return $this->_detail($this->exampleService, $id); } /** * 新增 * * 对应权限:sys:example:add,操作日志类型:新增, * 日志模板中包含示例名称:{name}。 * * @param ExampleRequest $request 已通过校验的示例请求 * @return JsonResponse 新增结果 */ #[OperationLog('示例管理-新增', OperationLog::TYPE_ADD, '新增示例:{name}')] #[Permission('sys:example:add', '添加示例')] public function add(ExampleRequest $request): JsonResponse { return $this->_add($this->exampleService, $request->validated()); } /** * 修改 * * 对应权限:sys:example:update,操作日志类型:修改。 * 若请求数据中缺少 id,则直接返回失败响应。 * * @param ExampleRequest $request 已通过校验的示例请求 * @return JsonResponse 修改结果 */ #[OperationLog('示例管理-修改', OperationLog::TYPE_UPDATE, '修改示例ID:{id}')] #[Permission('sys:example:update', '修改示例')] public function update(ExampleRequest $request): JsonResponse { $data = $request->validated(); $id = $data['id'] ?? 0; if (empty($id)) { return $this->fail('缺少id参数'); } return $this->_update($this->exampleService, $id, $data); } /** * 删除 * * 对应权限:sys:example:delete,操作日志类型:删除, * 日志模板中包含示例ID:{id}。 * * @param int $id 示例ID * @return JsonResponse 删除结果 */ #[OperationLog('示例管理-删除', OperationLog::TYPE_DELETE, '删除示例ID:{id}')] #[Permission('sys:example:delete', '删除示例')] public function delete(int $id): JsonResponse { return $this->_delete($this->exampleService, $id); } /** * 批量删除 * * 对应权限:sys:example:batchDelete,操作日志类型:删除。 * 从 JSON 请求体中读取 ids 数组,未传时按空数组处理。 * * @return JsonResponse 批量删除结果 */ #[OperationLog('示例管理-批量删除', OperationLog::TYPE_DELETE)] #[Permission('sys:example:batchDelete', '批量删除')] public function batchDelete(): JsonResponse { $ids = $this->getJsonBody()['ids'] ?? []; return $this->_batchDelete($this->exampleService, $ids); } /** * 导出数据 * * 对应权限:sys:example:export,操作日志类型:导出(TYPE_EXPORT)。 * 由基类 _export() 统一处理文件生成与响应封装。 * * @return JsonResponse 导出结果(data 为文件地址) */ #[OperationLog('示例管理-导出数据', OperationLog::TYPE_EXPORT)] #[Permission('sys:example:export', '导出示例')] public function export(): JsonResponse { return $this->_export($this->exampleService); } /** * 导入数据 * * 对应权限:sys:example:import,操作日志类型:导入(TYPE_IMPORT)。 * 由基类 _import() 统一处理文件校验(格式/大小/MIME)与响应封装。 * * @return JsonResponse 导入结果 */ #[OperationLog('示例管理-导入数据', OperationLog::TYPE_IMPORT, '通过Excel导入示例数据')] #[Permission('sys:example:import', '导入示例')] public function import(): JsonResponse { return $this->_import($this->exampleService); } } ``` :::tip 控制器模式 每个控制器遵循固定模式: 1. **构造函数注入 Service**(Laravel 依赖注入,`protected` 简写属性即成员属性) 2. 每个方法标注 `#[OperationLog]` 和 `#[Permission]` 注解 3. 简单调用 `$this->_page()` / `_detail()` / `_add()` 等快捷方法 4. 入参由 FormRequest 类型注入完成格式校验(见 [3.4 FormRequest 验证器](/zh/guide/validator.html)) ::: ## Controller 基类快捷方法 `app/Http/Controllers/Controller.php` 提供的通用方法: | 方法 | 用途 | 内部调用 | 失败场景 | |------|------|----------|----------| | `_page($service)` | 分页查询 | `Service::pageList()` | - | | `_list($service)` | 全量列表 | `Service::allList()` | - | | `_treeList($service)` | 树形列表 | `Service::treeList()` | - | | `_detail($service, $id)` | 详情查询 | `Service::detail($id)` | 空数据返回 `code=404` | | `_add($service, $data)` | 新增 | `Service::add($data)` | 捕获 `BizException` → `fail(消息, code)` | | `_update($service, $id, $data)` | 修改 | `Service::update($id, $data)` | id 缺失提示;捕获 `BizException` | | `_delete($service, $id)` | 删除 | `Service::delete($id)` | 捕获 `BizException`;其他异常记日志后返回通用提示 | | `_batchDelete($service, $ids)` | 批量删除 | `Service::batchDelete($ids)` | ids 为空提示;同上 | | `_export($service)` | 导出 | `Service::export()` | 捕获 `BizException`(如"无数据可导出") | | `_import($service)` | 导入 | `Service::import()` | 文件格式/大小/MIME 校验 + 通用提示 | 响应封装方法:`$this->success($data, $msg)` / `$this->fail($msg, $code)` / `$this->paginate($result)`(委托给 `Support\Result`,见 [5.16 统一响应与异常抛出](/zh/core/exception.html))。 参数获取方法:`getPageParams()`(pageNo/pageSize,限 1~100)、`getJsonBody()`(JSON 请求体)、`getParams()`(query + body 合并)。 ## 注解说明 ### #[OperationLog] 操作日志注解 ```php #[OperationLog('示例管理-新增', OperationLog::TYPE_ADD, '新增示例:{name}')] // │ │ │ // │ │ └── 描述模板(支持 {param} 占位符,替换为请求参数值) // │ └── 操作类型常量(TYPE_QUERY/ADD/UPDATE/DELETE/IMPORT/EXPORT 等 30 种) // └── 操作标题 ``` - 由 `log.operation` 中间件采集,响应后(terminable 阶段)落库; - 写操作(POST/PUT/DELETE)始终记录,读操作按注解类型选择性记录。 ### #[Permission] 权限注解 ```php #[Permission('sys:example:add', '添加示例')] // │ │ // │ └── 权限名称(菜单管理中显示) // └── 权限编码(菜单表 permission 字段) ``` - 由 `auth.jwt` 中间件反射校验:解析注解 → 比对当前用户权限列表 → 无权限返回 `code=403`; - 超级管理员(用户 ID=1)直接放行; - 未标注 `#[Permission]` 的认证接口只需登录即可访问。 ## 与手动构造响应的对比 ```php // ✅ 推荐:快捷方法(异常处理、日志、404 兜底全部内置) public function page(): JsonResponse { return $this->_page($this->exampleService); } // 特殊场景:手动组织响应 public function stats(): JsonResponse { $data = $this->exampleService->stats(); if (! $data) { return $this->fail('暂无统计数据', 404); } return $this->success($data); } ```