diff --git a/README.md b/README.md new file mode 100644 index 0000000..8e55c62 --- /dev/null +++ b/README.md @@ -0,0 +1,469 @@ +# Spring Boot Service Template + +这是一个基于 Spring Boot 的服务模板项目,旨在为开发者提供一个标准化的微服务基础结构,简化新项目的搭建过程,提高开发效率。 + +## 目录 + +- [1. 项目概述](#1-项目概述) +- [2. 技术架构](#2-技术架构) +- [3. 项目结构](#3-项目结构) +- [4. 核心功能](#4-核心功能) +- [5. 使用指南](#5-使用指南) +- [6. 开发规范](#6-开发规范) +- [7. 项目集成指南](#7-项目集成指南) + +## 1. 项目概述 + +### 1.1 项目简介 + +Spring Boot Service Template 是一个标准化的微服务基础结构模板,专为 Java 开发者和微服务架构设计者打造。该项目提供了一套完整的 CRUD 操作框架,通过泛型支持不同类型的数据转换,大大减少了重复代码的编写。 + +该模板内置了完善的实体审计机制,自动维护实体的创建时间和修改时间。同时,提供了强大的查询功能,支持多种条件查询、分页和排序功能。 + +### 1.2 项目目标 + +提供统一的服务模板,简化新项目的搭建过程,提高开发效率。通过封装通用的业务逻辑,让开发者能够专注于核心业务功能的实现。 + +### 1.3 核心特性 + +- 标准化的项目结构:遵循业界最佳实践的目录结构和代码组织方式 +- 简化依赖管理和构建流程:基于 Maven 的依赖管理,清晰的构建配置 +- 支持快速构建和部署微服务:提供完整的微服务基础组件 +- 泛型支持:通过泛型实现不同类型间的数据转换 +- 完善的审计机制:自动维护实体的创建时间和修改时间 +- 强大的查询功能:支持多种条件查询、分页和排序 +- 灵活的扩展机制:易于定制和扩展的架构设计 + +### 1.4 适用场景 + +适用于需要快速搭建 Spring Boot 微服务的项目,特别是那些需要大量 CRUD 操作的业务系统。 + +## 2. 技术架构 + +### 2.1 技术选型 + +#### 2.1.1 后端技术栈 +- Java 17 +- Spring Boot 3.4.3 +- Spring Data JPA +- QueryDSL 7.0 +- Lombok +- Fenix Spring Boot Starter 3.1.0 + +#### 2.1.2 核心框架 +- Spring Boot 作为核心框架,提供自动配置和快速开发能力 +- Spring Data JPA 用于数据访问,简化数据库操作 +- QueryDSL 用于类型安全的查询构建,避免运行时错误 +- Fenix 用于复杂动态查询,提供更灵活的查询能力 +- Lombok 减少样板代码,提高开发效率 + +#### 2.1.3 数据库技术 +- H2 Database (测试环境) + +### 2.2 架构设计 + +#### 2.2.1 整体架构图 +``` +┌─────────────────────────────────────┐ +│ Controller Layer │ +│ (处理HTTP请求,数据转换与响应) │ +├─────────────────────────────────────┤ +│ Service Layer │ +│ (业务逻辑处理,事务管理) │ +├─────────────────────────────────────┤ +│ Repository Layer │ +│ (数据访问,数据库交互) │ +├─────────────────────────────────────┤ +│ Entity Layer │ +│ (数据模型定义,实体映射) │ +└─────────────────────────────────────┘ +``` + +#### 2.2.2 模块划分 +- controller: 控制层,处理 HTTP 请求,包括接口定义和支持类 +- entity: 实体层,定义数据模型和数据库映射 +- service: 服务层,处理业务逻辑和事务管理 +- repository: 仓储层,处理数据访问和数据库交互 +- helper: 辅助类模块,提供工具类和通用方法 + +#### 2.2.3 设计模式 +- 模板方法模式:通过抽象类定义通用操作流程 +- 策略模式:通过函数式接口实现数据转换策略 +- 仓储模式:封装数据访问逻辑,提供统一的数据操作接口 + +## 3. 项目结构 + +### 3.1 目录结构说明 +``` +src/ +├── main/ +│ └── java/ +│ └── com/lanyuanxiaoyao/service/template/ +│ ├── controller/ +│ ├── entity/ +│ ├── helper/ +│ ├── repository/ +│ └── service/ +└── test/ + └── java/ + └── com/lanyuanxiaoyao/service/template/ + ├── controller/ + ├── entity/ + ├── repository/ + └── service/ +``` + +### 3.2 核心模块介绍 + +#### 3.2.1 controller模块 +提供基础的 CRUD 操作控制器接口和支持类。主要包含: +- [SimpleController](src/main/java/com/lanyuanxiaoyao/service/template/controller/SimpleController.java):定义基础 CRUD 接口 +- [SimpleControllerSupport](src/main/java/com/lanyuanxiaoyao/service/template/controller/SimpleControllerSupport.java):实现基础 CRUD 功能 +- [Query](src/main/java/com/lanyuanxiaoyao/service/template/controller/Query.java):查询条件封装类 +- 其他辅助接口如 SaveController、ListController、DetailController、RemoveController + +#### 3.2.2 entity模块 +定义基础实体类,包含审计字段。主要包含: +- [IdOnlyEntity](src/main/java/com/lanyuanxiaoyao/service/template/entity/IdOnlyEntity.java):仅包含 ID 的基础实体 +- [SimpleEntity](src/main/java/com/lanyuanxiaoyao/service/template/entity/SimpleEntity.java):包含基础字段的实体类,继承自 IdOnlyEntity + +#### 3.2.3 service模块 +提供基础服务接口和支持类。主要包含: +- [SimpleService](src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleService.java):定义基础服务接口 +- [SimpleServiceSupport](src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleServiceSupport.java):实现基础服务功能 + +#### 3.2.4 repository模块 +定义数据访问仓储接口。主要包含: +- [SimpleRepository](src/main/java/com/lanyuanxiaoyao/service/template/repository/SimpleRepository.java):基础仓储接口 + +#### 3.2.5 helper模块 +提供辅助工具类。主要包含: +- [ObjectHelper](src/main/java/com/lanyuanxiaoyao/service/template/helper/ObjectHelper.java):对象帮助类 + +### 3.3 测试模块结构 +测试模块包含完整的测试用例,覆盖 controller、entity、repository 和 service 各层。通过实际的业务实体(如 Employee、Company、Report)演示如何使用模板。 + +## 4. 核心功能 + +### 4.1 基础CRUD操作 + +#### 4.1.1 创建(Create) +支持通过 POST 请求创建实体对象。通过 save 接口实现,接收 SAVE_ITEM 类型的参数,通过 Mapper 转换为实体对象后保存。 + +#### 4.1.2 查询(Retrieve) +支持多种查询方式: +- 列表查询:获取所有实体对象 +- 条件查询:根据指定条件查询实体对象 +- 详情查询:根据 ID 获取单个实体对象 + +#### 4.1.3 更新(Update) +支持通过 POST 请求更新实体对象。通过 save 接口实现,当传入包含 ID 的对象时执行更新操作。 + +#### 4.1.4 删除(Delete) +支持通过 GET 请求删除实体对象。通过 remove 接口实现,根据 ID 删除指定实体。 + +### 4.2 查询功能详解 + +#### 4.2.1 简单查询 +支持基于 ID 的简单查询,通过 detail 接口实现。 + +#### 4.2.2 条件查询 +支持基于多种条件的复杂查询,通过 list 接口实现,支持以下查询条件: +- nullEqual: 字段值为null的条件 +- notNullEqual: 字段值不为null的条件 +- empty: 字段值为空的条件 +- notEmpty: 字段值不为空的条件 +- equal: 字段值相等的条件 +- notEqual: 字段值不相等的条件 +- like: 字段值模糊匹配的条件 +- notLike: 字段值不模糊匹配的条件 +- great: 字段值大于的条件 +- less: 字段值小于的条件 +- greatEqual: 字段值大于等于的条件 +- lessEqual: 字段值小于等于的条件 +- in: 字段值在指定范围内的条件 +- notIn: 字段值不在指定范围内的条件 +- between: 字段值在指定区间内的条件 +- notBetween: 字段值不在指定区间内的条件 + +#### 4.2.3 分页查询 +支持分页查询功能,通过 page 配置实现分页参数设置。 + +#### 4.2.4 排序查询 +支持排序查询功能,通过 sort 配置实现排序参数设置。 + +### 4.3 数据实体设计 + +#### 4.3.1 基础实体类 +定义通用的实体基类,包括 IdOnlyEntity 和 SimpleEntity。 + +#### 4.3.2 审计字段 +包含创建时间(createdTime)和修改时间(modifiedTime)等审计字段,通过 Spring Data JPA 的审计功能自动维护。 + +#### 4.3.3 实体关系 +支持常见的实体关系映射,如一对一、一对多、多对多等。 + +## 5. 使用指南 + +### 5.1 环境准备 + +#### 5.1.1 JDK安装 +需要安装 JDK 17 或更高版本。 + +#### 5.1.2 Maven配置 +需要配置 Maven 3.x 环境。 + +### 5.2 项目构建 + +#### 5.2.1 依赖管理 +通过 Maven 管理项目依赖。 + +#### 5.2.2 编译打包 +使用 `mvn clean package` 命令编译打包项目。 + +### 5.3 运行部署 + +#### 5.3.1 本地运行 +可以使用 `mvn spring-boot:run` 命令运行项目。 + +#### 5.3.2 生产部署 +可通过生成的 JAR 文件直接运行或部署到服务器,使用命令: +`java -jar target/spring-boot-service-template-1.0-SNAPSHOT.jar` + +## 6. 开发规范 + +### 6.1 代码规范 +遵循 Java 标准编码规范和 Spring Boot 最佳实践。 + +### 6.2 接口规范 +RESTful API 设计规范,统一的响应格式。 + +### 6.3 注释规范 +遵循标准的 JavaDoc 格式编写注释,详细说明类、方法、参数和返回值的含义。 + +### 6.4 异常处理 +统一异常处理机制,提供友好的错误信息。 + +## 7. 项目集成指南 + +本章节详细介绍如何在现有项目中集成 Spring Boot Service Template 的能力。 + +### 7.1 集成方式 + +通过 Maven 依赖引入(推荐) + +### 7.2 Maven 依赖引入方式 + +#### 7.2.1 添加依赖 + +在您的项目 pom.xml 文件中添加以下依赖: + +```xml + + com.lanyuanxiaoyao + spring-boot-service-template + 1.0.0-SNAPSHOT + +``` + +#### 7.2.2 配置依赖管理 + +确保您的项目中包含以下依赖管理配置: + +```xml + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + +``` + +#### 7.2.3 配置编译插件 + +确保您的项目中包含以下编译插件配置: + +```xml + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.14.0 + + + + org.projectlombok + lombok + 1.18.36 + + + org.hibernate + hibernate-jpamodelgen + 6.6.3.Final + + + io.github.openfeign.querydsl + querydsl-jpa + 7.0 + + + + + + +``` + +### 7.4 创建业务模块 + +创建业务模块的步骤如下: + +#### 7.4.1 创建实体类 + +创建实体类并继承 [SimpleEntity](src/main/java/com/lanyuanxiaoyao/service/template/entity/SimpleEntity.java): + +```java +@Entity +@Table(name = "employee") +public class Employee extends SimpleEntity { + private String name; + private Integer age; + // 其他字段和方法 +} +``` + +#### 7.4.2 创建仓储接口 + +创建仓储接口并继承 [SimpleRepository](src/main/java/com/lanyuanxiaoyao/service/template/repository/SimpleRepository.java): + +```java +@Repository +public interface EmployeeRepository extends SimpleRepository { + // 自定义查询方法 +} +``` + +#### 7.4.3 创建服务类 + +创建服务类并继承 [SimpleServiceSupport](src/main/java/com/lanyuanxiaoyao/service/template/service/SimpleServiceSupport.java): + +```java +@Service +public class EmployeeService extends SimpleServiceSupport { + public EmployeeService(EmployeeRepository repository) { + super(repository); + } + // 自定义业务方法 +} +``` + +#### 7.4.4 创建控制器类 + +创建控制器类并继承 [SimpleControllerSupport](src/main/java/com/lanyuanxiaoyao/service/template/controller/SimpleControllerSupport.java): + +```java +@RestController +@RequestMapping("employee") +public class EmployeeController extends SimpleControllerSupport { + public EmployeeController(EmployeeService service) { + super(service); + } + + @Override + protected Function saveItemMapper() { + // 实现保存项转换逻辑 + } + + @Override + protected Function listItemMapper() { + // 实现列表项转换逻辑 + } + + @Override + protected Function detailItemMapper() { + // 实现详情项转换逻辑 + } +} +``` + +#### 7.4.5 创建数据传输对象 + +创建用于数据传输的对象: + +```java +// 保存项 +public class EmployeeSaveItem { + private Long id; + private String name; + private Integer age; + // getter和setter方法 +} + +// 列表项 +public class EmployeeListItem { + private Long id; + private String name; + private Integer age; + // getter和setter方法 +} + +// 详情项 +public class EmployeeDetailItem { + private Long id; + private String name; + private Integer age; + private LocalDateTime createdTime; + private LocalDateTime modifiedTime; + // getter和setter方法 +} +``` + +### 7.5 配置启用 JPA 审计 + +在您的主应用类上添加 [@EnableJpaAuditing](https://docs.spring.io/spring-data/jpa/docs/current/api/org/springframework/data/jpa/repository/config/EnableJpaAuditing.html) 注解以启用 JPA 审计功能: + +```java +@SpringBootApplication +@EnableJpaAuditing +public class YourApplication { + public static void main(String[] args) { + SpringApplication.run(YourApplication.class, args); + } +} +``` + +### 7.6 配置 Fenix + +在您的 application.yml 或 application.properties 文件中添加 Fenix 配置: + +```yaml +fenix: + # 是否开启 Fenix + enabled: true + # SQL 执行后的输出格式,console: 控制台彩色输出; html: 彩色 HTML 输出; text: 纯文本输出 + output-format: console +``` + +### 7.7 测试集成效果 + +完成以上步骤后,您可以运行您的应用程序并测试以下功能: + +1. 创建实体:POST /employee/save +2. 查询列表:GET /employee/list 或 POST /employee/list(带条件) +3. 查询详情:GET /employee/detail/{id} +4. 删除实体:GET /employee/remove/{id} + +通过以上步骤,您就可以成功在现有项目中集成 Spring Boot Service Template 的能力,快速实现 CRUD 功能。 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 915c948..3f42ba4 100644 --- a/pom.xml +++ b/pom.xml @@ -58,12 +58,6 @@ h2 test - - io.github.linpeilie - mapstruct-plus-spring-boot-starter - ${mapstruct-plus.version} - test - @@ -128,16 +122,6 @@ jakarta.persistence-api 3.2.0 - - io.github.linpeilie - mapstruct-plus-processor - ${mapstruct-plus.version} - - - org.projectlombok - lombok-mapstruct-binding - 0.2.0 - -Aquerydsl.entityAccessors=true diff --git a/src/test/java/com/lanyuanxiaoyao/service/template/TestApplication.java b/src/test/java/com/lanyuanxiaoyao/service/template/TestApplication.java index 5eb3325..d534869 100644 --- a/src/test/java/com/lanyuanxiaoyao/service/template/TestApplication.java +++ b/src/test/java/com/lanyuanxiaoyao/service/template/TestApplication.java @@ -12,7 +12,6 @@ import com.lanyuanxiaoyao.service.template.entity.QEmployee; import com.lanyuanxiaoyao.service.template.entity.Report; import com.lanyuanxiaoyao.service.template.entity.Report_; import com.lanyuanxiaoyao.service.template.repository.EmployeeRepository; -import io.github.linpeilie.annotations.ComponentModelConfig; import jakarta.annotation.Resource; import java.util.List; import org.slf4j.Logger; @@ -35,7 +34,6 @@ import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableFenix @EnableJpaAuditing -@ComponentModelConfig public class TestApplication { private static final Logger log = LoggerFactory.getLogger(TestApplication.class); private static final String BASE_URL = "http://localhost:2490"; diff --git a/src/test/java/com/lanyuanxiaoyao/service/template/controller/CompanyController.java b/src/test/java/com/lanyuanxiaoyao/service/template/controller/CompanyController.java index 6c89d8c..1357af3 100644 --- a/src/test/java/com/lanyuanxiaoyao/service/template/controller/CompanyController.java +++ b/src/test/java/com/lanyuanxiaoyao/service/template/controller/CompanyController.java @@ -2,77 +2,69 @@ package com.lanyuanxiaoyao.service.template.controller; import com.lanyuanxiaoyao.service.template.entity.Company; import com.lanyuanxiaoyao.service.template.service.CompanyService; -import io.github.linpeilie.Converter; -import io.github.linpeilie.annotations.AutoMapper; import java.time.LocalDateTime; import java.util.function.Function; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("company") public class CompanyController extends SimpleControllerSupport { - private static final Converter converter = new Converter(); - public CompanyController(CompanyService service) { super(service); } @Override protected Function saveItemMapper() { - return item -> converter.convert(item, Company.class); + return item -> { + var company = new Company(); + company.setId(item.id()); + company.setName(item.name()); + company.setMembers(item.members()); + return company; + }; } @Override protected Function listItemMapper() { - return company -> converter.convert(company, ListItem.class); + return company -> new ListItem( + company.getId(), + company.getName(), + company.getMembers() + ); } @Override protected Function detailItemMapper() { - return company -> converter.convert(company, DetailItem.class); + return company -> new DetailItem( + company.getId(), + company.getName(), + company.getMembers(), + company.getCreatedTime(), + company.getModifiedTime() + ); } - @Setter - @Getter - @ToString - @AllArgsConstructor - @NoArgsConstructor - @AutoMapper(target = Company.class, reverseConvertGenerate = false) - public static class SaveItem { - private Long id; - private String name; - private Integer members; + public record SaveItem( + Long id, + String name, + Integer members + ) { } - @Setter - @Getter - @ToString - @AllArgsConstructor - @NoArgsConstructor - @AutoMapper(target = Company.class, convertGenerate = false) - public static class ListItem { - private Long id; - private String name; - private Integer members; + public record ListItem( + Long id, + String name, + Integer members + ) { } - @Setter - @Getter - @ToString - @AllArgsConstructor - @NoArgsConstructor - @AutoMapper(target = Company.class, convertGenerate = false) - public static class DetailItem { - private Long id; - private String name; - private Integer members; - private LocalDateTime createdTime; - private LocalDateTime modifiedTime; + public record DetailItem( + Long id, + String name, + Integer members, + LocalDateTime createdTime, + LocalDateTime modifiedTime + ) { } } diff --git a/src/test/java/com/lanyuanxiaoyao/service/template/controller/EmployeeController.java b/src/test/java/com/lanyuanxiaoyao/service/template/controller/EmployeeController.java index 374a1f5..edc535b 100644 --- a/src/test/java/com/lanyuanxiaoyao/service/template/controller/EmployeeController.java +++ b/src/test/java/com/lanyuanxiaoyao/service/template/controller/EmployeeController.java @@ -3,87 +3,82 @@ package com.lanyuanxiaoyao.service.template.controller; import com.lanyuanxiaoyao.service.template.entity.Employee; import com.lanyuanxiaoyao.service.template.service.CompanyService; import com.lanyuanxiaoyao.service.template.service.EmployeeService; -import io.github.linpeilie.Converter; -import io.github.linpeilie.annotations.AutoMapper; -import io.github.linpeilie.annotations.AutoMapping; -import io.github.linpeilie.annotations.ReverseAutoMapping; import java.time.LocalDateTime; import java.util.function.Function; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("employee") public class EmployeeController extends SimpleControllerSupport { - private final Converter converter = new Converter(); + private final CompanyService companyService; - public EmployeeController(EmployeeService service) { + public EmployeeController(EmployeeService service, CompanyService companyService) { super(service); + this.companyService = companyService; } @Override protected Function saveItemMapper() { - return item -> converter.convert(item, Employee.class); + return item -> { + var employee = new Employee(); + employee.setId(item.id()); + employee.setName(item.name()); + employee.setAge(item.age()); + employee.setRole(Employee.Role.USER); + employee.setCompany(companyService.detailOrThrow(item.companyId())); + return employee; + }; } @Override protected Function listItemMapper() { - return employee -> converter.convert(employee, ListItem.class); + return employee -> new ListItem( + employee.getId(), + employee.getName(), + employee.getAge(), + employee.getRole() + ); } @Override protected Function detailItemMapper() { - return employee -> converter.convert(employee, DetailItem.class); + return employee -> new DetailItem( + employee.getId(), + employee.getCompany().getId(), + employee.getName(), + employee.getAge(), + employee.getRole(), + employee.getCreatedTime(), + employee.getModifiedTime() + ); } - @Setter - @Getter - @ToString - @AllArgsConstructor - @NoArgsConstructor - @AutoMapper(target = Employee.class, uses = CompanyService.class, reverseConvertGenerate = false) - public static class SaveItem { - private Long id; - @AutoMapping(target = "company", qualifiedByName = "detailOrThrow") - private Long companyId; - private String name; - private Integer age; - @AutoMapping(defaultValue = "USER") - private Employee.Role role; + public record SaveItem( + Long id, + Long companyId, + String name, + Integer age, + Employee.Role role + ) { } - @Setter - @Getter - @ToString - @AllArgsConstructor - @NoArgsConstructor - @AutoMapper(target = Employee.class, convertGenerate = false) - public static class ListItem { - private Long id; - private String name; - private Integer age; - private Employee.Role role; + public record ListItem( + Long id, + String name, + Integer age, + Employee.Role role + ) { } - @Setter - @Getter - @ToString - @AllArgsConstructor - @NoArgsConstructor - @AutoMapper(target = Employee.class, convertGenerate = false) - public static class DetailItem { - private Long id; - @ReverseAutoMapping(source = "company.id") - private Long companyId; - private String name; - private Integer age; - private Employee.Role role; - private LocalDateTime createdTime; - private LocalDateTime modifiedTime; + public record DetailItem( + Long id, + Long companyId, + String name, + Integer age, + Employee.Role role, + LocalDateTime createdTime, + LocalDateTime modifiedTime + ) { } } diff --git a/src/test/java/com/lanyuanxiaoyao/service/template/controller/ReportController.java b/src/test/java/com/lanyuanxiaoyao/service/template/controller/ReportController.java index 3aa3440..0fdd698 100644 --- a/src/test/java/com/lanyuanxiaoyao/service/template/controller/ReportController.java +++ b/src/test/java/com/lanyuanxiaoyao/service/template/controller/ReportController.java @@ -1,27 +1,16 @@ package com.lanyuanxiaoyao.service.template.controller; -import com.lanyuanxiaoyao.service.template.entity.Employee; import com.lanyuanxiaoyao.service.template.entity.Report; import com.lanyuanxiaoyao.service.template.service.EmployeeService; import com.lanyuanxiaoyao.service.template.service.ReportService; -import io.github.linpeilie.Converter; -import io.github.linpeilie.annotations.AutoMapper; import java.time.LocalDateTime; import java.util.function.Function; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; -import org.mapstruct.Mapping; -import org.mapstruct.factory.Mappers; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("report") public class ReportController extends SimpleControllerSupport { - private final Converter converter = new Converter(); private final EmployeeService employeeService; public ReportController(ReportService service, EmployeeService employeeService) { @@ -31,83 +20,71 @@ public class ReportController extends SimpleControllerSupport saveItemMapper() { - return item -> converter.convert(item, Report.class); + return item -> { + var report = new Report(); + report.setId(item.id()); + report.setScore(item.score()); + report.setLevel(item.level()); + report.setEmployeeId(item.employeeId()); + return report; + }; } @Override protected Function listItemMapper() { - var mapper = Mappers.getMapper(ListItem.Mapper.class); return report -> { var employee = employeeService.detailOrThrow(report.getEmployeeId()); - return mapper.map(report, employee); + return new ListItem( + report.getId(), + employee.getId(), + employee.getName(), + report.getScore(), + report.getLevel() + ); }; } @Override protected Function detailItemMapper() { - var mapper = Mappers.getMapper(DetailItem.Mapper.class); return report -> { var employee = employeeService.detailOrThrow(report.getEmployeeId()); - return mapper.map(report, employee); + return new DetailItem( + report.getId(), + employee.getId(), + employee.getName(), + report.getScore(), + report.getLevel(), + report.getCreatedTime(), + report.getModifiedTime() + ); }; } - @Setter - @Getter - @ToString - @AllArgsConstructor - @NoArgsConstructor - @AutoMapper(target = Report.class, reverseConvertGenerate = false) - public static class SaveItem { - private Long id; - private Double score; - private Report.Level level; - private Long employeeId; + public record SaveItem( + Long id, + Double score, + Report.Level level, + Long employeeId + ) { } - @Setter - @Getter - @ToString - @AllArgsConstructor - @NoArgsConstructor - public static class ListItem { - private Long id; - private Long employeeId; - private String employeeName; - private Double score; - private Report.Level level; - - @org.mapstruct.Mapper - public interface Mapper { - @Mapping(target = "id", source = "report.id") - @Mapping(target = "employeeId", source = "employee.id") - @Mapping(target = "employeeName", source = "employee.name") - ListItem map(Report report, Employee employee); - } + public record ListItem( + Long id, + Long employeeId, + String employeeName, + Double score, + Report.Level level + ) { } - @Setter - @Getter - @ToString - @AllArgsConstructor - @NoArgsConstructor - public static class DetailItem { - private Long id; - private Long employeeId; - private String employeeName; - private Double score; - private Report.Level level; - private LocalDateTime createdTime; - private LocalDateTime modifiedTime; - - @org.mapstruct.Mapper - public interface Mapper { - @Mapping(target = "id", source = "report.id") - @Mapping(target = "employeeId", source = "employee.id") - @Mapping(target = "employeeName", source = "employee.name") - @Mapping(target = "createdTime", source = "report.createdTime") - @Mapping(target = "modifiedTime", source = "report.modifiedTime") - DetailItem map(Report report, Employee employee); - } + public record DetailItem( + Long id, + Long employeeId, + String employeeName, + Double score, + Report.Level level, + LocalDateTime createdTime, + LocalDateTime modifiedTime + ) { } }