You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

31 KiB

开发规范

**本文引用的文件** - [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)

更新摘要

变更内容

  • 更新了数据传输对象设计规范章节,增加了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:数据字典服务(分组、项管理、引用计数等)
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
  • AuthApplication.java
  • pom.xml

章节来源

  • CrmAppApplication.java
  • AuthApplication.java
  • 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
  • OwnedEntity.java
  • BaseDTO.java
  • BaseParam.java
  • Result.java
  • PageResult.java
  • ResultCodeEnum.java
  • GlobalExceptionHandlerAdvice.java
  • BusinessErrorException.java
  • MissingParameterException.java
  • PermissionErrorException.java
  • ResourceNotExistException.java
  • DataOwnership.java
  • DataScope.java
  • DataScopeLevel.java
  • DataScopeHelper.java
  • DataVisibilityContext.java
  • LoginUser.java
  • SecurityUtils.java
  • MetaObjectFillHandler.java
  • SnowflakeIdWorker.java
  • CustomIdGenerator.java
  • MybatisPlusConfig.java

架构总览

分层与边界:

  • 表现层(Controller):接收请求、参数校验、调用 Service
  • 服务层(Service):业务编排、事务边界、调用 Mapper 与外部客户端
  • 持久层(Mapper):数据访问,基于 MyBatis Plus
  • 安全与数据权限:过滤器/拦截器 + 注解 + 上下文,贯穿 Controller -> Service -> Mapper
  • 基础设施:统一异常、日志追踪、ID 生成、分页、枚举、工具类
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
  • AuthService.java
  • AuthServiceImpl.java
  • TokenService.java

详细组件分析

实体类设计规范(BaseEntity 与 OwnedEntity)

  • BaseEntity
    • 职责:提供统一的审计字段(如创建人、创建时间、更新人、更新时间等)
    • 使用方式:所有持久化实体继承 BaseEntity;配合元数据填充处理器自动设置审计字段
    • 复杂度:O(1) 字段赋值,填充发生在插入/更新前
  • OwnedEntity
    • 职责:在 BaseEntity 基础上增加"数据所有者"字段,用于数据隔离与权限过滤
    • 使用方式:需要数据归属控制的实体继承 OwnedEntity;结合 DataOwnership/DataScope 注解与上下文进行行级过滤
    • 注意:避免在批量操作中遗漏数据所有者,确保上下文正确设置
classDiagram
class BaseEntity {
+审计字段集合
+默认填充逻辑
}
class OwnedEntity {
+数据所有者字段
+数据可见性关联
}
BaseEntity <|-- OwnedEntity : "继承"

图示来源

  • BaseEntity.java
  • OwnedEntity.java

章节来源

  • BaseEntity.java
  • OwnedEntity.java
  • 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 字段读取实时引用计数,不进入缓存
  • 适用场景:分页列表展示
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
  • DictGroup.java
  • DictItem.java
  • DictGroupVO.java
  • DictItemVO.java

DTO 转换机制

服务层使用 toDTO 方法进行实体到 DTO 的转换:

// 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
  • BaseParam.java
  • Result.java
  • PageResult.java
  • ResultCodeEnum.java
  • DictGroupVO.java
  • DictItemVO.java
  • DictGroupServiceImpl.java
  • DictItemServiceImpl.java

认证与鉴权流程

  • 登录流程
    • 控制器接收登录参数,调用认证服务验证用户
    • 认证成功后由令牌服务签发 JWT,并返回给客户端
  • 鉴权流程
    • 请求进入时通过 JWT 过滤器解析令牌,构建登录用户上下文
    • 数据权限通过 DataScope 注解与 DataOwnership 注解共同作用,结合 DataVisibilityContext 进行行级过滤
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
  • TokenService.java
  • DataScope.java
  • DataOwnership.java
  • DataScopeHelper.java
  • DataVisibilityContext.java

章节来源

  • JwtAuthenticationFilter.java
  • TokenService.java
  • DataScope.java
  • DataOwnership.java
  • DataScopeHelper.java
  • DataVisibilityContext.java

