# abacus.springboot.example — 架构文档(ARCHITECTURE) > 模块、依赖、契约、目录布局的**唯一权威**(本仓库视角)。新增/重命名/移动模块或调整依赖方向,必须先改本文,再改代码(同一个 commit)。 > 上游:`PRD.md`(行为)。前后端共享约束见工作区 `docs/`(`../../../../docs/coding-standards.md` §5 后端规范、§6 接口契约),本文不复制其正文。 ## 0. 阅读指引 本文描述后端模板的模块划分与依赖方向;§2 模块清单与 §6 目录一一对应,§3.2 是跨模块接口契约。新会话先读 §2 + §6 定位任务归属,再动手。 ## 1. 领域模型(Domain Model) ### 1.1 实体 模板自带示例纵切面(稽查 JcBill),供复制改写: | 实体 | 字段 | 关系 | 持久化? | |---|---|---|---| | jc_bill(稽查主单) | id(@Id)/version(@Version)/status/… | 1:N 明细 | 是 | | jc_bill_item / jc_bill_photo / jc_bill_hg / jc_bill_hg_pay / jc_source_item / jc_bill_in_item / jc_bill_source_item | id/主单关联字段 | N:1 主单 | 是 | 字段细节见 `dao/*.java` 与 `sql/upgrade.xml`(建表 DDL)。 ### 1.2 派生概念(非持久化) - `api/view/*`:请求/响应 DTO(ApiReq*/ApiResp*),编排层与 Controller 之间传递。 - `@Transient` 字段:实体上的非持久化附加信息(如 `recsource`)。 ### 1.3 不变量(任何模块都必须维护) - I1. 业务主键一律由 `DaoIdGenerator` 生成(prefix+yyyyMMdd+serialLength),禁止手拼/UUID。 - I2. 原生 SQL 全量 `?` 参数化,禁止字符串拼接。 - I3. 分层依赖单向:api/controller → esb/wsi → {pi/impl, repository} → dao;禁止反向依赖。 - I4. Controller 直接 return 业务对象,禁止手拼统一响应体。 ## 2. 模块清单 按依赖层级从低到高排列。 ### Layer 0 — dao(实体层) ``` ## 模块名:dao - 职责:JPA 实体(表映射、状态常量、@Version 乐观锁) - 不负责:查询逻辑、业务规则 - 输入:无(被 repository/impl 引用) - 输出:实体类型 - 关键类型/接口:@Entity 类(如 JcBill) - 持有状态:无(纯数据) ``` ### Layer 0 — config(基础设施配置) ``` ## 模块名:config - 职责:@Configuration(DaoIdGenerator、AbacusConfigNote 默认值)+ 配置 key 常量 - 不负责:业务规则 - 输入:application.yml / Nacos 配置 - 输出:基础设施 Bean - 持有状态:无 ``` ### Layer 1 — repository / pi+impl(数据访问) ``` ## 模块名:repository(Spring Data JPA) - 职责:标准 CRUD 与派生查询(findByXxx) - 不负责:复杂查询(走 pi/impl) - 输出:实体查询结果 ## 模块名:pi + impl(原生 SQL 访问) - 职责:复杂查询/批量写(pi 定义接口,impl 实现,SQL 参数化) - 不负责:业务编排 - 输出:DTO/实体结果 ``` ### Layer 2 — esb / wsi(服务编排与接口) ``` ## 模块名:esb + wsi - 职责:业务用例编排(esb/*BizService,@Service)、对外服务接口(wsi/*ServiceIF) - 不负责:直接 SQL、Controller 层参数解析 - 输入:Controller 传入的 DTO/参数 - 输出:编排结果(DTO/实体) - 持有状态:事务边界(@Transactional 按需) ``` ### Layer 3 — api / controller(接口层) ``` ## 模块名:api + controller - 职责:对外接口(api/,springdoc 扫描)与前端/内部接口(controller/,abacus.controllerPackages 扫描) - 不负责:业务编排与 SQL - 输入:HTTP 请求(@RequestParam/@RequestBody) - 输出:业务对象(由 ResultResponseBodyWrapper 包装) - 持有状态:无 ``` ## 3. 依赖图(DAG) ```mermaid graph TD api_controller[api / controller] --> esb_wsi[esb / wsi] esb_wsi --> pi_impl[pi / impl] esb_wsi --> repository[repository] pi_impl --> dao[dao] repository --> dao esb_wsi --> dao config -.注入.-> esb_wsi config -.注入.-> pi_impl ``` ### 3.1 依赖方向规则 - 高层依赖低层,单向;**禁止** dao 依赖 repository、esb 依赖 controller 等反向依赖。 - 跨层调用走接口(wsi ServiceIF / pi AccessIF),不 reach into 实现。 ### 3.2 跨模块接口契约(写代码时必须遵守的签名) ``` // module: controller // @RequestMapping(value, method) -> 业务对象(throws Exception) // 直接 return,I4 // module: esb/wsi // XxxServiceIF.method(dto...) throws Exception // 编排用例,事务边界 // module: pi/impl // XxxAccessIF.method(params...) -> List // 原生 SQL,I2 参数化 // module: repository // XxxRepository extends JpaRepository, JpaSpecificationExecutor // module: config // @Bean DaoIdGenerator(prefix/useDateFormat/yyyyMMdd/serialLength) // I1 ``` ## 4. 持久化与边界 - 数据源:Druid 连接池 + JPA;多数据源由 Nacos `abacus-database.yml` 提供(enableMultiSource / multidb0~9 / defaultDB / readDB / dynamicRelation)。 - 外部边界:Nacos(注册+配置)、Kafka(消息)、XXL-JOB(调度)、Feign(服务间调用)、springdoc(接口文档)、Actuator(监控)。 ## 5. 测试边界 - 无自动化单测(PRD 决策);接口人工冒烟。 - **必须真机验证**:多数据源路由、Kafka 消费、XXL-JOB 调度、Nacos 配置拉取、真实数据库迁移——mock/模拟器不算数。 ## 6. 目录结构(与 §2 模块清单一一对应) ``` src/main/java/abacus/springboot/<应用名>/ ├── Application.java # 入口(注册 ResultResponseBodyWrapper) ├── api/ # 对外 Controller(springdoc 扫描);api/view/ 放 DTO ├── controller/ # 前端/内部 Controller(abacus.controllerPackages 扫描) ├── dao/ # JPA 实体(abacus.entitypackages 扫描) ├── esb/ # Service 编排层(@Service) ├── wsi/ # 服务接口 *ServiceIF ├── pi/ # 数据访问接口 *AccessIF ├── impl/ # 数据访问实现(原生 SQL) ├── repository/ # Spring Data JPA Repository ├── config/ # @Configuration + 配置常量 ├── util/ vo/ # 既有兼容(可引不可增) src/main/resources/ ├── config/{dev,test,prod}/ # 三套同构配置 ├── sql/{table,data}/ + upgrade.xml # 建表双份/初始化/版本化升级 ├── html/vue/<应用名>/ # 前端构建产物(打包入 *-bin.zip) └── doc/升级日志.md # 功能更新记录 ``` ## 7. 自检(架构健康度三问) 1. 出 bug 了,能否 30 秒内指出是哪个包(controller/esb/impl/repository)的责任? 2. 换数据库/换 JPA 实现,改动能否控制在 impl/repository + 配置内? 3. 加新业务接口,能否立刻说出它落在 api 还是 controller、esb 是否要新增 BizService? ## 8. 待办与已知技术负债 - `springdoc-openapi-maven-plugin` 的 `apiDocsUrl` 硬编码 `http://localhost:8080/v3/api-docs`,与应用实际端口(9060)不一致,生成 openapi.json 时需手工修正。 - `prod/application.yml` 引用 `abacus.springboot.example.springdoc` 扫描路径但该包不存在(模板未创建 springdoc 包)——新系统以实际包为准。 ## 9. 文档变更协议 - 加/删模块或改依赖方向 → 改本文 §2 + §3,同一 commit。 - 改对外签名 → 先改 §3.2,再改代码。 - 与 `PRD.md` 冲突 → 以 `PRD.md` 为准,回改本文;与共享 `docs/coding-standards.md` 冲突 → 以 docs/ 为准并回改本文。