1
0

feat: 加入MapStruct的示例

This commit is contained in:
2025-08-24 18:16:33 +08:00
parent 9d52da9b1a
commit c7350da73a
7 changed files with 91 additions and 70 deletions

25
pom.xml
View File

@@ -16,6 +16,8 @@
<spring-boot.version>3.4.3</spring-boot.version>
<spring-cloud.version>2024.0.1</spring-cloud.version>
<querydsl.version>7.0</querydsl.version>
<mapstruct.version>1.6.3</mapstruct.version>
<mapstruct-plus.version>1.5.0</mapstruct-plus.version>
</properties>
<dependencies>
@@ -39,6 +41,13 @@
<version>${querydsl.version}</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
@@ -49,6 +58,12 @@
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId>
<version>${mapstruct-plus.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
@@ -113,6 +128,16 @@
<artifactId>jakarta.persistence-api</artifactId>
<version>3.2.0</version>
</path>
<path>
<groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-processor</artifactId>
<version>${mapstruct-plus.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>0.2.0</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-Aquerydsl.entityAccessors=true</arg>

View File

@@ -222,4 +222,8 @@ public abstract class SimpleControllerSupport<ENTITY extends SimpleEntity, SAVE_
* @return Function<ENTITY, DETAIL_ITEM> 实体到详情项的转换函数
*/
protected abstract Function<ENTITY, DETAIL_ITEM> detailItemMapper();
public interface Mapper<S, T> {
T map(S source) throws Exception;
}
}

View File

@@ -19,6 +19,7 @@ import java.util.List;
import java.util.Optional;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.mapstruct.Named;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
@@ -532,6 +533,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
* @param id 实体ID
* @return ENTITY 返回实体详情不存在时返回null
*/
@Named("detail")
@Override
public ENTITY detail(Long id) {
return detailOptional(id).orElse(null);
@@ -547,6 +549,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
* @return ENTITY 返回实体详情
* @throws IdNotFoundException 当实体不存在时抛出
*/
@Named("detailOrThrow")
@Override
public ENTITY detailOrThrow(Long id) {
return detailOptional(id).orElseThrow(() -> new IdNotFoundException(id));

View File

@@ -4,6 +4,7 @@ import com.blinkfox.fenix.EnableFenix;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lanyuanxiaoyao.service.template.entity.Company;
import com.lanyuanxiaoyao.service.template.entity.Company_;
import com.lanyuanxiaoyao.service.template.entity.Employee;
import com.lanyuanxiaoyao.service.template.entity.Employee_;
@@ -11,6 +12,7 @@ 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;
@@ -33,6 +35,7 @@ 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";

View File

@@ -2,6 +2,8 @@ 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;
@@ -15,39 +17,25 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("company")
public class CompanyController extends SimpleControllerSupport<Company, CompanyController.SaveItem, CompanyController.ListItem, CompanyController.DetailItem> {
private static final Converter converter = new Converter();
public CompanyController(CompanyService service) {
super(service);
}
@Override
protected Function<SaveItem, Company> saveItemMapper() {
return item -> {
var company = new Company();
company.setId(item.getId());
company.setName(item.getName());
company.setMembers(item.getMembers());
return company;
};
return item -> converter.convert(item, Company.class);
}
@Override
protected Function<Company, ListItem> listItemMapper() {
return company -> new ListItem(
company.getId(),
company.getName(),
company.getMembers()
);
return company -> converter.convert(company, ListItem.class);
}
@Override
protected Function<Company, DetailItem> detailItemMapper() {
return company -> new DetailItem(
company.getId(),
company.getName(),
company.getMembers(),
company.getCreatedTime(),
company.getModifiedTime()
);
return company -> converter.convert(company, DetailItem.class);
}
@Setter
@@ -55,6 +43,7 @@ public class CompanyController extends SimpleControllerSupport<Company, CompanyC
@ToString
@AllArgsConstructor
@NoArgsConstructor
@AutoMapper(target = Company.class, reverseConvertGenerate = false)
public static class SaveItem {
private Long id;
private String name;
@@ -66,6 +55,7 @@ public class CompanyController extends SimpleControllerSupport<Company, CompanyC
@ToString
@AllArgsConstructor
@NoArgsConstructor
@AutoMapper(target = Company.class, convertGenerate = false)
public static class ListItem {
private Long id;
private String name;
@@ -77,6 +67,7 @@ public class CompanyController extends SimpleControllerSupport<Company, CompanyC
@ToString
@AllArgsConstructor
@NoArgsConstructor
@AutoMapper(target = Company.class, convertGenerate = false)
public static class DetailItem {
private Long id;
private String name;

View File

@@ -3,6 +3,10 @@ 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;
@@ -16,47 +20,25 @@ import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("employee")
public class EmployeeController extends SimpleControllerSupport<Employee, EmployeeController.SaveItem, EmployeeController.ListItem, EmployeeController.DetailItem> {
private final CompanyService companyService;
private final Converter converter = new Converter();
public EmployeeController(EmployeeService service, CompanyService companyService) {
public EmployeeController(EmployeeService service) {
super(service);
this.companyService = companyService;
}
@Override
protected Function<SaveItem, Employee> saveItemMapper() {
return item -> {
var employee = new Employee();
employee.setId(item.getId());
employee.setName(item.getName());
employee.setAge(item.getAge());
employee.setRole(Employee.Role.USER);
employee.setCompany(companyService.detailOrThrow(item.getCompanyId()));
return employee;
};
return item -> converter.convert(item, Employee.class);
}
@Override
protected Function<Employee, ListItem> listItemMapper() {
return employee -> new ListItem(
employee.getId(),
employee.getName(),
employee.getAge(),
employee.getRole()
);
return employee -> converter.convert(employee, ListItem.class);
}
@Override
protected Function<Employee, DetailItem> detailItemMapper() {
return employee -> new DetailItem(
employee.getId(),
employee.getCompany().getId(),
employee.getName(),
employee.getAge(),
employee.getRole(),
employee.getCreatedTime(),
employee.getModifiedTime()
);
return employee -> converter.convert(employee, DetailItem.class);
}
@Setter
@@ -64,11 +46,15 @@ public class EmployeeController extends SimpleControllerSupport<Employee, Employ
@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;
}
@Setter
@@ -76,6 +62,7 @@ public class EmployeeController extends SimpleControllerSupport<Employee, Employ
@ToString
@AllArgsConstructor
@NoArgsConstructor
@AutoMapper(target = Employee.class, convertGenerate = false)
public static class ListItem {
private Long id;
private String name;
@@ -88,8 +75,10 @@ public class EmployeeController extends SimpleControllerSupport<Employee, Employ
@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;

View File

@@ -1,8 +1,11 @@
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;
@@ -10,12 +13,15 @@ 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<Report, ReportController.SaveItem, ReportController.ListItem, ReportController.DetailItem> {
private final Converter converter = new Converter();
private final EmployeeService employeeService;
public ReportController(ReportService service, EmployeeService employeeService) {
@@ -25,43 +31,24 @@ public class ReportController extends SimpleControllerSupport<Report, ReportCont
@Override
protected Function<SaveItem, Report> saveItemMapper() {
return item -> {
var report = new Report();
report.setId(item.getId());
report.setScore(item.getScore());
report.setLevel(item.getLevel());
report.setEmployeeId(item.getEmployeeId());
return report;
};
return item -> converter.convert(item, Report.class);
}
@Override
protected Function<Report, ListItem> listItemMapper() {
var mapper = Mappers.getMapper(ListItem.Mapper.class);
return report -> {
var employee = employeeService.detailOrThrow(report.getEmployeeId());
return new ListItem(
report.getId(),
employee.getId(),
employee.getName(),
report.getScore(),
report.getLevel()
);
return mapper.map(report, employee);
};
}
@Override
protected Function<Report, DetailItem> detailItemMapper() {
var mapper = Mappers.getMapper(DetailItem.Mapper.class);
return report -> {
var employee = employeeService.detailOrThrow(report.getEmployeeId());
return new DetailItem(
report.getId(),
employee.getId(),
employee.getName(),
report.getScore(),
report.getLevel(),
report.getCreatedTime(),
report.getModifiedTime()
);
return mapper.map(report, employee);
};
}
@@ -70,6 +57,7 @@ public class ReportController extends SimpleControllerSupport<Report, ReportCont
@ToString
@AllArgsConstructor
@NoArgsConstructor
@AutoMapper(target = Report.class, reverseConvertGenerate = false)
public static class SaveItem {
private Long id;
private Double score;
@@ -88,6 +76,14 @@ public class ReportController extends SimpleControllerSupport<Report, ReportCont
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);
}
}
@Setter
@@ -103,5 +99,15 @@ public class ReportController extends SimpleControllerSupport<Report, ReportCont
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);
}
}
}