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.

627 lines
31 KiB

1 month ago
# 开发规范
<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)
1 month ago
- [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)
1 month ago
- [pom.xml](file://pom.xml)
</cite>
1 month ago
## 更新摘要
**变更内容**
- 更新了数据传输对象设计规范章节,增加了DictGroupVO和DictItemVO的实践案例
- 完善了DTO设计模式说明,展示了如何避免直接暴露实体内部结构
- 增强了BaseDTO设计原则的实际应用示例
- 补充了VO与Entity分离的最佳实践指导
1 month ago
## 目录
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:文件服务(上传、分片、预览、清理任务等)
1 month ago
- crm-dict:数据字典服务(分组、项管理、引用计数等)
1 month ago
```mermaid
graph TB
subgraph "应用层"
APP["crm-app<br/>启动与配置"]
end
subgraph "业务域"
AUTH["crm-auth<br/>认证与系统管理"]
FILE["crm-file<br/>文件服务"]
1 month ago
DICT["crm-dict<br/>数据字典服务"]
1 month ago
end
subgraph "基础能力"
BASE["crm-base<br/>通用实体/DTO/Param/Result<br/>安全上下文/异常/工具/配置"]
end
APP --> AUTH
APP --> FILE
1 month ago
APP --> DICT
1 month ago
AUTH --> BASE
FILE --> BASE
1 month ago
DICT --> BASE
1 month ago
```
**图示来源**
- [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
1 month ago
- 职责:在 BaseEntity 基础上增加"数据所有者"字段,用于数据隔离与权限过滤
1 month ago
- 使用方式:需要数据归属控制的实体继承 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)
1 month ago
**更新** 数据传输对象设计规范得到实践验证,通过 DictGroupVO 和 DictItemVO 的重构展示了如何避免直接暴露实体内部结构,遵循了 BaseDTO 的设计原则。
1 month ago
- BaseDTO
- 用途:作为通用 DTO 基类,承载接口返回数据或跨层传输数据
- 建议:仅包含必要字段,避免直接暴露实体内部结构
1 month ago
- 特性:支持 Entity 到 DTO 的自动转换,包含序列化支持和状态字段
1 month ago
- BaseParam
- 用途:作为通用请求参数基类,承载入参校验与封装
- 建议:与表单/查询参数一一对应,必要时使用分组校验
1 month ago
- 特性:内置分页参数、关键字搜索、排序功能
1 month ago
- Result/PageResult
- 用途:统一 API 响应包装,包含状态码、消息、数据体;PageResult 扩展分页信息
- 建议:保持响应结构一致,便于前端解析与错误处理
- 枚举与常量
- ResultCodeEnum:统一错误码定义,避免硬编码
- 业务枚举:集中定义于 domain/enums 包下,保证一致性
1 month ago
#### 实践案例:DictGroupVO 和 DictItemVO
DictGroupVO 和 DictItemVO 是数据传输对象设计规范的优秀实践案例:
**DictGroupVO** - 字典分组视图对象
- 独立字段设计:不继承实体,只暴露前端需要的业务字段
- 排除敏感字段:不包含审计字段(creatorId/updaterId/updateTime/deleted)和软删内部字段(deleteKey)
- 业务增强字段:包含 itemCount(分组下未删除的字典项数量)
- 适用场景:分页列表展示
**DictItemVO** - 字典项视图对象
- 独立字段设计:不继承实体,只暴露前端需要的业务字段
- 排除敏感字段:不包含审计字段和软删内部字段
- 业务增强字段:包含 groupName(所属分组名称)、isDefault(是否为分组默认项)、referenced(是否被业务引用)、effectiveSelectable(是否有效可选)
- 实时数据:referenced 字段读取实时引用计数,不进入缓存
- 适用场景:分页列表展示
1 month ago
```mermaid
classDiagram
1 month ago
class BaseEntity {
+id : Long
+creatorId : String
+createTime : LocalDateTime
+updaterId : String
+updateTime : LocalDateTime
+deleted : Boolean
1 month ago
}
1 month ago
class DictGroup {
+name : String
+code : String
+sortNo : Integer
+status : Integer
+description : String
+builtin : Boolean
+deleteKey : Long
1 month ago
}
1 month ago
class DictItem {
+groupId : Long
+name : String
+code : String
+value : String
+sortNo : Integer
+status : Integer
+description : String
+builtin : Boolean
+deleteKey : Long
1 month ago
}
1 month ago
class DictGroupVO {
+id : Long
+name : String
+code : String
+sortNo : Integer
+status : Integer
+description : String
+builtin : Boolean
+createTime : LocalDateTime
+itemCount : Long
1 month ago
}
1 month ago
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
1 month ago
}
1 month ago
BaseEntity <|-- DictGroup : "继承"
BaseEntity <|-- DictItem : "继承"
DictGroup --> DictGroupVO : "转换为"
DictItem --> DictItemVO : "转换为"
1 month ago
```
**图示来源**
1 month ago
- [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));
```
1 month ago
**章节来源**
- [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)
1 month ago
- [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)
1 month ago
### 认证与鉴权流程
- 登录流程
- 控制器接收登录参数,调用认证服务验证用户
- 认证成功后由令牌服务签发 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)
## 依赖分析
1 month ago
模块间依赖关系清晰,遵循"上层依赖下层"的原则:
- crm-app 依赖 crm-auth、crm-file 与 crm-dict
- crm-auth、crm-file 与 crm-dict 均依赖 crm-base
1 month ago
- 各模块内按 controller -> service -> mapper 分层依赖
```mermaid
graph LR
APP["crm-app"] --> AUTH["crm-auth"]
APP --> FILE["crm-file"]
1 month ago
APP --> DICT["crm-dict"]
1 month ago
AUTH --> BASE["crm-base"]
FILE --> BASE
1 month ago
DICT --> BASE
1 month ago
```
**图示来源**
- [pom.xml](file://pom.xml)
**章节来源**
- [pom.xml](file://pom.xml)
## 性能考虑
- 分布式 ID:使用雪花算法生成唯一 ID,避免自增主键在高并发下的瓶颈
- 元数据填充:通过 MyBatis Plus 的元数据填充减少手动赋值开销
- 数据权限:尽量将数据权限条件下推到 SQL 层,减少内存过滤
- 缓存与限流:对热点数据(如部门树、菜单)考虑引入缓存;对外部调用(如第三方登录、文件预览)增加超时与重试策略
- 分页查询:合理使用分页,避免一次性加载大量数据
1 month ago
- DTO 优化:通过独立的 VO 对象减少数据传输量,避免暴露不必要的实体字段
1 month ago
## 故障排查指南
- 全局异常处理
- 统一捕获业务异常、参数异常、权限异常与资源不存在异常
- 返回统一 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)
## 结论
1 month ago
本规范从代码风格、命名约定、包结构到实体与 DTO 设计、异常与日志、Git 工作流与代码审查,提供了完整的开发标准。通过 DictGroupVO 和 DictItemVO 的实践案例,进一步验证了数据传输对象设计规范的有效性。遵循这些规范有助于提升代码质量、降低协作成本,并为后续扩展与维护奠定基础。
1 month ago
## 附录
### 代码风格与命名约定
- 类名:大驼峰,名词或名词短语(如 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 设计模式
1 month ago
**更新** 数据传输对象设计模式的实践验证:
- **DTO 设计原则**
- 面向接口输出,精简字段,避免泄露内部结构
- 独立字段设计,不直接继承实体,按需组合业务字段
- 排除敏感字段(审计字段、软删字段等)
- 支持 Entity 到 DTO 的自动转换
- **实践案例**
- DictGroupVO:仅包含前端需要的分组展示字段和业务增强字段
- DictItemVO:包含字典项基本信息和运行时计算的业务字段
- UserListDTO:反范式组装,后端批量填充关联数据
- **Param 设计原则**
- 面向输入,严格校验,必要时使用分组校验
- 继承 BaseParam 获得通用分页和搜索功能
- **Result 设计原则**
- 统一响应格式,便于前端解析
- PageResult 扩展分页信息
- 枚举:集中定义,避免魔法值
1 month ago
### 异常处理规范
- 自定义异常分类:业务异常、参数异常、权限异常、资源不存在异常
- 全局异常处理器统一捕获并转换为 Result
- 避免吞掉异常,确保错误可追溯
### 日志记录规范
- 使用统一日志框架,区分 INFO/WARN/ERROR
- 关键路径记录必要上下文,避免敏感信息泄露
- 使用 TraceIdFilter 生成的追踪 ID 串联日志
### 注释编写规范
- 类与方法必须有清晰注释,说明职责、参数、返回值与异常
- 复杂逻辑添加行内注释,解释关键步骤
- 枚举与常量需有含义明确的描述
### Git 提交信息规范
- 格式:<type>(<scope>): <subject>
- type:feat、fix、docs、style、refactor、test、chore
1 month ago
- scope:模块或功能范围(如 auth、file、base、dict)
1 month ago
- subject:简洁明了,不超过 50 字符
### 分支管理策略
- main:稳定版本,仅接受合并请求
- develop:开发主干,日常集成
- feature/*:功能分支,完成后合并至 develop
- hotfix/*:热修复分支,紧急修复后合并至 main 与 develop
### 代码审查流程
- 提交前自检:编译通过、单元测试覆盖、符合规范
- 发起 MR/PR:填写变更说明与影响范围
- 审查要点:逻辑正确性、性能、安全性、可维护性
- 通过后合并:确保 CI 通过且无冲突