Skip to content

后端工程规范 ​

面向对象:后端开发者、代码评审者、AI Agent。

本文维护 com.bokun.* 后端代码与 digital-construction-* 模块的分层、实现和验证规范。跨端契约见公共开发约定。

决策优先级 ​

后端修改按以下顺序判断正确性:

  1. 用户明确指令、适用业务基线、已核实的接口契约与安全要求;
  2. 项目硬约束:包根 com.bokun、模块边界和公共基础能力;
  3. 当前仓库同类型成熟实现;
  4. RuoYi-Vue-Plus 6.X 基线和 generator 模板;
  5. 通用 Java、Spring、MyBatis-Plus 实践。

成熟代码是本地证据,不是绝对真理。若它与前两项冲突,说明差异并按目标修正。

优先参考的代码来源 ​

  • 生成器 Java 模板:digital-construction-modules/digital-construction-gen/src/main/resources/fm/java/;Mapper XML 模板:digital-construction-modules/digital-construction-gen/src/main/resources/fm/xml/mapper.xml.ftl。
  • 公共能力:digital-construction-common/,按任务选择 core、mybatis、web、redis、translation、json、oss、excel、log 等对应模块。
  • 业务样本根目录:digital-construction-modules/digital-construction-business/src/main/java/com/bokun/business/,下表路径均相对此目录。
场景代码入口
工点主数据controller/SiteMasterController.java → service/impl/SiteMasterServiceImpl.java → mapper/SiteMasterMapper.java
线路与标段主数据controller/LineController.java、controller/BidSectionController.java
工程数据授权controller/UserDataScopeController.java → service/impl/UserDataScopeServiceImpl.java;授权判定见 service/helper/EngineeringDataAccessHelper.java

先核对需求、根因和必须保持的正确行为,从直接调用方与实际数据流确定影响边界,按任务分级扩展并收敛调查;不按改动行数预判风险或减少必要调查。新增模式、上下文不足或涉及共享机制时,核验最接近的成熟样本;样本与当前业务契约或规范存在差异时先查清,不能机械复制。防御、校验、抽象和异常处理统一按实现简洁性执行。

分层结构 ​

标准 CRUD 固定结构:

text
domain/Entity.java
domain/bo/EntityBo.java
domain/vo/EntityVo.java
mapper/EntityMapper.java
service/IEntityService.java
service/impl/EntityServiceImpl.java
controller/EntityController.java

Controller 只负责协议边界;业务规则和跨资源写入放在 Service;数据访问按项目 Mapper 体系实现。

关键类全限定名 ​

  • com.bokun.common.core.domain.R<T>:统一响应。
  • com.bokun.common.mybatis.core.page.PageQuery:分页查询参数。
  • com.bokun.common.core.domain.PageResult<T>:分页结果。
  • com.bokun.common.mybatis.core.domain.BaseEntity:实体基类。
  • com.bokun.common.mybatis.core.mapper.BaseMapperPlus<E, V>:Mapper 基类。
  • com.bokun.common.core.utils.MapstructUtils:MapStruct Plus 转换工具。
  • com.bokun.common.core.exception.ServiceException:业务异常。

Entity 规则 ​

  • 默认继承 BaseEntity。
  • 使用 Lombok @Data、@EqualsAndHashCode(callSuper = true)。
  • @TableName("业务表名");现有业务表多为 biz_* 或 form_*。
  • 主键用 @TableId。
  • 有 delFlag 保留 @TableLogic;有乐观锁字段保留 @Version。
  • 展示字段和派生字段放 VO,不放 Entity。

Entity 与表结构成对核验 ​

实体继承 BaseEntity 时,数据库表必须同时具备其实际持久化的审计列,包括 create_dept、create_by、create_time、update_by、update_time。不能因为字段值为空就假定 MyBatis-Plus 不会把列带入 INSERT/UPDATE。

