1
0

docs: 将 database 模块文档拆分为独立文件

This commit is contained in:
2026-04-01 17:31:25 +08:00
parent 0a7e38f931
commit 6bf9a3295a
3 changed files with 618 additions and 76 deletions

409
docs/database-usage.md Normal file
View File

@@ -0,0 +1,409 @@
# Database 模块使用指南
单表 CRUD → REST 接口快速实现框架。
## 使用模式
### Web 应用
引入 database 模块,创建 Entity → Repository → Service → Controller实现 REST 接口。
### 非 Web 应用
**无需引入 web 依赖**database 模块的 `spring-boot-starter-web` scope 为 `provided`)。
仅使用 Entity → Repository → Service直接注入 Service 使用:
```java
@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired
private EmployeeService service;
@Override
public void run(String... args) {
Employee emp = new Employee();
emp.setName("张三");
Long id = service.save(emp);
Employee found = service.detail(id);
List<Employee> list = service.list();
}
}
```
适用:批处理、定时任务、数据迁移、命令行应用、后台服务。
## 快速开始
### 1. 添加依赖
```xml
<dependency>
<groupId>com.lanyuanxiaoyao</groupId>
<artifactId>spring-boot-service-template-database</artifactId>
</dependency>
```
### 2. 创建实体
```java
@Getter @Setter
@ToString(callSuper = true)
@FieldNameConstants
@Entity
@Table(name = "employee")
public class Employee extends SimpleEntity {
@Column(comment = "员工姓名", nullable = false)
private String name;
@Column(comment = "部门ID")
private Long departmentId;
@Column(comment = "邮箱")
private String email;
}
```
继承 `SimpleEntity` 自动获得 `id`(雪花算法)、`createdTime``modifiedTime`(自动填充)。
### 3. 创建 Repository
```java
@Repository
public interface EmployeeRepository extends SimpleRepository<Employee> {}
```
继承能力CRUD、分页、Specification、QueryDSL、Example。
### 4. 创建 Service
```java
@Slf4j
@Service
public class EmployeeService extends SimpleServiceSupport<Employee> {
public EmployeeService(EmployeeRepository repository) {
super(repository);
}
}
```
自动获得完整 CRUD 能力。
### 5. 创建 ControllerWeb 应用)
```java
@Slf4j
@RestController
@RequestMapping("employee")
public class EmployeeController
extends SimpleControllerSupport<Employee, EmployeeController.SaveItem, EmployeeController.ListItem, EmployeeController.DetailItem> {
private final EmployeeService service;
public EmployeeController(EmployeeService service) {
super(service);
this.service = service;
}
@Override
protected Function<SaveItem, Employee> saveItemMapper() {
return item -> {
Employee entity = new Employee();
entity.setId(item.id());
entity.setName(item.name());
entity.setDepartmentId(item.departmentId());
entity.setEmail(item.email());
return entity;
};
}
@Override
protected Function<Employee, ListItem> listItemMapper() {
return entity -> new ListItem(
entity.getId(), entity.getName(), entity.getDepartmentId(),
entity.getEmail(), entity.getCreatedTime()
);
}
@Override
protected Function<Employee, DetailItem> detailItemMapper() {
return entity -> new DetailItem(
entity.getId(), entity.getName(), entity.getDepartmentId(),
entity.getEmail(), entity.getCreatedTime(), entity.getModifiedTime()
);
}
public record SaveItem(Long id, String name, Long departmentId, String email) {}
public record ListItem(Long id, String name, Long departmentId, String email, LocalDateTime createdTime) {}
public record DetailItem(Long id, String name, Long departmentId, String email, LocalDateTime createdTime, LocalDateTime modifiedTime) {}
}
```
实现三个 Mapper`saveItemMapper()`, `listItemMapper()`, `detailItemMapper()`
## 代码生成
```java
DatabaseHelper.generateBasicFiles(
"com.example.entity", // 实体包
"com.example", // 项目根包
"./src/main/java/com/example", // 源码路径
false // 是否覆盖
);
```
生成 Repository、Service、Controller。
## API 接口Web 应用)
### POST /{entity}/save
保存/更新实体。
请求(新增):
```json
{"name": "张三", "departmentId": 1, "email": "zhangsan@example.com"}
```
请求(更新):
```json
{"id": 123456789, "name": "李四"}
```
响应:
```json
{"status": 0, "message": "OK", "data": 123456789}
```
特性:不传 id 为新增,传 id 为更新(仅更新非 null 字段)。
### GET/POST /{entity}/list
GET获取全部列表
POST条件查询
```json
{
"query": {
"equal": {"departmentId": 1},
"like": {"name": "%张%"},
"greatEqual": {"createdTime": "2026-01-01 00:00:00"}
},
"sort": [{"column": "createdTime", "direction": "DESC"}],
"page": {"index": 1, "size": 20}
}
```
响应:
```json
{"status": 0, "message": "OK", "data": {"items": [...], "total": 100}}
```
### GET /{entity}/detail/{id}
响应:
```json
{"status": 0, "message": "OK", "data": {"id": 123, "name": "张三", ...}}
```
ID 不存在返回 500。
### GET /{entity}/remove/{id}
响应:
```json
{"status": 0, "message": "OK", "data": null}
```
## 查询条件
### Query 结构
```java
Query(
query: Queryable, // 查询条件
sort: List<Sortable>, // 排序
page: Pageable // 分页
)
```
### 查询操作
| 操作 | 类型 | 示例 |
|---|---|---|
| equal | Map | `{"name": "张三"}` |
| notEqual | Map | `{"status": "DELETED"}` |
| like | Map | `{"name": "%张%"}` |
| contain | Map | `{"name": "张"}``%张%` |
| startWith | Map | `{"name": "张"}``张%` |
| endWith | Map | `{"name": "三"}``%三` |
| great/greatEqual | Map | `{"age": 18}` |
| less/lessEqual | Map | `{"age": 60}` |
| between | Map | `{"age": {"start": 18, "end": 60}}` |
| inside | Map | `{"id": [1, 2, 3]}` |
| notInside | Map | `{"status": ["DELETED"]}` |
| nullEqual | List | `["deletedAt"]` |
| notNullEqual | List | `["email"]` |
### 排序
```json
{"sort": [{"column": "createdTime", "direction": "DESC"}]}
```
direction: `ASC` 升序,`DESC` 降序
### 分页
```json
{"page": {"index": 1, "size": 20}}
```
index 从 1 开始,默认 `(1, 10)`,无排序默认 `createdTime DESC`
## 高级用法
### 扩展 Service
```java
@Service
public class EmployeeService extends SimpleServiceSupport<Employee> {
private final EmployeeRepository repository;
public EmployeeService(EmployeeRepository repository) {
super(repository);
this.repository = repository;
}
// 自定义方法
public List<Employee> findByDepartmentId(Long departmentId) {
return repository.findAll(
(root, query, builder) -> builder.equal(root.get("departmentId"), departmentId)
);
}
// 全局过滤条件
@Override
protected Predicate commonPredicates(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
return builder.equal(root.get("deleted"), false); // 软删除过滤
}
}
```
### QueryDSL 查询
```java
public List<Employee> findActiveEmployees() {
QEmployee q = QEmployee.employee;
return repository.findAll(q.status.eq("ACTIVE").and(q.deleted.isFalse()));
}
```
### MapStruct Mapper
```java
@Mapper
public interface EmployeeMapper {
Employee toEntity(SaveItem item);
ListItem toListItem(Employee entity);
DetailItem toDetailItem(Employee entity);
}
// Controller 中使用
@Override
protected Function<SaveItem, Employee> saveItemMapper() {
return mapper::toEntity;
}
```
## 实体设计
### 字段类型
- ID: `Long`(雪花算法)
- 时间: `LocalDateTime`
- 金额: `BigDecimal`
- 枚举: Java enum存储为字符串
- 布尔: `Boolean`
### 关联关系
```java
@Entity
public class Order extends SimpleEntity {
@ManyToOne
@JoinColumn(name = "customer_id")
private Customer customer;
@OneToMany(mappedBy = "order", fetch = FetchType.LAZY)
private List<OrderItem> items;
}
```
注意:谨慎使用 `@OneToMany`,可能导致 N+1 问题。
### 索引
```java
@Entity
@Table(name = "employee", indexes = {
@Index(name = "idx_department", columnList = "department_id")
})
public class Employee extends SimpleEntity { ... }
```
## 工具类
### DatabaseHelper
```java
// 生成 DDL
DatabaseHelper.generateDDL(
"com.example.entity", "./sql", MySQL8Dialect.class,
"jdbc:mysql://localhost:3306/test", "root", "password",
com.mysql.cj.jdbc.Driver.class
);
```
### SnowflakeHelper
```java
Long id = SnowflakeHelper.next();
```
## 常见问题
**Q: 非 Web 应用如何使用?**
A: 不引入 web 依赖,创建 Entity → Repository → Service直接注入 Service 使用。
**Q: 如何实现软删除?**
A: 添加 `deleted` 字段,重写 `commonPredicates()` 过滤,覆盖 `remove()` 改为更新。
**Q: 如何处理复杂查询?**
A: 使用 QueryDSL 或 Repository `@Query` 方法:
```java
@Query("SELECT e FROM Employee e WHERE e.departmentId = :deptId")
List<Employee> findByDepartment(@Param("deptId") Long deptId);
```
**Q: 如何批量插入?**
A: `service.save(entities)``repository.saveAll(entities)`
**Q: 查询条件支持关联对象吗?**
A: 支持,使用多级路径如 `"department.name"`
## 最佳实践
1. DTO 设计SaveItem 可修改字段ListItem 列表字段DetailItem 完整字段
2. 事务Service 方法已加事务,无需重复
3. 性能:列表查询避免关联对象,使用投影或 DTO
4. 代码生成:初期脚手架生成,后期手动调整
## 测试用例
`src/test/java/.../integration/`