|
|
|
|
# 开发规范
|
|
|
|
|
|
|
|
|
|
<cite>
|
|
|
|
|
**本文引用的文件**
|
|
|
|
|
- [CrmAppApplication.java](file://crm-app/src/main/java/com/crm/app/CrmAppApplication.java)
|
|
|
|
|
- [application.yml](file://crm-app/src/main/resources/application.yml)
|
|
|
|
|
- [AuthApplication.java](file://crm-auth/src/main/java/com/crm/auth/AuthApplication.java)
|
|
|
|
|
- [application.yml](file://crm-auth/src/main/resources/application.yml)
|
|
|
|
|
- [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java)
|
|
|
|
|
- [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java)
|
|
|
|
|
- [BaseDTO.java](file://crm-base/src/main/java/com/crm/base/domain/dto/BaseDTO.java)
|
|
|
|
|
- [BaseParam.java](file://crm-base/src/main/java/com/crm/base/domain/param/BaseParam.java)
|
|
|
|
|
- [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java)
|
|
|
|
|
- [PageResult.java](file://crm-base/src/main/java/com/crm/base/domain/result/PageResult.java)
|
|
|
|
|
- [ResultCodeEnum.java](file://crm-base/src/main/java/com/crm/base/domain/result/ResultCodeEnum.java)
|
|
|
|
|
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
|
|
|
|
|
- [BusinessErrorException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/BusinessErrorException.java)
|
|
|
|
|
- [MissingParameterException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/MissingParameterException.java)
|
|
|
|
|
- [PermissionErrorException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/PermissionErrorException.java)
|
|
|
|
|
- [ResourceNotExistException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/ResourceNotExistException.java)
|
|
|
|
|
- [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java)
|
|
|
|
|
- [DataOwnership.java](file://crm-base/src/main/java/com/crm/base/security/DataOwnership.java)
|
|
|
|
|
- [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java)
|
|
|
|
|
- [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java)
|
|
|
|
|
- [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java)
|
|
|
|
|
- [LoginUser.java](file://crm-base/src/main/java/com/crm/base/security/LoginUser.java)
|
|
|
|
|
- [SecurityUtils.java](file://crm-base/src/main/java/com/crm/base/security/SecurityUtils.java)
|
|
|
|
|
- [TraceIdFilter.java](file://crm-base/src/main/java/com/crm/base/filter/TraceIdFilter.java)
|
|
|
|
|
- [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)
|
|
|
|
|
- [MetaObjectFillHandler.java](file://crm-base/src/main/java/com/crm/base/config/MetaObjectFillHandler.java)
|
|
|
|
|
- [SnowflakeIdWorker.java](file://crm-base/src/main/java/com/crm/base/config/SnowflakeIdWorker.java)
|
|
|
|
|
- [CustomIdGenerator.java](file://crm-base/src/main/java/com/crm/base/config/CustomIdGenerator.java)
|
|
|
|
|
- [AuthService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthService.java)
|
|
|
|
|
- [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java)
|
|
|
|
|
- [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java)
|
|
|
|
|
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
|
|
|
|
|
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
|
|
|
|
|
- [SecurityExceptionHandlers.java](file://crm-auth/src/main/java/com/crm/auth/security/SecurityExceptionHandlers.java)
|
|
|
|
|
- [LoginParam.java](file://crm-auth/src/main/java/com/crm/auth/domain/param/LoginParam.java)
|
|
|
|
|
- [LoginResultDTO.java](file://crm-auth/src/main/java/com/crm/auth/domain/dto/LoginResultDTO.java)
|
|
|
|
|
- [UserInfoDTO.java](file://crm-auth/src/main/java/com/crm/auth/domain/dto/UserInfoDTO.java)
|
|
|
|
|
- [AuthUser.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/AuthUser.java)
|
|
|
|
|
- [AuthIdentity.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/AuthIdentity.java)
|
|
|
|
|
- [SysDept.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysDept.java)
|
|
|
|
|
- [SysMenu.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysMenu.java)
|
|
|
|
|
- [SysRole.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysRole.java)
|
|
|
|
|
- [SysRoleMenu.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysRoleMenu.java)
|
|
|
|
|
- [SysUserDept.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysUserDept.java)
|
|
|
|
|
- [SysUserRole.java](file://crm-auth/src/main/java/com/crm/auth/domain/entity/SysUserRole.java)
|
|
|
|
|
- [DataScopeEnum.java](file://crm-auth/src/main/java/com/crm/auth/domain/enums/DataScopeEnum.java)
|
|
|
|
|
- [IdentityTypeEnum.java](file://crm-auth/src/main/java/com/crm/auth/domain/enums/IdentityTypeEnum.java)
|
|
|
|
|
- [MenuTypeEnum.java](file://crm-auth/src/main/java/com/crm/auth/domain/enums/MenuTypeEnum.java)
|
|
|
|
|
- [FileApi.java](file://crm-file/src/main/java/com/crm/file/api/FileApi.java)
|
|
|
|
|
- [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java)
|
|
|
|
|
- [FileInfo.java](file://crm-file/src/main/java/com/crm/file/domain/entity/FileInfo.java)
|
|
|
|
|
- [IFileInfoService.java](file://crm-file/src/main/java/com/crm/file/service/IFileInfoService.java)
|
|
|
|
|
- [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java)
|
|
|
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
|
|
|
|
- [KkFileViewClient.java](file://crm-file/src/main/java/com/crm/file/service/KkFileViewClient.java)
|
|
|
|
|
- [OrphanChunkCleanupTask.java](file://crm-file/src/main/java/com/crm/file/task/OrphanChunkCleanupTask.java)
|
|
|
|
|
- [DictGroupVO.java](file://crm-dict/src/main/java/com/crm/dict/domain/dto/DictGroupVO.java)
|
|
|
|
|
- [DictItemVO.java](file://crm-dict/src/main/java/com/crm/dict/domain/dto/DictItemVO.java)
|
|
|
|
|
- [DictGroup.java](file://crm-dict/src/main/java/com/crm/dict/domain/entity/DictGroup.java)
|
|
|
|
|
- [DictItem.java](file://crm-dict/src/main/java/com/crm/dict/domain/entity/DictItem.java)
|
|
|
|
|
- [DictGroupServiceImpl.java](file://crm-dict/src/main/java/com/crm/dict/service/impl/DictGroupServiceImpl.java)
|
|
|
|
|
- [DictItemServiceImpl.java](file://crm-dict/src/main/java/com/crm/dict/service/impl/DictItemServiceImpl.java)
|
|
|
|
|
- [UserListDTO.java](file://crm-auth/src/main/java/com/crm/auth/domain/dto/UserListDTO.java)
|
|
|
|
|
- [RoleDetailVO.java](file://crm-auth/src/main/java/com/crm/auth/domain/dto/RoleDetailVO.java)
|
|
|
|
|
- [UserStatsVO.java](file://crm-auth/src/main/java/com/crm/auth/domain/dto/UserStatsVO.java)
|
|
|
|
|
- [pom.xml](file://pom.xml)
|
|
|
|
|
</cite>
|
|
|
|
|
|
|
|
|
|
## 更新摘要
|
|
|
|
|
**变更内容**
|
|
|
|
|
- 更新了数据传输对象设计规范章节,增加了DictGroupVO和DictItemVO的实践案例
|
|
|
|
|
- 完善了DTO设计模式说明,展示了如何避免直接暴露实体内部结构
|
|
|
|
|
- 增强了BaseDTO设计原则的实际应用示例
|
|
|
|
|
- 补充了VO与Entity分离的最佳实践指导
|
|
|
|
|
|
|
|
|
|
## 目录
|
|
|
|
|
1. [简介](#简介)
|
|
|
|
|
2. [项目结构](#项目结构)
|
|
|
|
|
3. [核心组件](#核心组件)
|
|
|
|
|
4. [架构总览](#架构总览)
|
|
|
|
|
5. [详细组件分析](#详细组件分析)
|
|
|
|
|
6. [依赖分析](#依赖分析)
|
|
|
|
|
7. [性能考虑](#性能考虑)
|
|
|
|
|
8. [故障排查指南](#故障排查指南)
|
|
|
|
|
9. [结论](#结论)
|
|
|
|
|
10. [附录](#附录)
|
|
|
|
|
|
|
|
|
|
## 简介
|
|
|
|
|
本规范面向 CRM 后端多模块工程,统一代码风格、命名约定、包结构、实体与数据传输对象设计、异常与日志规范、注释规范以及 Git 工作流与代码审查流程。目标是通过一致的编码标准提升代码质量、可维护性与团队协作效率。
|
|
|
|
|
|
|
|
|
|
## 项目结构
|
|
|
|
|
本项目采用多模块 Maven 工程,按领域与职责划分:
|
|
|
|
|
- crm-app:应用启动入口与全局配置
|
|
|
|
|
- crm-base:基础能力(通用实体、DTO/Param/Result、安全上下文、数据权限、异常、工具类、MyBatis Plus 配置)
|
|
|
|
|
- crm-auth:认证授权与系统管理(用户、角色、菜单、部门、第三方登录等)
|
|
|
|
|
- crm-file:文件服务(上传、分片、预览、清理任务等)
|
|
|
|
|
- crm-dict:数据字典服务(分组、项管理、引用计数等)
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
graph TB
|
|
|
|
|
subgraph "应用层"
|
|
|
|
|
APP["crm-app<br/>启动与配置"]
|
|
|
|
|
end
|
|
|
|
|
subgraph "业务域"
|
|
|
|
|
AUTH["crm-auth<br/>认证与系统管理"]
|
|
|
|
|
FILE["crm-file<br/>文件服务"]
|
|
|
|
|
DICT["crm-dict<br/>数据字典服务"]
|
|
|
|
|
end
|
|
|
|
|
subgraph "基础能力"
|
|
|
|
|
BASE["crm-base<br/>通用实体/DTO/Param/Result<br/>安全上下文/异常/工具/配置"]
|
|
|
|
|
end
|
|
|
|
|
APP --> AUTH
|
|
|
|
|
APP --> FILE
|
|
|
|
|
APP --> DICT
|
|
|
|
|
AUTH --> BASE
|
|
|
|
|
FILE --> BASE
|
|
|
|
|
DICT --> BASE
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**图示来源**
|
|
|
|
|
- [CrmAppApplication.java](file://crm-app/src/main/java/com/crm/app/CrmAppApplication.java)
|
|
|
|
|
- [AuthApplication.java](file://crm-auth/src/main/java/com/crm/auth/AuthApplication.java)
|
|
|
|
|
- [pom.xml](file://pom.xml)
|
|
|
|
|
|
|
|
|
|
**章节来源**
|
|
|
|
|
- [CrmAppApplication.java](file://crm-app/src/main/java/com/crm/app/CrmAppApplication.java)
|
|
|
|
|
- [AuthApplication.java](file://crm-auth/src/main/java/com/crm/auth/AuthApplication.java)
|
|
|
|
|
- [pom.xml](file://pom.xml)
|
|
|
|
|
|
|
|
|
|
## 核心组件
|
|
|
|
|
- 通用实体基类与数据所有权
|
|
|
|
|
- BaseEntity:统一审计字段(如创建时间、更新时间等),配合元数据填充处理器自动落库
|
|
|
|
|
- OwnedEntity:在 BaseEntity 基础上增加数据归属字段,结合数据可见性上下文实现行级数据权限控制
|
|
|
|
|
- 数据传输对象
|
|
|
|
|
- BaseDTO:通用 DTO 基类,用于接口返回或跨层传输
|
|
|
|
|
- BaseParam:通用请求参数基类,用于入参校验与封装
|
|
|
|
|
- Result/PageResult:统一响应包装与分页结果
|
|
|
|
|
- 安全与数据权限
|
|
|
|
|
- LoginUser/SecurityUtils:当前登录用户上下文获取
|
|
|
|
|
- DataOwnership/DataScope/DataScopeLevel/DataScopeHelper/DataVisibilityContext:数据权限注解、级别、辅助方法与上下文
|
|
|
|
|
- 异常体系
|
|
|
|
|
- BusinessErrorException/MissingParameterException/PermissionErrorException/ResourceNotExistException:业务、参数、权限、资源不存在等异常类型
|
|
|
|
|
- GlobalExceptionHandlerAdvice:全局异常处理,统一错误码与消息
|
|
|
|
|
- MyBatis Plus 增强
|
|
|
|
|
- MetaObjectFillHandler:自动填充审计字段
|
|
|
|
|
- SnowflakeIdWorker/CustomIdGenerator:分布式 ID 生成策略
|
|
|
|
|
- MybatisPlusConfig:MP 配置注入
|
|
|
|
|
|
|
|
|
|
**章节来源**
|
|
|
|
|
- [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java)
|
|
|
|
|
- [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java)
|
|
|
|
|
- [BaseDTO.java](file://crm-base/src/main/java/com/crm/base/domain/dto/BaseDTO.java)
|
|
|
|
|
- [BaseParam.java](file://crm-base/src/main/java/com/crm/base/domain/param/BaseParam.java)
|
|
|
|
|
- [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java)
|
|
|
|
|
- [PageResult.java](file://crm-base/src/main/java/com/crm/base/domain/result/PageResult.java)
|
|
|
|
|
- [ResultCodeEnum.java](file://crm-base/src/main/java/com/crm/base/domain/result/ResultCodeEnum.java)
|
|
|
|
|
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
|
|
|
|
|
- [BusinessErrorException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/BusinessErrorException.java)
|
|
|
|
|
- [MissingParameterException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/MissingParameterException.java)
|
|
|
|
|
- [PermissionErrorException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/PermissionErrorException.java)
|
|
|
|
|
- [ResourceNotExistException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/ResourceNotExistException.java)
|
|
|
|
|
- [DataOwnership.java](file://crm-base/src/main/java/com/crm/base/security/DataOwnership.java)
|
|
|
|
|
- [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java)
|
|
|
|
|
- [DataScopeLevel.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeLevel.java)
|
|
|
|
|
- [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java)
|
|
|
|
|
- [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java)
|
|
|
|
|
- [LoginUser.java](file://crm-base/src/main/java/com/crm/base/security/LoginUser.java)
|
|
|
|
|
- [SecurityUtils.java](file://crm-base/src/main/java/com/crm/base/security/SecurityUtils.java)
|
|
|
|
|
- [MetaObjectFillHandler.java](file://crm-base/src/main/java/com/crm/base/config/MetaObjectFillHandler.java)
|
|
|
|
|
- [SnowflakeIdWorker.java](file://crm-base/src/main/java/com/crm/base/config/SnowflakeIdWorker.java)
|
|
|
|
|
- [CustomIdGenerator.java](file://crm-base/src/main/java/com/crm/base/config/CustomIdGenerator.java)
|
|
|
|
|
- [MybatisPlusConfig.java](file://crm-base/src/main/java/com/crm/base/config/MybatisPlusConfig.java)
|
|
|
|
|
|
|
|
|
|
## 架构总览
|
|
|
|
|
分层与边界:
|
|
|
|
|
- 表现层(Controller):接收请求、参数校验、调用 Service
|
|
|
|
|
- 服务层(Service):业务编排、事务边界、调用 Mapper 与外部客户端
|
|
|
|
|
- 持久层(Mapper):数据访问,基于 MyBatis Plus
|
|
|
|
|
- 安全与数据权限:过滤器/拦截器 + 注解 + 上下文,贯穿 Controller -> Service -> Mapper
|
|
|
|
|
- 基础设施:统一异常、日志追踪、ID 生成、分页、枚举、工具类
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
participant Client as "客户端"
|
|
|
|
|
participant AuthCtrl as "认证控制器"
|
|
|
|
|
participant TokenSvc as "令牌服务"
|
|
|
|
|
participant AuthService as "认证服务"
|
|
|
|
|
participant DB as "数据库"
|
|
|
|
|
Client->>AuthCtrl : "POST /auth/login"
|
|
|
|
|
AuthCtrl->>AuthService : "验证用户名密码"
|
|
|
|
|
AuthService->>DB : "查询用户信息"
|
|
|
|
|
DB-->>AuthService : "用户记录"
|
|
|
|
|
AuthService-->>AuthCtrl : "用户信息"
|
|
|
|
|
AuthCtrl->>TokenSvc : "签发JWT"
|
|
|
|
|
TokenSvc-->>AuthCtrl : "令牌"
|
|
|
|
|
AuthCtrl-->>Client : "登录成功响应"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**图示来源**
|
|
|
|
|
- [AuthController.java](file://crm-auth/src/main/java/com/crm/auth/controller/AuthController.java)
|
|
|
|
|
- [AuthService.java](file://crm-auth/src/main/java/com/crm/auth/service/IAuthService.java)
|
|
|
|
|
- [AuthServiceImpl.java](file://crm-auth/src/main/java/com/crm/auth/service/impl/AuthServiceImpl.java)
|
|
|
|
|
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
|
|
|
|
|
|
|
|
|
|
## 详细组件分析
|
|
|
|
|
|
|
|
|
|
### 实体类设计规范(BaseEntity 与 OwnedEntity)
|
|
|
|
|
- BaseEntity
|
|
|
|
|
- 职责:提供统一的审计字段(如创建人、创建时间、更新人、更新时间等)
|
|
|
|
|
- 使用方式:所有持久化实体继承 BaseEntity;配合元数据填充处理器自动设置审计字段
|
|
|
|
|
- 复杂度:O(1) 字段赋值,填充发生在插入/更新前
|
|
|
|
|
- OwnedEntity
|
|
|
|
|
- 职责:在 BaseEntity 基础上增加"数据所有者"字段,用于数据隔离与权限过滤
|
|
|
|
|
- 使用方式:需要数据归属控制的实体继承 OwnedEntity;结合 DataOwnership/DataScope 注解与上下文进行行级过滤
|
|
|
|
|
- 注意:避免在批量操作中遗漏数据所有者,确保上下文正确设置
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
classDiagram
|
|
|
|
|
class BaseEntity {
|
|
|
|
|
+审计字段集合
|
|
|
|
|
+默认填充逻辑
|
|
|
|
|
}
|
|
|
|
|
class OwnedEntity {
|
|
|
|
|
+数据所有者字段
|
|
|
|
|
+数据可见性关联
|
|
|
|
|
}
|
|
|
|
|
BaseEntity <|-- OwnedEntity : "继承"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**图示来源**
|
|
|
|
|
- [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java)
|
|
|
|
|
- [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java)
|
|
|
|
|
|
|
|
|
|
**章节来源**
|
|
|
|
|
- [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java)
|
|
|
|
|
- [OwnedEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/OwnedEntity.java)
|
|
|
|
|
- [MetaObjectFillHandler.java](file://crm-base/src/main/java/com/crm/base/config/MetaObjectFillHandler.java)
|
|
|
|
|
|
|
|
|
|
### 数据传输对象设计(DTO、Param、Result)
|
|
|
|
|
|
|
|
|
|
**更新** 数据传输对象设计规范得到实践验证,通过 DictGroupVO 和 DictItemVO 的重构展示了如何避免直接暴露实体内部结构,遵循了 BaseDTO 的设计原则。
|
|
|
|
|
|
|
|
|
|
- BaseDTO
|
|
|
|
|
- 用途:作为通用 DTO 基类,承载接口返回数据或跨层传输数据
|
|
|
|
|
- 建议:仅包含必要字段,避免直接暴露实体内部结构
|
|
|
|
|
- 特性:支持 Entity 到 DTO 的自动转换,包含序列化支持和状态字段
|
|
|
|
|
- BaseParam
|
|
|
|
|
- 用途:作为通用请求参数基类,承载入参校验与封装
|
|
|
|
|
- 建议:与表单/查询参数一一对应,必要时使用分组校验
|
|
|
|
|
- 特性:内置分页参数、关键字搜索、排序功能
|
|
|
|
|
- Result/PageResult
|
|
|
|
|
- 用途:统一 API 响应包装,包含状态码、消息、数据体;PageResult 扩展分页信息
|
|
|
|
|
- 建议:保持响应结构一致,便于前端解析与错误处理
|
|
|
|
|
- 枚举与常量
|
|
|
|
|
- ResultCodeEnum:统一错误码定义,避免硬编码
|
|
|
|
|
- 业务枚举:集中定义于 domain/enums 包下,保证一致性
|
|
|
|
|
|
|
|
|
|
#### 实践案例:DictGroupVO 和 DictItemVO
|
|
|
|
|
|
|
|
|
|
DictGroupVO 和 DictItemVO 是数据传输对象设计规范的优秀实践案例:
|
|
|
|
|
|
|
|
|
|
**DictGroupVO** - 字典分组视图对象
|
|
|
|
|
- 独立字段设计:不继承实体,只暴露前端需要的业务字段
|
|
|
|
|
- 排除敏感字段:不包含审计字段(creatorId/updaterId/updateTime/deleted)和软删内部字段(deleteKey)
|
|
|
|
|
- 业务增强字段:包含 itemCount(分组下未删除的字典项数量)
|
|
|
|
|
- 适用场景:分页列表展示
|
|
|
|
|
|
|
|
|
|
**DictItemVO** - 字典项视图对象
|
|
|
|
|
- 独立字段设计:不继承实体,只暴露前端需要的业务字段
|
|
|
|
|
- 排除敏感字段:不包含审计字段和软删内部字段
|
|
|
|
|
- 业务增强字段:包含 groupName(所属分组名称)、isDefault(是否为分组默认项)、referenced(是否被业务引用)、effectiveSelectable(是否有效可选)
|
|
|
|
|
- 实时数据:referenced 字段读取实时引用计数,不进入缓存
|
|
|
|
|
- 适用场景:分页列表展示
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
classDiagram
|
|
|
|
|
class BaseEntity {
|
|
|
|
|
+id : Long
|
|
|
|
|
+creatorId : String
|
|
|
|
|
+createTime : LocalDateTime
|
|
|
|
|
+updaterId : String
|
|
|
|
|
+updateTime : LocalDateTime
|
|
|
|
|
+deleted : Boolean
|
|
|
|
|
}
|
|
|
|
|
class DictGroup {
|
|
|
|
|
+name : String
|
|
|
|
|
+code : String
|
|
|
|
|
+sortNo : Integer
|
|
|
|
|
+status : Integer
|
|
|
|
|
+description : String
|
|
|
|
|
+builtin : Boolean
|
|
|
|
|
+deleteKey : Long
|
|
|
|
|
}
|
|
|
|
|
class DictItem {
|
|
|
|
|
+groupId : Long
|
|
|
|
|
+name : String
|
|
|
|
|
+code : String
|
|
|
|
|
+value : String
|
|
|
|
|
+sortNo : Integer
|
|
|
|
|
+status : Integer
|
|
|
|
|
+description : String
|
|
|
|
|
+builtin : Boolean
|
|
|
|
|
+deleteKey : Long
|
|
|
|
|
}
|
|
|
|
|
class DictGroupVO {
|
|
|
|
|
+id : Long
|
|
|
|
|
+name : String
|
|
|
|
|
+code : String
|
|
|
|
|
+sortNo : Integer
|
|
|
|
|
+status : Integer
|
|
|
|
|
+description : String
|
|
|
|
|
+builtin : Boolean
|
|
|
|
|
+createTime : LocalDateTime
|
|
|
|
|
+itemCount : Long
|
|
|
|
|
}
|
|
|
|
|
class DictItemVO {
|
|
|
|
|
+id : Long
|
|
|
|
|
+groupId : Long
|
|
|
|
|
+name : String
|
|
|
|
|
+code : String
|
|
|
|
|
+value : String
|
|
|
|
|
+sortNo : Integer
|
|
|
|
|
+status : Integer
|
|
|
|
|
+description : String
|
|
|
|
|
+builtin : Boolean
|
|
|
|
|
+createTime : LocalDateTime
|
|
|
|
|
+groupName : String
|
|
|
|
|
+isDefault : Boolean
|
|
|
|
|
+referenced : Boolean
|
|
|
|
|
+effectiveSelectable : Boolean
|
|
|
|
|
}
|
|
|
|
|
BaseEntity <|-- DictGroup : "继承"
|
|
|
|
|
BaseEntity <|-- DictItem : "继承"
|
|
|
|
|
DictGroup --> DictGroupVO : "转换为"
|
|
|
|
|
DictItem --> DictItemVO : "转换为"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**图示来源**
|
|
|
|
|
- [BaseEntity.java](file://crm-base/src/main/java/com/crm/base/domain/entity/BaseEntity.java)
|
|
|
|
|
- [DictGroup.java](file://crm-dict/src/main/java/com/crm/dict/domain/entity/DictGroup.java)
|
|
|
|
|
- [DictItem.java](file://crm-dict/src/main/java/com/crm/dict/domain/entity/DictItem.java)
|
|
|
|
|
- [DictGroupVO.java](file://crm-dict/src/main/java/com/crm/dict/domain/dto/DictGroupVO.java)
|
|
|
|
|
- [DictItemVO.java](file://crm-dict/src/main/java/com/crm/dict/domain/dto/DictItemVO.java)
|
|
|
|
|
|
|
|
|
|
#### DTO 转换机制
|
|
|
|
|
|
|
|
|
|
服务层使用 toDTO 方法进行实体到 DTO 的转换:
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
// DictGroupServiceImpl 中的使用示例
|
|
|
|
|
PageResult<DictGroupVO> result = new PageResult<>(page)
|
|
|
|
|
.convert(g -> g.toDTO(DictGroupVO::new));
|
|
|
|
|
|
|
|
|
|
// DictItemServiceImpl 中的使用示例
|
|
|
|
|
PageResult<DictItemVO> result = new PageResult<>(page)
|
|
|
|
|
.convert(i -> i.toDTO(DictItemVO::new));
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**章节来源**
|
|
|
|
|
- [BaseDTO.java](file://crm-base/src/main/java/com/crm/base/domain/dto/BaseDTO.java)
|
|
|
|
|
- [BaseParam.java](file://crm-base/src/main/java/com/crm/base/domain/param/BaseParam.java)
|
|
|
|
|
- [Result.java](file://crm-base/src/main/java/com/crm/base/domain/result/Result.java)
|
|
|
|
|
- [PageResult.java](file://crm-base/src/main/java/com/crm/base/domain/result/PageResult.java)
|
|
|
|
|
- [ResultCodeEnum.java](file://crm-base/src/main/java/com/crm/base/domain/result/ResultCodeEnum.java)
|
|
|
|
|
- [DictGroupVO.java](file://crm-dict/src/main/java/com/crm/dict/domain/dto/DictGroupVO.java)
|
|
|
|
|
- [DictItemVO.java](file://crm-dict/src/main/java/com/crm/dict/domain/dto/DictItemVO.java)
|
|
|
|
|
- [DictGroupServiceImpl.java](file://crm-dict/src/main/java/com/crm/dict/service/impl/DictGroupServiceImpl.java)
|
|
|
|
|
- [DictItemServiceImpl.java](file://crm-dict/src/main/java/com/crm/dict/service/impl/DictItemServiceImpl.java)
|
|
|
|
|
|
|
|
|
|
### 认证与鉴权流程
|
|
|
|
|
- 登录流程
|
|
|
|
|
- 控制器接收登录参数,调用认证服务验证用户
|
|
|
|
|
- 认证成功后由令牌服务签发 JWT,并返回给客户端
|
|
|
|
|
- 鉴权流程
|
|
|
|
|
- 请求进入时通过 JWT 过滤器解析令牌,构建登录用户上下文
|
|
|
|
|
- 数据权限通过 DataScope 注解与 DataOwnership 注解共同作用,结合 DataVisibilityContext 进行行级过滤
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
sequenceDiagram
|
|
|
|
|
participant Client as "客户端"
|
|
|
|
|
participant Filter as "JWT过滤器"
|
|
|
|
|
participant Ctrl as "业务控制器"
|
|
|
|
|
participant Svc as "业务服务"
|
|
|
|
|
participant MP as "MyBatis Plus"
|
|
|
|
|
Client->>Filter : "携带JWT的请求"
|
|
|
|
|
Filter->>Filter : "解析令牌与用户上下文"
|
|
|
|
|
Filter-->>Ctrl : "放行并注入上下文"
|
|
|
|
|
Ctrl->>Svc : "执行业务方法"
|
|
|
|
|
Svc->>MP : "执行SQL带数据权限条件"
|
|
|
|
|
MP-->>Svc : "返回受控数据"
|
|
|
|
|
Svc-->>Ctrl : "业务结果"
|
|
|
|
|
Ctrl-->>Client : "统一响应"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**图示来源**
|
|
|
|
|
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
|
|
|
|
|
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
|
|
|
|
|
- [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java)
|
|
|
|
|
- [DataOwnership.java](file://crm-base/src/main/java/com/crm/base/security/DataOwnership.java)
|
|
|
|
|
- [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java)
|
|
|
|
|
- [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java)
|
|
|
|
|
|
|
|
|
|
**章节来源**
|
|
|
|
|
- [JwtAuthenticationFilter.java](file://crm-auth/src/main/java/com/crm/auth/security/JwtAuthenticationFilter.java)
|
|
|
|
|
- [TokenService.java](file://crm-auth/src/main/java/com/crm/auth/security/TokenService.java)
|
|
|
|
|
- [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java)
|
|
|
|
|
- [DataOwnership.java](file://crm-base/src/main/java/com/crm/base/security/DataOwnership.java)
|
|
|
|
|
- [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java)
|
|
|
|
|
- [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java)
|
|
|
|
|
|
|
|
|
|
### 文件服务组件
|
|
|
|
|
- FileController:提供文件上传、下载、预览等接口
|
|
|
|
|
- IFileInfoService/FileInfoServiceImpl:文件信息管理与业务逻辑
|
|
|
|
|
- FileApiImpl:对外文件能力抽象实现
|
|
|
|
|
- KkFileViewClient:第三方文件预览客户端
|
|
|
|
|
- OrphanChunkCleanupTask:定时清理孤立分片任务
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
classDiagram
|
|
|
|
|
class FileController {
|
|
|
|
|
+上传接口
|
|
|
|
|
+下载接口
|
|
|
|
|
+预览接口
|
|
|
|
|
}
|
|
|
|
|
class IFileInfoService {
|
|
|
|
|
+文件信息管理
|
|
|
|
|
}
|
|
|
|
|
class FileInfoServiceImpl {
|
|
|
|
|
+实现文件业务逻辑
|
|
|
|
|
}
|
|
|
|
|
class FileApiImpl {
|
|
|
|
|
+对外API实现
|
|
|
|
|
}
|
|
|
|
|
class KkFileViewClient {
|
|
|
|
|
+预览客户端
|
|
|
|
|
}
|
|
|
|
|
class OrphanChunkCleanupTask {
|
|
|
|
|
+清理任务
|
|
|
|
|
}
|
|
|
|
|
FileController --> IFileInfoService : "调用"
|
|
|
|
|
IFileInfoService <|.. FileInfoServiceImpl : "实现"
|
|
|
|
|
FileApiImpl --> IFileInfoService : "依赖"
|
|
|
|
|
FileController --> KkFileViewClient : "预览"
|
|
|
|
|
OrphanChunkCleanupTask --> IFileInfoService : "清理"
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**图示来源**
|
|
|
|
|
- [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java)
|
|
|
|
|
- [IFileInfoService.java](file://crm-file/src/main/java/com/crm/file/service/IFileInfoService.java)
|
|
|
|
|
- [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java)
|
|
|
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
|
|
|
|
- [KkFileViewClient.java](file://crm-file/src/main/java/com/crm/file/service/KkFileViewClient.java)
|
|
|
|
|
- [OrphanChunkCleanupTask.java](file://crm-file/src/main/java/com/crm/file/task/OrphanChunkCleanupTask.java)
|
|
|
|
|
|
|
|
|
|
**章节来源**
|
|
|
|
|
- [FileController.java](file://crm-file/src/main/java/com/crm/file/controller/FileController.java)
|
|
|
|
|
- [IFileInfoService.java](file://crm-file/src/main/java/com/crm/file/service/IFileInfoService.java)
|
|
|
|
|
- [FileInfoServiceImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileInfoServiceImpl.java)
|
|
|
|
|
- [FileApiImpl.java](file://crm-file/src/main/java/com/crm/file/service/impl/FileApiImpl.java)
|
|
|
|
|
- [KkFileViewClient.java](file://crm-file/src/main/java/com/crm/file/service/KkFileViewClient.java)
|
|
|
|
|
- [OrphanChunkCleanupTask.java](file://crm-file/src/main/java/com/crm/file/task/OrphanChunkCleanupTask.java)
|
|
|
|
|
|
|
|
|
|
### 复杂逻辑流程图(数据权限过滤)
|
|
|
|
|
```mermaid
|
|
|
|
|
flowchart TD
|
|
|
|
|
Start(["进入受控方法"]) --> CheckAnno["检查是否标注数据权限注解"]
|
|
|
|
|
CheckAnno --> |是| BuildScope["构建数据范围条件"]
|
|
|
|
|
CheckAnno --> |否| Skip["跳过数据权限过滤"]
|
|
|
|
|
BuildScope --> ApplyScope["应用到查询条件"]
|
|
|
|
|
ApplyScope --> ExecQuery["执行数据库查询"]
|
|
|
|
|
Skip --> ExecQuery
|
|
|
|
|
ExecQuery --> Return["返回受控结果"]
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**图示来源**
|
|
|
|
|
- [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java)
|
|
|
|
|
- [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java)
|
|
|
|
|
- [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java)
|
|
|
|
|
|
|
|
|
|
**章节来源**
|
|
|
|
|
- [DataScope.java](file://crm-base/src/main/java/com/crm/base/annotation/DataScope.java)
|
|
|
|
|
- [DataScopeHelper.java](file://crm-base/src/main/java/com/crm/base/security/DataScopeHelper.java)
|
|
|
|
|
- [DataVisibilityContext.java](file://crm-base/src/main/java/com/crm/base/security/DataVisibilityContext.java)
|
|
|
|
|
|
|
|
|
|
## 依赖分析
|
|
|
|
|
模块间依赖关系清晰,遵循"上层依赖下层"的原则:
|
|
|
|
|
- crm-app 依赖 crm-auth、crm-file 与 crm-dict
|
|
|
|
|
- crm-auth、crm-file 与 crm-dict 均依赖 crm-base
|
|
|
|
|
- 各模块内按 controller -> service -> mapper 分层依赖
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
graph LR
|
|
|
|
|
APP["crm-app"] --> AUTH["crm-auth"]
|
|
|
|
|
APP --> FILE["crm-file"]
|
|
|
|
|
APP --> DICT["crm-dict"]
|
|
|
|
|
AUTH --> BASE["crm-base"]
|
|
|
|
|
FILE --> BASE
|
|
|
|
|
DICT --> BASE
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
**图示来源**
|
|
|
|
|
- [pom.xml](file://pom.xml)
|
|
|
|
|
|
|
|
|
|
**章节来源**
|
|
|
|
|
- [pom.xml](file://pom.xml)
|
|
|
|
|
|
|
|
|
|
## 性能考虑
|
|
|
|
|
- 分布式 ID:使用雪花算法生成唯一 ID,避免自增主键在高并发下的瓶颈
|
|
|
|
|
- 元数据填充:通过 MyBatis Plus 的元数据填充减少手动赋值开销
|
|
|
|
|
- 数据权限:尽量将数据权限条件下推到 SQL 层,减少内存过滤
|
|
|
|
|
- 缓存与限流:对热点数据(如部门树、菜单)考虑引入缓存;对外部调用(如第三方登录、文件预览)增加超时与重试策略
|
|
|
|
|
- 分页查询:合理使用分页,避免一次性加载大量数据
|
|
|
|
|
- DTO 优化:通过独立的 VO 对象减少数据传输量,避免暴露不必要的实体字段
|
|
|
|
|
|
|
|
|
|
## 故障排查指南
|
|
|
|
|
- 全局异常处理
|
|
|
|
|
- 统一捕获业务异常、参数异常、权限异常与资源不存在异常
|
|
|
|
|
- 返回统一 Result 结构,便于前端处理
|
|
|
|
|
- 常见异常定位
|
|
|
|
|
- 参数缺失:检查 BaseParam 校验规则与入参映射
|
|
|
|
|
- 权限不足:检查 DataScope/DataOwnership 注解与上下文设置
|
|
|
|
|
- 资源不存在:检查查询条件与数据归属
|
|
|
|
|
- 日志追踪
|
|
|
|
|
- TraceIdFilter:为每个请求生成追踪 ID,贯穿日志链路
|
|
|
|
|
- 建议在关键路径打印必要上下文,避免泄露敏感信息
|
|
|
|
|
|
|
|
|
|
**章节来源**
|
|
|
|
|
- [GlobalExceptionHandlerAdvice.java](file://crm-base/src/main/java/com/crm/base/advice/GlobalExceptionHandlerAdvice.java)
|
|
|
|
|
- [BusinessErrorException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/BusinessErrorException.java)
|
|
|
|
|
- [MissingParameterException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/MissingParameterException.java)
|
|
|
|
|
- [PermissionErrorException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/PermissionErrorException.java)
|
|
|
|
|
- [ResourceNotExistException.java](file://crm-base/src/main/java/com/crm/base/domain/exception/ResourceNotExistException.java)
|
|
|
|
|
- [TraceIdFilter.java](file://crm-base/src/main/java/com/crm/base/filter/TraceIdFilter.java)
|
|
|
|
|
|
|
|
|
|
## 结论
|
|
|
|
|
本规范从代码风格、命名约定、包结构到实体与 DTO 设计、异常与日志、Git 工作流与代码审查,提供了完整的开发标准。通过 DictGroupVO 和 DictItemVO 的实践案例,进一步验证了数据传输对象设计规范的有效性。遵循这些规范有助于提升代码质量、降低协作成本,并为后续扩展与维护奠定基础。
|
|
|
|
|
|
|
|
|
|
## 附录
|
|
|
|
|
|
|
|
|
|
### 代码风格与命名约定
|
|
|
|
|
- 类名:大驼峰,名词或名词短语(如 UserService、FileInfo)
|
|
|
|
|
- 方法名:小驼峰,动词开头(如 getUserById、uploadFile)
|
|
|
|
|
- 常量:全大写加下划线(如 MAX_RETRY_COUNT)
|
|
|
|
|
- 包名:全小写,按功能划分(controller、service、mapper、domain、config、security、utils)
|
|
|
|
|
- 字段命名:小驼峰,语义明确,避免缩写歧义
|
|
|
|
|
|
|
|
|
|
### 包结构规范
|
|
|
|
|
- controller:HTTP 接口层,仅做参数校验与调用服务
|
|
|
|
|
- service:业务逻辑层,事务边界与方法编排
|
|
|
|
|
- mapper:数据访问层,基于 MyBatis Plus
|
|
|
|
|
- domain:
|
|
|
|
|
- entity:持久化实体
|
|
|
|
|
- dto:数据传输对象
|
|
|
|
|
- param:请求参数
|
|
|
|
|
- enums:枚举定义
|
|
|
|
|
- config:配置类(Spring、MyBatis Plus、Redis、Knife4j 等)
|
|
|
|
|
- security:安全相关(过滤器、拦截器、上下文、工具)
|
|
|
|
|
- utils:通用工具类
|
|
|
|
|
- advice:全局异常处理
|
|
|
|
|
- filter:过滤器(如追踪 ID)
|
|
|
|
|
|
|
|
|
|
### 实体类设计规范
|
|
|
|
|
- 所有实体继承 BaseEntity,获得审计字段
|
|
|
|
|
- 需要数据归属控制的实体继承 OwnedEntity
|
|
|
|
|
- 避免在实体中放置业务逻辑,保持 POJO 特性
|
|
|
|
|
- 字段注释完整,便于文档生成与理解
|
|
|
|
|
|
|
|
|
|
### DTO、Param、Result 设计模式
|
|
|
|
|
|
|
|
|
|
**更新** 数据传输对象设计模式的实践验证:
|
|
|
|
|
|
|
|
|
|
- **DTO 设计原则**
|
|
|
|
|
- 面向接口输出,精简字段,避免泄露内部结构
|
|
|
|
|
- 独立字段设计,不直接继承实体,按需组合业务字段
|
|
|
|
|
- 排除敏感字段(审计字段、软删字段等)
|
|
|
|
|
- 支持 Entity 到 DTO 的自动转换
|
|
|
|
|
|
|
|
|
|
- **实践案例**
|
|
|
|
|
- DictGroupVO:仅包含前端需要的分组展示字段和业务增强字段
|
|
|
|
|
- DictItemVO:包含字典项基本信息和运行时计算的业务字段
|
|
|
|
|
- UserListDTO:反范式组装,后端批量填充关联数据
|
|
|
|
|
|
|
|
|
|
- **Param 设计原则**
|
|
|
|
|
- 面向输入,严格校验,必要时使用分组校验
|
|
|
|
|
- 继承 BaseParam 获得通用分页和搜索功能
|
|
|
|
|
|
|
|
|
|
- **Result 设计原则**
|
|
|
|
|
- 统一响应格式,便于前端解析
|
|
|
|
|
- PageResult 扩展分页信息
|
|
|
|
|
- 枚举:集中定义,避免魔法值
|
|
|
|
|
|
|
|
|
|
### 异常处理规范
|
|
|
|
|
- 自定义异常分类:业务异常、参数异常、权限异常、资源不存在异常
|
|
|
|
|
- 全局异常处理器统一捕获并转换为 Result
|
|
|
|
|
- 避免吞掉异常,确保错误可追溯
|
|
|
|
|
|
|
|
|
|
### 日志记录规范
|
|
|
|
|
- 使用统一日志框架,区分 INFO/WARN/ERROR
|
|
|
|
|
- 关键路径记录必要上下文,避免敏感信息泄露
|
|
|
|
|
- 使用 TraceIdFilter 生成的追踪 ID 串联日志
|
|
|
|
|
|
|
|
|
|
### 注释编写规范
|
|
|
|
|
- 类与方法必须有清晰注释,说明职责、参数、返回值与异常
|
|
|
|
|
- 复杂逻辑添加行内注释,解释关键步骤
|
|
|
|
|
- 枚举与常量需有含义明确的描述
|
|
|
|
|
|
|
|
|
|
### Git 提交信息规范
|
|
|
|
|
- 格式:<type>(<scope>): <subject>
|
|
|
|
|
- type:feat、fix、docs、style、refactor、test、chore
|
|
|
|
|
- scope:模块或功能范围(如 auth、file、base、dict)
|
|
|
|
|
- subject:简洁明了,不超过 50 字符
|
|
|
|
|
|
|
|
|
|
### 分支管理策略
|
|
|
|
|
- main:稳定版本,仅接受合并请求
|
|
|
|
|
- develop:开发主干,日常集成
|
|
|
|
|
- feature/*:功能分支,完成后合并至 develop
|
|
|
|
|
- hotfix/*:热修复分支,紧急修复后合并至 main 与 develop
|
|
|
|
|
|
|
|
|
|
### 代码审查流程
|
|
|
|
|
- 提交前自检:编译通过、单元测试覆盖、符合规范
|
|
|
|
|
- 发起 MR/PR:填写变更说明与影响范围
|
|
|
|
|
- 审查要点:逻辑正确性、性能、安全性、可维护性
|
|
|
|
|
- 通过后合并:确保 CI 通过且无冲突
|