新增表、调整持久化字段、继承关系或 Entity/Mapper 映射时,必须通过项目 MCP 检查开发库 USER_TAB_COLUMNS 中受影响的实际结构,并验证受影响的真实读写链路;涉及写入映射时至少验证一条真实写入链路。交付数据库基线及字段矩阵按数据库设计特别检查的阶段和范围要求核对,普通局部变更不因历史基线资料缺失扩展整表文档工作。仅修改注释、非持久化逻辑或查询条件,不要求无关的全表核验和写入。数据库变更通过项目 MCP 执行,不在仓库新增 SQL 文件。

BO 规则 ​

  • 实现 Serializable。
  • 加 @AutoMapper(target = Entity.class, reverseConvertGenerate = false)。
  • 请求/查询专用字段(含 params)放 BO。
  • 校验注解(@NotBlank、@NotNull、@Size、@Xss、@Email)按真实业务语义添加,不整套堆砌;有分组校验时沿用 AddGroup、EditGroup、QueryGroup。
  • 查询含日期范围时保留 params = new HashMap<>(),用 beginXxx / endXxx 键。

VO 规则 ​

  • 实现 Serializable。
  • 加 @AutoMapper(target = Entity.class)。
  • 导出场景才加 @ExcelIgnoreUnannotated、@ExcelProperty、@ExcelDictFormat、@ExcelDictConvert 等。
  • 关联展示字段沿用 @Translation(type = TransConstant.XXX, mapper = "createBy") 风格。

Mapper 规则 ​

  • 默认 interface XxxMapper extends BaseMapperPlus<Xxx, XxxVo>。
  • 简单 entity→vo 不手写转换,依赖 BaseMapperPlus 的 selectVoList / selectVoPage。
  • 角色数据范围注解(@DataPermission/@DataColumn)机制已于 2026-09-29 整体移除,不再新增;工程数据可见范围统一由 EngineeringDataAccessHelper 判定或注入 EXISTS 谓词(按标段工点专属资源、工点共享资源与整线资源分别控制),杜绝独立三维 OR 交叉放行。
  • 复杂联表用 MPJ:QueryBuilder.lambdaJoin("别名", Entity.class),保持同模块风格。
  • 只有 BaseMapperPlus + wrapper 表达不了时才补 XML(模板:fm/xml/mapper.xml.ftl)。
  • Mapper 默认方法只放短小查询;业务编排、缓存、事务和跨 Mapper 写操作放 Service。

Service 规则 ​

  • 类用 @RequiredArgsConstructor、@Service,需要日志时加 @Slf4j。

  • Mapper 注入字段用具体业务短名,如 SiteMasterMapper → siteMasterMapper。

  • 读操作返回 Vo、List<Vo> 或 PageResult<Vo>。

  • 常规转换一律 MapstructUtils.convert(bo, Entity.class) / MapstructUtils.convert(entity, Vo.class),不要手写逐字段 setter。

  • 分页查询:

    java
    Page<Vo> result = entityMapper.selectVoPage(pageQuery.build(), lqw);
    return PageResult.build(result.getRecords(), result.getTotal());
  • 条件优先用项目扩展:eqIfPresent、eqIfText、likeIfText、inIfNotEmpty、betweenParams、betweenIfPresent。

  • 包含多个持久化步骤、读取校验后写入、金额或状态流转、跨资源写入,或失败时必须整体回滚的操作,应在 Service 层设置清晰事务边界并使用 @Transactional(rollbackFor = Exception.class);单条独立 CRUD 不机械添加事务。

  • 业务失败(权限、数据完整性、删除前校验)用 ServiceException。

  • 保留现有有效的防误删、防越权和防并发覆盖逻辑,不因低并发基线擅自删除已确认的业务保护。

  • 金额或状态流转更新必须校验合法前置状态;并发控制是否纳入处理遵循根 AGENTS.md 的“并发与缺陷认定”。已纳入时优先复用项目乐观锁或带旧状态条件的更新方式,不为理论竞争时序另建机制。