文件服务组件

  • FileController:提供文件上传、下载、预览等接口
  • IFileInfoService/FileInfoServiceImpl:文件信息管理与业务逻辑
  • FileApiImpl:对外文件能力抽象实现
  • KkFileViewClient:第三方文件预览客户端
  • OrphanChunkCleanupTask:定时清理孤立分片任务
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
  • IFileInfoService.java
  • FileInfoServiceImpl.java
  • FileApiImpl.java
  • KkFileViewClient.java
  • OrphanChunkCleanupTask.java

章节来源

  • FileController.java
  • IFileInfoService.java
  • FileInfoServiceImpl.java
  • FileApiImpl.java
  • KkFileViewClient.java
  • OrphanChunkCleanupTask.java

复杂逻辑流程图(数据权限过滤)

flowchart TD
Start(["进入受控方法"]) --> CheckAnno["检查是否标注数据权限注解"]
CheckAnno --> |是| BuildScope["构建数据范围条件"]
CheckAnno --> |否| Skip["跳过数据权限过滤"]
BuildScope --> ApplyScope["应用到查询条件"]
ApplyScope --> ExecQuery["执行数据库查询"]
Skip --> ExecQuery
ExecQuery --> Return["返回受控结果"]

图示来源

  • DataScope.java
  • DataScopeHelper.java
  • DataVisibilityContext.java

章节来源

  • DataScope.java
  • DataScopeHelper.java
  • DataVisibilityContext.java

依赖分析

模块间依赖关系清晰,遵循"上层依赖下层"的原则:

  • crm-app 依赖 crm-auth、crm-file 与 crm-dict
  • crm-auth、crm-file 与 crm-dict 均依赖 crm-base
  • 各模块内按 controller -> service -> mapper 分层依赖
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

章节来源

  • pom.xml

性能考虑

  • 分布式 ID:使用雪花算法生成唯一 ID,避免自增主键在高并发下的瓶颈
  • 元数据填充:通过 MyBatis Plus 的元数据填充减少手动赋值开销
  • 数据权限:尽量将数据权限条件下推到 SQL 层,减少内存过滤
  • 缓存与限流:对热点数据(如部门树、菜单)考虑引入缓存;对外部调用(如第三方登录、文件预览)增加超时与重试策略
  • 分页查询:合理使用分页,避免一次性加载大量数据
  • DTO 优化:通过独立的 VO 对象减少数据传输量,避免暴露不必要的实体字段

故障排查指南

  • 全局异常处理
    • 统一捕获业务异常、参数异常、权限异常与资源不存在异常
    • 返回统一 Result 结构,便于前端处理
  • 常见异常定位
    • 参数缺失:检查 BaseParam 校验规则与入参映射
    • 权限不足:检查 DataScope/DataOwnership 注解与上下文设置
    • 资源不存在:检查查询条件与数据归属
  • 日志追踪
    • TraceIdFilter:为每个请求生成追踪 ID,贯穿日志链路
    • 建议在关键路径打印必要上下文,避免泄露敏感信息

章节来源

  • GlobalExceptionHandlerAdvice.java
  • BusinessErrorException.java
  • MissingParameterException.java
  • PermissionErrorException.java
  • ResourceNotExistException.java
  • 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:feat、fix、docs、style、refactor、test、chore
  • scope:模块或功能范围(如 auth、file、base、dict)
  • subject:简洁明了,不超过 50 字符

分支管理策略

  • main:稳定版本,仅接受合并请求
  • develop:开发主干,日常集成
  • feature/*:功能分支,完成后合并至 develop
  • hotfix/*:热修复分支,紧急修复后合并至 main 与 develop

代码审查流程

  • 提交前自检:编译通过、单元测试覆盖、符合规范
  • 发起 MR/PR:填写变更说明与影响范围
  • 审查要点:逻辑正确性、性能、安全性、可维护性
  • 通过后合并:确保 CI 通过且无冲突