library-picturebook-activity/.claude/memory/java-backend.md
En b805f456a6 feat: 完善后端基础架构和登录功能
- 添加 Lombok 配置支持
- 完善枚举类和常量定义
- 新增工具类(TraceId、限流、OSS 等)
- 添加切面(日志、限流、TraceId)
- 更新数据库索引规范(应用层防重)
- 登录页面样式优化
- 前后端项目文档补充
2026-03-31 13:58:28 +08:00

253 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Java 后端开发规范
本项目 Java 后端开发规范,基于 Spring Boot + MyBatis-Plus 技术栈。
## JDK 版本要求(重要)
**必须使用 JDK 17** 进行编译和运行。
如果系统环境变量配置的是 JDK 1.8,请在编译前设置 `JAVA_HOME`
```bash
# 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"
```
## 核心原则
1. **OpenAPI 规范驱动** - 前后端通过接口规范对齐
2. **类型安全优先** - 强制类型校验
3. **约定大于配置** - 统一代码风格
4. **自动化优先** - 能自动化的绝不手动
5. **三层架构分离** - 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、异常类型、消息、堆栈
## 统一响应格式
```java
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}` - 用户 Token
- `user:info:{userId}` - 用户信息缓存
- `dict:{type}` - 数据字典
- `lock:{resource}:{id}` - 分布式锁
- `rate_limit:{key}` - 限流计数器
## 数据库索引规范(重要)
### 唯一索引处理原则
**项目使用逻辑删除,唯一索引通过应用层控制,而非数据库唯一约束。**
#### 背景问题
当表有逻辑删除字段(`deleted`)时,数据库唯一索引会导致:
1. 删除后无法重新添加相同数据
2. 错误信息不友好,直接返回数据库异常
#### 解决方案
| 层级 | 职责 | 实现方式 |
|------|------|----------|
| **数据库层** | 普通索引 | `KEY idx_xxx (xxx)` 而非 `UNIQUE KEY uk_xxx (xxx)` |
| **应用层** | 重复校验 | Service 层查询 + 悲观锁 `FOR UPDATE` |
| **异常处理** | 兜底处理 | 全局异常处理器捕获 `DuplicateKeyException` |
#### 实现示例
**1. 数据库迁移Flyway**
```sql
-- ❌ 错误:使用唯一索引
UNIQUE KEY `uk_username` (`username`)
-- ✅ 正确:使用普通索引
KEY `idx_username` (`username`)
```
**2. Mapper 层(悲观锁查询)**
```java
/**
* 根据用户名查询用户(悲观锁,用于创建时防并发)
*/
@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 层(事务 + 校验)**
```java
@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 | 配置键 |
### 关联表索引规范
对于多对多关联表,使用普通索引而非唯一索引:
```sql
-- 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 配置