Controller 规则 ​

  • 继承 BaseController;类上通常 @Validated、@RestController、@RequiredArgsConstructor、@RequestMapping。
  • 返回值 R<T> / R<Void>。
  • 标准接口:GET /list、POST /export、GET /{id}、POST、PUT、DELETE /{ids}。
  • 权限 @SaCheckPermission("module:business:action");写操作和导出加 @Log(title = "...", businessType = BusinessType.X)。
  • 写接口按已确认业务要求使用 @RepeatSubmit,是否新增防重遵循根规则,不因附近接口已有注解而机械添加;分组校验用 @Validated(AddGroup.class) / EditGroup.class。
  • Controller 负责接参、校验、权限、日志;重业务逻辑放 Service。

权限码规则(硬约束) ​

权限码格式、前后端与菜单的一致性要求及回归检查统一遵循公共开发约定 · 三段式权限码。

MapStruct 规则 ​

  • 目标:常规转换不出现手工 setter 链。
  • BO → Entity:MapstructUtils.convert(bo, Entity.class),BO 上 @AutoMapper(target = Entity.class, reverseConvertGenerate = false)。
  • Entity → VO:MapstructUtils.convert(entity, Vo.class),VO 上 @AutoMapper(target = Entity.class)。
  • 字段名不同或需要忽略字段时,用 @AutoMapping(target = "xxx", ignore = true) 或同包自定义 Mapper 接口,先查项目是否已有类似处理。
  • 列表转换:MapstructUtils.convert(list, Vo.class) 或 selectVoPage/selectVoList。
  • 新增/修改共用同一 BO 时,先查 MapstructUtils.convert(bo, Entity.class) 是否会覆盖不该覆盖的字段(如创建时间、逻辑删除),必要时在 Service 中单独处理。

查询与工具规则 ​

  • 分页统一 PageQuery / PageResult,不引入新的分页 DTO。
  • 日期范围从 bo.getParams() 取 beginXxx / endXxx,用 betweenParams(Entity::getField, params, "beginXxx", "endXxx")。
  • 优先项目工具:MapstructUtils、StringUtils、StreamUtils、ValidatorUtils、SpringUtils、RedisUtils。
  • 数组转列表按附近代码使用 List.of(ids) 或 Arrays.asList(ids)。

数据权限、缓存、翻译与 JSON 增强 ​

  • 数据权限:角色数据范围(@DataPermission)机制已于 2026-09-29 整体移除;工程数据统一按新工程数据授权(EngineeringDataAccessHelper.applyPairScope 等)在 Service/Mapper 层动态裁剪,新业务域按公共开发约定显式声明过滤策略。
  • 缓存:有 @Cacheable / @CacheEvict / CacheUtils 的模块,写操作同步处理缓存失效。
  • 翻译:实现 TranslationInterface<T> + @TranslationType;VO 用 @Translation;批量翻译必须实现 translationBatch,避免逐条查询。
  • JSON 增强:沿用 JsonFieldProcessor 的 collect / prepare / process 三阶段模型。

大整数 ID 约定 ​

后端序列化、前端传递与接口排查统一遵循公共开发约定 · 前后端大整数 ID 约定。

数据库与 SQL 规则 ​

  • 数据库可迁移性是硬约束,DM8 只是当前运行与验证环境;优先使用 MyBatis-Plus、项目查询能力和标准 SQL。
  • 数据库查询、结构检查、DDL、DML、迁移、初始化和验证 SQL 统一通过项目 MCP dcp-dm8-dev,入口是 .agents/mcp/launch.ps1;仓库不保存业务 .sql 文件,不使用命令行 SQL 客户端、临时 Java/Python 直连或项目外 MCP。新表、新字段和数据库变更由此直接作用于开发库,写入前核对环境、对象和条件,写入后回读并报告实际影响行数/对象;逻辑约束不能只存在于某个厂商实现的注释中。
  • 避免把 MySQL、DM8、人大金仓或 openGauss 专属函数、分页、类型和关键字写进通用业务层。
  • 无法避免的厂商差异集中在 Mapper/XML 或明确的数据库适配点,并说明替换条件;不要在 Controller、Service 散落数据库类型判断。
  • 当前只实现实际使用的数据库版本,不提前生成尚未启用的多套适配代码。
  • 分页使用 PageQuery 的构建逻辑,不手写厂商分页 SQL;表名、字段名与 Entity 映射一致。
  • 修改 Mapper XML 前先查看同模块风格,并检查新增 SQL 的跨数据库可替换性。

