- 添加 Lombok 配置支持 - 完善枚举类和常量定义 - 新增工具类(TraceId、限流、OSS 等) - 添加切面(日志、限流、TraceId) - 更新数据库索引规范(应用层防重) - 登录页面样式优化 - 前后端项目文档补充
7.1 KiB
7.1 KiB
Java 后端开发规范
本项目 Java 后端开发规范,基于 Spring Boot + MyBatis-Plus 技术栈。
JDK 版本要求(重要)
必须使用 JDK 17 进行编译和运行。
如果系统环境变量配置的是 JDK 1.8,请在编译前设置 JAVA_HOME:
# Windows (Git Bash) - 根据实际安装路径调整
export JAVA_HOME="/f/Java/jdk-17"
export PATH="$JAVA_HOME/bin:$PATH"
# 编译项目
mvn clean compile -DskipTests
# 或者在启动时指定
mvn spring-boot:run -Djava.home="/f/Java/jdk-17"
核心原则
- OpenAPI 规范驱动 - 前后端通过接口规范对齐
- 类型安全优先 - 强制类型校验
- 约定大于配置 - 统一代码风格
- 自动化优先 - 能自动化的绝不手动
- 三层架构分离 - Controller、Service、Mapper 职责清晰
技术栈
| 组件 | 技术选型 | 版本 |
|---|---|---|
| 框架 | Spring Boot | 3.2+ |
| 持久层 | MyBatis-Plus | 3.5+ |
| 对象映射 | MapStruct | 1.5+ |
| 数据库 | MySQL | 8.0+ |
| 缓存 | Redis | - |
| 安全 | Spring Security + JWT | - |
| API 文档 | Knife4j | 4.x |
三层架构
| 层级 | 职责 | 数据接收 | 数据返回 |
|---|---|---|---|
| Controller | 接收请求、参数校验、返回响应 | DTO/Request | VO/Response |
| Service | 处理业务逻辑、事务控制 | DTO/Entity | Entity |
| Mapper | 数据库 CRUD 操作 | Entity/条件 | Entity |
核心规范:
- Service↔Mapper 之间只用 Entity,禁止 DTO/VO 转换
- 转换只在 Controller 层发生
- Service 继承
IService<T> - 查询接口默认分页
消除魔法值规范
禁止在代码中使用魔法值,所有状态、类型、常量必须使用枚举定义
- 枚举类存放在
enums包下 - 枚举包含
code和desc字段 - 提供
getCode()、getDesc()、valueOfCode()方法 - 数据库存储
code,代码中使用枚举
ORM 实体类规范
表名命名
t_user_*- 用户模块t_sys_*- 系统模块t_biz_*- 业务模块t_auth_*- 权限模块
审计字段(必填)
所有表必须包含审计字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | BIGINT | 主键(自增) |
| create_by | VARCHAR(50) | 创建人 |
| create_time | DATETIME | 创建时间 |
| update_by | VARCHAR(50) | 更新人 |
| update_time | DATETIME | 更新时间 |
| deleted | TINYINT | 逻辑删除(0-未删除,1-已删除) |
- 审计字段通过 MyBatis-Plus
FieldFill自动填充 - 禁止手动设置审计字段
日志规范
日志语言
所有日志必须使用中文
TraceId 链路追踪
- 使用 MDC 实现 TraceId 链路追踪
- AOP 切面在请求入口生成 TraceId
- 日志格式包含
[%X{traceId}]
环境差异化配置
| 环境 | 日志策略 |
|---|---|
| 开发/测试 | 全量记录(DEBUG 级别) |
| 生产 | 精简记录(INFO/WARN 级别) |
AOP 日志实现
- 拦截 Controller 层所有方法
- 请求日志:TraceId、请求方法、路径、IP、耗时
- 异常日志:TraceId、异常类型、消息、堆栈
统一响应格式
Result<T> {
code: Integer; // 状态码
message: String; // 消息
data: T; // 数据
timestamp: Long; // 时间戳
}
错误码: 200-成功、400-参数错误、401-未授权、403-无权限、404-不存在、500-系统错误
MapStruct 对象映射
- 使用
@Mapper注解定义 Converter 接口 - Entity ↔ VO 转换在 Controller 层调用
- Service 层和 Mapper 层禁止 DTO/VO 转换
- 命名规范:
XxxConverter或XxxMapStruct
工具类规范
- 工具函数集中管理,禁止在 Controller 层编写工具方法
- 工具类私有构造、静态方法、无状态、线程安全
- 命名规范:
XxxUtil(通用)、XxxHelper(业务)、XxxConverter(转换)
多环境配置
| 配置项 | dev | test | prod |
|---|---|---|---|
| SQL 日志 | 开启 | 开启 | 关闭 |
| Swagger | 开启 | 开启 | 关闭 |
| Flyway Clean | 允许 | 禁止 | 禁止 |
快速参考
Redis Key 命名
auth:token:{token}- 用户 Tokenuser:info:{userId}- 用户信息缓存dict:{type}- 数据字典lock:{resource}:{id}- 分布式锁rate_limit:{key}- 限流计数器
数据库索引规范(重要)
唯一索引处理原则
项目使用逻辑删除,唯一索引通过应用层控制,而非数据库唯一约束。
背景问题
当表有逻辑删除字段(deleted)时,数据库唯一索引会导致:
- 删除后无法重新添加相同数据
- 错误信息不友好,直接返回数据库异常
解决方案
| 层级 | 职责 | 实现方式 |
|---|---|---|
| 数据库层 | 普通索引 | KEY idx_xxx (xxx) 而非 UNIQUE KEY uk_xxx (xxx) |
| 应用层 | 重复校验 | Service 层查询 + 悲观锁 FOR UPDATE |
| 异常处理 | 兜底处理 | 全局异常处理器捕获 DuplicateKeyException |
实现示例
1. 数据库迁移(Flyway)
-- ❌ 错误:使用唯一索引
UNIQUE KEY `uk_username` (`username`)
-- ✅ 正确:使用普通索引
KEY `idx_username` (`username`)
2. Mapper 层(悲观锁查询)
/**
* 根据用户名查询用户(悲观锁,用于创建时防并发)
*/
@Select("SELECT * FROM t_user WHERE username = #{username} AND tenant_id = #{tenantId} AND deleted = 0 FOR UPDATE")
User getUserByUsernameForUpdate(@Param("username") String username, @Param("tenantId") Long tenantId);
3. Service 层(事务 + 校验)
@Transactional(rollbackFor = Exception.class)
public UserVO createUser(CreateUserDTO dto, Long tenantId, Long operatorId) {
log.info("开始创建用户,用户名:{}", dto.getUsername());
// 使用悲观锁检查用户名是否已存在(防止并发)
User existingUser = userMapper.getUserByUsernameForUpdate(dto.getUsername(), tenantId);
if (existingUser != null) {
throw new BusinessException("用户名已存在");
}
// 插入用户
User user = convert(dto);
userMapper.insert(user);
return convertToVO(user);
}
4. 需要应用层校验的字段
以下字段需要添加应用层重复校验:
| 表 | 字段 | 说明 |
|---|---|---|
| t_user | username, email, phone | 用户名、邮箱、手机号 |
| t_role | code | 角色编码 |
| t_permission | code | 权限编码 |
| t_dict | code + tenant_id | 字典编码 |
| t_tenant | code | 租户编码 |
| t_sys_config | config_key | 配置键 |
关联表索引规范
对于多对多关联表,使用普通索引而非唯一索引:
-- t_user_role: 用户角色关联表
KEY `idx_user_role` (`user_id`, `role_id`)
-- t_role_permission: 角色权限关联表
KEY `idx_role_permission` (`role_id`, `permission_id`)
注意:关联表的重复数据控制在应用层业务逻辑中处理。
核心环境变量
SPRING_PROFILES_ACTIVE- 活跃环境DB_HOST、DB_PASSWORD- 数据库配置REDIS_HOST、REDIS_PASSWORD- Redis 配置JWT_SECRET- JWT 密钥OSS_ACCESS_KEY_ID、OSS_ACCESS_KEY_SECRET- OSS 配置