# 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 list = service.list(); } } ``` 适用:批处理、定时任务、数据迁移、命令行应用、后台服务。 ## 快速开始 ### 1. 添加依赖 ```xml com.lanyuanxiaoyao spring-boot-service-template-database ``` ### 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 {} ``` 继承能力:CRUD、分页、Specification、QueryDSL、Example。 ### 4. 创建 Service ```java @Slf4j @Service public class EmployeeService extends SimpleServiceSupport { public EmployeeService(EmployeeRepository repository) { super(repository); } } ``` 自动获得完整 CRUD 能力。 ### 5. 创建 Controller(Web 应用) ```java @Slf4j @RestController @RequestMapping("employee") public class EmployeeController extends SimpleControllerSupport { private final EmployeeService service; public EmployeeController(EmployeeService service) { super(service); this.service = service; } @Override protected Function 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 listItemMapper() { return entity -> new ListItem( entity.getId(), entity.getName(), entity.getDepartmentId(), entity.getEmail(), entity.getCreatedTime() ); } @Override protected Function 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, // 排序 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 { private final EmployeeRepository repository; public EmployeeService(EmployeeRepository repository) { super(repository); this.repository = repository; } // 自定义方法 public List findByDepartmentId(Long departmentId) { return repository.findAll( (root, query, builder) -> builder.equal(root.get("departmentId"), departmentId) ); } // 全局过滤条件 @Override protected Predicate commonPredicates(Root root, CriteriaQuery query, CriteriaBuilder builder) { return builder.equal(root.get("deleted"), false); // 软删除过滤 } } ``` ### QueryDSL 查询 ```java public List 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 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 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 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/`