# Router 层(Flask Blueprint) Router 层是 HTTP 接口层,负责定义路由、权限装饰器和请求参数解析。每个业务模块对应一个 router 文件,所有业务逻辑委托给 Service 层处理。 ## 文件位置 ``` src/modules/system/position/router.py ``` ## 完整代码 以岗位模块为例,`src/modules/system/position/router.py` 完整内容: ```python """ 岗位管理控制器模块 ============================================================= 提供岗位(Position)相关的API接口,包括: - 岗位分页查询 - 岗位详情查询 - 岗位添加、更新、删除 - 岗位状态设置 - 岗位数据列表获取 """ from flask import Blueprint, request from src.middleware import check_demo, operation_log from src.core.permission import check_permission from src.modules.system.position import service as position from src.common.utils.request import parse_batch_ids, parse_request_body from src.core import response as R position_blue = Blueprint('position', __name__, url_prefix='/position') # ============================================================ # 岗位分页查询 # ============================================================ @position_blue.route('/page', methods=["GET"]) @check_permission("sys:position:page") @operation_log("岗位管理", "查询") def page(): """ 查询岗位分页数据 Returns: JSON: 岗位分页数据,包含 records(数据列表)、total(总记录数)等 """ return R.ok(data=position.get_position_page(request.args)) # ============================================================ # 岗位详情查询 # ============================================================ @position_blue.route('/detail/', methods=["GET"]) @check_permission("sys:position:detail") @operation_log("岗位管理", "详情") def detail(id): """ 查询岗位详情 Args: id: 岗位ID Returns: JSON: 岗位详细信息 """ data = position.get_position_detail(id) return R.ok(data=data) # ============================================================ # 岗位添加 # ============================================================ @position_blue.route('/add', methods=["POST"]) @check_permission("sys:position:add") @check_demo @operation_log("岗位管理", "新增") def add(): """ 添加岗位 Returns: JSON: 操作结果 """ json_data, err = parse_request_body() if err: return R.failed(msg=err) position.add_position(json_data) return R.ok(msg="添加成功") # ============================================================ # 岗位更新 # ============================================================ @position_blue.route('/update', methods=["PUT"]) @check_permission("sys:position:update") @check_demo @operation_log("岗位管理", "修改") def update(): """ 更新岗位 Returns: JSON: 操作结果 """ json_data, err = parse_request_body() if err: return R.failed(msg=err) position.update_position(json_data) return R.ok(msg="更新成功") # ============================================================ # 岗位删除 # ============================================================ @position_blue.route('/delete/', methods=["DELETE"]) @check_permission("sys:position:delete") @check_demo @operation_log("岗位管理", "删除") def delete(id): """ 删除岗位 Args: id: 岗位ID(支持逗号分隔的多个ID) Returns: JSON: 操作结果 """ count = position.delete_positions(id) return R.ok(msg=f"本次共删除{count}条数据") # ============================================================ # 岗位批量删除 # ============================================================ @position_blue.route('/batchDelete', methods=["DELETE"]) @check_permission("sys:position:batchDelete") @check_demo @operation_log("岗位管理", "批量删除") def batch_delete(): """ 批量删除岗位 Request Body: [1, 2, 3] # 岗位ID数组 Returns: JSON: 操作结果 """ id_str, err = parse_batch_ids() if err: return err count = position.delete_positions(id_str) return R.ok(msg=f"本次共删除{count}条数据") # ============================================================ # 岗位状态设置 # ============================================================ @position_blue.route('/status', methods=["PUT"]) @check_permission("sys:position:status") @check_demo @operation_log("岗位管理", "状态变更") def status(): """ 设置岗位状态 Returns: JSON: 操作结果 """ json_data, err = parse_request_body() if err: return R.failed(msg=err) position.update_position_status(json_data) return R.ok(msg="设置成功") # ============================================================ # 岗位列表获取(无分页) # ============================================================ @position_blue.route('/list', methods=["GET"]) @check_permission("sys:position:list") @operation_log("岗位管理", "查询") def get_position_list(): """ 获取岗位数据列表(无分页) 用于下拉选择框,支持 name 模糊匹配。 Returns: JSON: 岗位列表数据 """ result = position.get_position_list(request.args) return R.ok(data=result) ``` ## 代码解析 ### Blueprint 实例 ```python position_blue = Blueprint('position', __name__, url_prefix='/position') ``` 每个 router 文件创建一个独立的 `Blueprint` 实例,后续在 `src/routes/v1.py` 中统一注册。 ### 装饰器说明 | 装饰器 | 作用 | 位置 | |:---|:---|:---| | `@position_blue.route()` | 定义 HTTP 方法和路径 | 最外层 | | `@check_permission('sys:position:page')` | RBAC 权限校验 | 路由装饰器之后 | | `@check_demo` | 演示模式拦截(写操作) | 权限装饰器之后 | | `@operation_log("岗位管理", "查询")` | 操作日志记录 | 最内层 | **装饰器顺序必须严格遵守**:路由 → 权限 → 演示模式 → 操作日志。 ### 权限字符串命名规范 ``` sys:{module}:{action} ``` | 动作 | HTTP 方法 | 说明 | |:---|:---|:---| | `page` | GET | 分页查询 | | `detail` | GET | 详情查询 | | `list` | GET | 列表查询(无分页) | | `add` | POST | 新增 | | `update` | PUT | 更新 | | `delete` | DELETE | 单条删除 | | `batchDelete` | DELETE | 批量删除 | | `status` | PUT | 状态变更 | ### 参数解析 ```python # 解析请求体 JSON(POST/PUT) json_data, err = parse_request_body() if err: return R.failed(msg=err) # 解析批量删除的 ID 数组(DELETE) id_str, err = parse_batch_ids() if err: return err # 获取查询参数(GET) params = request.args # 如 request.args.get('name') ``` ### 响应封装 ```python # 成功响应 R.ok(data=data) # 返回数据 R.ok(msg="添加成功") # 返回消息 R.ok(data=data, msg="ok") # 同时返回数据和消息 # 失败响应 R.failed(msg="参数错误") # 返回错误消息 ``` ## 开发要点 1. **只需两步注册**:一行导入 Blueprint,一行添加到 `BLUEPRINTS` 列表 2. **prefix 与模块目录名保持一致**:便于代码导航 3. **所有业务蓝图都挂在 `v1` 路由组下**:自动享受 `login_required` 认证保护 4. **装饰器顺序**:路由 → `@check_permission` → `@check_demo` → `@operation_log` 5. **Router 层不处理业务逻辑**:只做参数解析和响应封装,业务逻辑委托 Service 层 ## 总结 Router 层通过 Flask Blueprint 定义路由,使用 `@check_permission` 实现 RBAC 权限控制,`@check_demo` 拦截演示模式写操作,`@operation_log` 自动记录操作日志。参数解析通过 `parse_request_body()` / `parse_batch_ids()` 完成,响应封装通过 `R.ok()` / `R.failed()` 统一格式。