JavaDoc 注释规则 ​

  • 公共接口、复杂业务规则、非直观约束、兼容性处理和容易误用的逻辑补简洁 JavaDoc,说明“为什么”和关键语义,不复述实现。
  • 标准 CRUD、显而易见的方法和重复字段说明不强制生成模板式注释。
  • void 方法不写 @return;返回 boolean 说明 true/false 含义。
  • 复杂私有方法(算法、映射、规则)补短注释;简单 getter/框架覆写不强行重复注释。
  • 只改注释时,不重排 import、不格式化全文件、不改代码行为。

前后端联动规则 ​

  • 后端接口路径和权限前缀与前端 src/api 保持一致。
  • 日期范围查询保留 bo.params,前端 addDateRange / useDateRangeQuery 才能对接。
  • 导出保持 POST /export,批量删除 DELETE /{ids}。
  • 前端改动部分使用前端工程规范。

测试与验证 ​

测试复用、范围选择、验证层次及停止条件统一见公共开发约定 · 验证范围;证据和完成表述见最新验证证据。后端特有检查如下:

  • 按根 AGENTS.md 根据实际风险选择定向测试、接口、数据库回读或浏览器等证据,不因后端链路供页面使用就一律执行浏览器验证。Agent 判断需要或用户显式要求时,从真实业务页面操作;不得以 API 请求或内部状态注入冒充页面验证,文件上传例外遵循根规则。无运行行为变化的修改执行对应静态核对,结论限于实际覆盖范围。
  • 根据需求、稳定契约及根因证据选择回归,重点检查实际受影响的列表、统计、导出、调用方、历史数据和失败路径;鉴权、数据范围、事务、缓存或状态变化时覆盖相应边界。不机械执行全部测试,也不以目标接口正常代替关联回归;网络、日志和数据库回读可作辅助证据。
  • 持久化结构、继承关系及映射变化按Entity 与表结构成对核验验证真实链路;涉及写入映射时至少验证一条真实写入链路,查询条件修改不附加无关写入。
  • 后端鉴权、数据范围、事务边界和回滚等独立风险必须使用能覆盖该风险的检查,不能用仅验证纯函数或编译的结果替代。
  • 编译、定向回归、完整模块回归的命令见环境配置与运行 · 验证入口。根 pom 默认跳过测试,Surefire 还按 ${profiles.active} 过滤标签;需要执行测试时按该入口显式关闭跳过选项,并核对目标测试标签及本次报告的实际执行数量,不能仅凭 BUILD SUCCESS 判定回归通过。
  • 项目工具入口正常执行即为可用证据;新环境、路径不确定或执行异常时按环境配置与运行诊断。工具或依赖问题不豁免必要回归,实际未通过范围按根规则报告。

避免事项 ​

  • 不要在 Controller 里暴露 Entity 代替 BO/VO。
  • 任务涉及权限、日志、事务或删除保护时,不要将其留到后续补做;任务不涉及的能力不添加占位代码。
  • 不要用 Wrappers.lambdaQuery 覆盖已有 QueryBuilder / MPJ 风格。
  • 不要删除日期范围 params 处理。
  • 不要把 business / workflow 复杂逻辑简化成 generator 裸产物。
  • 不要照抄 ruoyi-* 旧名、org.dromara 包名或旧模块名。

交付前自检 ​

仅对本次改动选取适用项,检查结果可直接作为任务验证记录,无需另填整套清单:

  • 对照受影响分层正文核对 BO/VO/Entity 职责、分页查询、删除校验及稳定契约;转换和注释符合 MapStruct、JavaDoc 章节。
  • 对照 Service、Controller 和数据范围正文核对权限、日志、防重、事务及异常路径。
  • 涉及持久化结构或映射时完成成对核验;涉及行为时按测试与验证取得对应证据。文档与待发布事项统一按根规则收尾。