切换日光/暗黑模式
075. Battice Service、自动路由与字段校验
学习目标
这一节把通用服务和自动接口真正跑起来。
学完后,你应该能理解:
BatticeService如何包装 SQLModel 实体;- 如何从模型自动生成模块配置;
- 单条查询如何复用分页查询;
- 自动路由如何一次生成多个接口;
- 字段校验规则如何覆盖默认配置。
测试保护代码逻辑
AI 或人工修改代码时,很容易不小心改掉原有逻辑。
如果底层 SQL 构建器有测试保护,问题会更早暴露。
例如原本空值字段应该被跳过。
如果有人把跳过逻辑删掉,测试会发现生成 SQL 多了不该出现的字段。
所以通用模块这种底层代码必须靠测试兜住。
否则上层接口看起来报错时,定位会很痛苦。
BatticeService
BatticeService 是对模型的通用服务包装。
可以把一个 SQLModel 实体类传进去。
它会提供一组通用方法,例如:
- 分页查询;
- 单条查询;
- 新增;
- 批量新增;
- 更新;
- 批量更新;
- 删除。
这样业务代码可以不直接写 SQLModel 查询,也能使用通用模块能力。
从模型生成配置
通用模块需要模块配置。
手写配置很麻烦。
但 SQLModel 实体类里已经有很多信息:
- 表名;
- 字段名;
- 字段类型;
- 模型字段定义。
所以 BatticeService 可以根据实体类自动生成模块配置。
例如从模型上读取 __tablename__ 作为表名。
再遍历模型字段生成字段配置。
字段配置自动生成
生成出来的配置会包含字段列表。
例如用户模型里有:
- 用户名;
- 姓名;
- 邮箱;
- 是否有效;
- 创建时间;
- 更新时间。
这些字段会变成通用模块可以识别的列配置。
后续查询、筛选、返回数据都依赖这份配置。
单条查询
单条查询本质上复用分页查询。
例如要按用户名查用户:
py
{"username": "张三"}服务会把这个字典转成筛选条件:
txt
username = 张三然后调用列表查询。
只不过分页参数限制为只查一条。
这样单条查询也能复用字段转换、SQL 构建、拦截器等通用能力。
调试单条查询
调试时可以看到几个关键对象。
第一个是 modelConfig。
它保存表名和字段配置。
第二个是查询请求体。
它会从简单字典变成标准查询参数。
第三个是生成的 SQL。
真实 SQL 仍然带占位符。
第四个是参数数组。
例如:
txt
["张三", 0, 1]表示查询用户名为张三,并限制只查一条。
查询结果转换
数据库返回结果后,还要做转换。
例如:
- 日期对象转字符串;
- JSON 字符串转数组;
- 逗号分隔字符串转数组;
- 数据库字段命名转前端字段命名。
如果当前模型没有需要转换的字段,这一步不会明显改变结果。
但通用模块必须保留这个环节。
因为其他模块可能依赖它。
两套数据访问方式
项目里现在有两套方式。
第一套是 SQLModel。
它适合具体业务逻辑。
例如用户激活这种需要先查状态再决定更新的场景。
第二套是 Battice。
它适合通用后台表格能力。
例如列表查询、动态筛选、批量更新、快速生成接口。
这两套方式不是互斥关系。
按场景选择即可。
自动生成接口
add_battice_route 可以把一个实体类变成一组接口。
类似 LangServe 可以把模型对象变成接口服务。
通用模块也可以把数据模型变成增删改查接口。
一次会生成多类接口。
常见包括:
- 分页查询;
- 单条查询;
- 新增;
- 批量新增;
- 更新;
- 批量更新;
- 删除。
这样新增一个模块时,不需要手写每个接口。
路由前缀
自动生成接口时会有一个统一前缀。
例如:
txt
/generic/battice-demo/list其中:
generic是通用接口前缀;battice-demo是模块标识;list是动作类型。
接口内部会调用对应服务函数。
分页查询接口
分页查询接口支持通用查询参数。
例如按姓名模糊查询。
也可以只查总数。
还可以在分页查询同时返回总数。
这些能力都来自前面写好的查询构建器。
接口层只是把请求接到服务函数上。
拦截器类型类比
拦截器动作名称类似事件名。
前端里会监听:
js
click通用模块里会监听:
txt
beforeInsert
afterInsert
beforeList
afterList如果没有定义这个动作类型,就无法注册对应拦截器。
所以类型定义不是多余的。
它规定了系统允许哪些扩展点。
字段校验覆盖
自动生成配置只能给出默认字段信息。
但业务经常需要额外规则。
例如金额不能超过 100 万。
这时可以通过额外列配置覆盖默认字段配置。
例如给 amount 配:
- 类型是数字;
- 必填;
- 最小值;
- 最大值;
- 错误提示。
这样同一个模型可以生成不同接口。
一个接口不做额外校验。
另一个接口增加业务校验。
校验效果
如果普通接口没有配置金额上限,大金额也能写入。
如果校验接口配置了金额最大值,再提交超过限制的值,就会返回错误。
这说明通用模块的字段配置不是只用于展示。
它也参与后端数据校验。
这一节的重点
这一节让通用模块真正从代码结构变成可调用接口。
你需要记住:
BatticeService把 SQLModel 实体包装成通用服务;- 模块配置可以从模型字段自动生成;
- 单条查询可以复用分页查询;
add_battice_route可以一次生成多类接口;- 拦截器动作名像事件名,必须先定义才能注册;
- 额外字段配置可以覆盖默认配置,并用于后端校验;
- 测试用例是防止底层逻辑被改坏的关键保护。