205 lines
5.9 KiB
Markdown
205 lines
5.9 KiB
Markdown
# Database 模块开发指南
|
||
|
||
单表 CRUD → REST 接口快速实现框架。基于 JPA + Fenix + QueryDSL + MapStruct。
|
||
|
||
## 架构
|
||
|
||
```
|
||
Controller (REST) → Service (业务) → Repository (数据访问) → Entity (模型)
|
||
```
|
||
|
||
### 组件结构
|
||
|
||
| 包 | 组件 | 职责 |
|
||
|---|---|---|
|
||
| entity | IdOnlyEntity, SimpleEntity | 实体基类 |
|
||
| entity | SnowflakeId, SnowflakeIdGenerator | ID 生成 |
|
||
| entity | Query, GlobalResponse, Page | 查询/响应封装 |
|
||
| repository | SimpleRepository | 统一数据访问接口 |
|
||
| service | SaveService, QueryService, RemoveService | 功能接口 |
|
||
| service | SimpleService, SimpleServiceSupport | 组合接口与实现 |
|
||
| service | QueryParser | 查询条件解析 |
|
||
| controller | SaveController, QueryController, RemoveController | REST 接口 |
|
||
| controller | SimpleController, SimpleControllerSupport | 组合接口与实现 |
|
||
| helper | DatabaseHelper, SnowflakeHelper | 工具类 |
|
||
| exception | *Exception | 异常定义 |
|
||
|
||
## 核心设计
|
||
|
||
### 实体继承
|
||
|
||
```
|
||
IdOnlyEntity (id: Long, @SnowflakeId)
|
||
↑
|
||
SimpleEntity (+ createdTime, modifiedTime)
|
||
↑
|
||
业务实体 (@Entity)
|
||
```
|
||
|
||
**实现要点**:
|
||
- `@MappedSuperclass` 标记基类
|
||
- `@SnowflakeId` 触发 `SnowflakeIdGenerator` 生成 ID
|
||
- `@CreatedDate/@LastModifiedDate` + `AuditingEntityListener` 自动填充时间
|
||
|
||
### Repository
|
||
|
||
```java
|
||
@NoRepositoryBean
|
||
public interface SimpleRepository<E> extends
|
||
FenixJpaRepository<E, Long>, // CRUD + Fenix
|
||
FenixJpaSpecificationExecutor<E>, // Specification
|
||
ListQueryByExampleExecutor<E>, // Example
|
||
ListQuerydslPredicateExecutor<E> {} // QueryDSL
|
||
```
|
||
|
||
**核心能力**:
|
||
- `saveOrUpdateByNotNullProperties()` - 部分字段更新
|
||
- Specification - 动态条件查询
|
||
- QueryDSL - 类型安全查询
|
||
|
||
### Service 接口组合
|
||
|
||
```java
|
||
SaveService<ENTITY> // save(entity), save(entities)
|
||
QueryService<ENTITY> // detail(id), list(), list(query), count()
|
||
RemoveService<ENTITY> // remove(id), remove(ids)
|
||
|
||
SimpleService<ENTITY> extends SaveService, QueryService, RemoveService
|
||
```
|
||
|
||
**SimpleServiceSupport 实现**:
|
||
- 保存:Fenix `saveOrUpdateByNotNullProperties()`
|
||
- 查询:JPA Criteria + Specification
|
||
- 删除:`deleteBatchByIds()`
|
||
- 扩展点:重写 `commonPredicates()` 添加全局过滤条件
|
||
|
||
### Controller 接口组合
|
||
|
||
```java
|
||
SaveController<SAVE_ITEM> // POST /save
|
||
QueryController<LIST_ITEM, DETAIL_ITEM> // GET/POST /list, GET /detail/{id}
|
||
RemoveController // GET /remove/{id}
|
||
|
||
SimpleController<SAVE_ITEM, LIST_ITEM, DETAIL_ITEM>
|
||
```
|
||
|
||
**SimpleControllerSupport 实现**:
|
||
- 调用 Service 方法
|
||
- 通过 Mapper 转换 DTO ↔ Entity
|
||
- 封装 GlobalResponse
|
||
- 扩展点:实现 `saveItemMapper()`, `listItemMapper()`, `detailItemMapper()`
|
||
|
||
### 查询条件
|
||
|
||
**Query 结构**:`Query(query: Queryable, sort: List<Sortable>, page: Pageable)`
|
||
|
||
**QueryParser**:抽象类定义解析接口,`JpaQueryParser` 转换为 JPA Predicate
|
||
|
||
**支持操作**:
|
||
|
||
| 类别 | 操作 |
|
||
|---|---|
|
||
| 空值 | nullEqual, notNullEqual, empty, notEmpty |
|
||
| 相等 | equal, notEqual |
|
||
| 模糊 | like, notLike, contain, notContain |
|
||
| 前后缀 | startWith, endWith, notStartWith, notEndWith |
|
||
| 比较 | great, less, greatEqual, lessEqual |
|
||
| 区间 | between, notBetween |
|
||
| 集合 | inside, notInside |
|
||
|
||
**实现**:JPA CriteriaBuilder 构建,支持多级字段路径(如 `user.name`),自动类型转换(枚举、LocalDateTime)
|
||
|
||
### 响应格式
|
||
|
||
```java
|
||
GlobalResponse<T>(status, message, data)
|
||
// status: 0 成功, 500 失败
|
||
// 列表: data = ListItem(items, total)
|
||
// 详情: data = DetailItem(item)
|
||
```
|
||
|
||
## 技术细节
|
||
|
||
### 雪花算法
|
||
|
||
`SnowflakeHelper`:64 位 Long,1 位符号 + 41 位时间戳 + 10 位机器 ID + 12 位序列号
|
||
|
||
`SnowflakeIdGenerator`:实现 `IdentifierGenerator`,持久化时调用 `SnowflakeHelper.next()`
|
||
|
||
### 部分更新
|
||
|
||
Fenix `saveOrUpdateByNotNullProperties()`:
|
||
- 自动判断 INSERT/UPDATE
|
||
- 仅更新非 null 字段
|
||
|
||
### 命名策略
|
||
|
||
`PhysicalNamingStrategySnakeCaseImpl`:camelCase → snake_case
|
||
|
||
### 注解处理器
|
||
|
||
执行顺序:lombok → hibernate-jpamodelgen → querydsl-apt → mapstruct-processor
|
||
|
||
生成:getter/setter、JPA 元模型(_Entity)、QueryDSL Q 类(QEntity)、MapStruct Mapper
|
||
|
||
## 工具类
|
||
|
||
### DatabaseHelper
|
||
|
||
```java
|
||
// 生成 DDL
|
||
generateDDL(entityPackages, ddlFilePath, dialect, jdbc, username, password, driver)
|
||
|
||
// 生成脚手架
|
||
generateBasicFiles(entityPackages, projectRootPackage, projectRootPath, override)
|
||
```
|
||
|
||
### SnowflakeHelper
|
||
|
||
```java
|
||
Long id = SnowflakeHelper.next();
|
||
```
|
||
|
||
## 扩展指南
|
||
|
||
### 软删除
|
||
|
||
1. 创建 `SoftDeleteEntity extends SimpleEntity`,添加 `deleted` 字段
|
||
2. 重写 `commonPredicates()` 返回 `deleted = false` 条件
|
||
3. 覆盖 `remove()` 改为更新 `deleted` 字段
|
||
|
||
### 多租户
|
||
|
||
1. 创建 `TenantEntity extends SimpleEntity`,添加 `tenantId` 字段
|
||
2. 重写 `commonPredicates()` 添加租户过滤
|
||
3. ThreadLocal 或 Spring Security 存储当前租户
|
||
|
||
### 审计字段
|
||
|
||
在 `SimpleEntity` 添加 `createdBy`, `modifiedBy`,配合 Spring Security 获取当前用户
|
||
|
||
### 自定义查询操作符
|
||
|
||
1. `Query.Queryable` 添加字段
|
||
2. `QueryParser` 添加抽象方法
|
||
3. `JpaQueryParser` 实现转换为 Predicate
|
||
|
||
## 测试
|
||
|
||
- H2 内存数据库
|
||
- `@DataJpaTest` 测试 Repository
|
||
- `@WebMvcTest` 测试 Controller
|
||
- 测试用例:`src/test/java/.../integration/`
|
||
|
||
## 依赖
|
||
|
||
核心:spring-boot-starter-data-jpa, fenix-spring-boot-starter:4.0.0, querydsl-jpa:7.1, mapstruct:1.6.3
|
||
|
||
传递:spring-boot-service-template-common
|
||
|
||
## 注意事项
|
||
|
||
- 事务:写操作 `@Transactional(rollbackFor = Throwable.class)`,读操作 `@Transactional(readOnly = true)`
|
||
- 异常:不使用全局处理器,直接抛出
|
||
- 性能:批量操作使用批量方法
|
||
- 线程安全:GlobalResponse 用 record 保证不可变,SnowflakeHelper 用原子变量 |