本文是關於如何在api請求體和響應體中使用DTO,以及如何在DTO和實體之間進行映射。
爲什麼使用DTO而不是實體?
- 更新實體有時只更新實體的一部分,如果在請求體中使用實體,當您只傳遞實體中的部分字段時,其他字段將是實體的默認值或null。如果實體的字段太多,更新將變得非常麻煩。
- 通過使用僅傳遞您需要的字段的不同DTO,它將使請求更加高效和簡潔。
- Spring MVC自動將請求參數綁定到bean,聲明爲使用@RequestMapping註釋的方法的參數。由於這種自動綁定功能,可以在@RequestMapping帶註釋的方法的參數上提供一些意外的字段。參考自:https://rules.sonarsource.com/java/tag/spring/RSPEC-4684。
你什麼時候需要DTO?
通常我們需要在創建,更新實體時創建DTO或在api中返回一些json數據。
1.創建一個實體
創建實體時,我們需要創建一個DTO來重現字段。在大多數情況下,DTO包含所有字段的實體,並且每個實體應該只有一個創建DTO。
我們應該只包含DTO中需要的字段,並將所有需要字段傳遞給DTO而不使用空值。
例如,當您創建job時,如果創建job操作僅創建具有一些基本信息的作業,您只需要從請求傳遞必需的字段並創建DTO來處理傳遞的字段,
所以DTO只包含創建實體所必需的字段。在DTO中,使用驗證來驗證字段的完整性。例如
public class JobDto {
private Long jobId;
@NotBlank(message = "The job title couldn't be empty!")
private String title;
@NotBlank(message = "The job employment type couldn't be empty!")
private String employmentType;
...
}
使用@Valid註釋來驗證它,如果驗證沒有通過,它將拋出異常:
@PostMapping(value = "/jobs")
@PreAuthorize("hasAuthority('create_job')")
public JobDetail createJob(@RequestBody @Valid final JobDto job) {
...
}
2.更新實體
更新實體時,如果更新是完全更新,我們可以使用在步驟1中創建的實體。如果更新是部分更新,我們需要創建新端點以進行更新並創建新的DTO以重新獲取字段。
例如,當我們需要更新job的描述,但我們不想傳遞job的所有字段時,我們應該添加一個端點來處理更新,並創建一個DTO來重新接收該字段。例如
@Data
@NoArgsConstructor
public class JobDescriptionUpdatePojo {
private String description;
}
@PatchMapping("jobs/{id}/job-description")
@PreAuthorize("hasPermission(#jobId,'change_job')")
public JobInfoDto updateJobDescription(@PathVariable final Long id,
@RequestBody final JobDescriptionUpdatePojo jobDescriptionUpdatePojo) {
final Job job = jobService.findJobById(id);
return jobMapper.convertToJobInfoDto(jobService
.updateJobDescription(JobDescriptionUpdatePojo, job));
}
3.返回json數據
當我們在api中返回json數據時,我們需要創建一個DTO來返回數據,而DTO應該只包含我們需要的字段。
使用MapStruct進行映射,我們需要將依賴項添加到項目的pom.xml文件中:
< dependency >
< groupId > org.mapstruct </ groupId >
< artifactId > mapstruct-jdk8 </ artifactId >
< version > 1.3.0.Final </ version >
</ dependency >
< dependency >
< groupId > org.mapstruct </ groupId >
< artifactId > mapstruct-processor </ artifactId >
< version >1.3.0.Final</ version >
</ dependency >
配置映射器
這是所有映射器的全局配置,如果你真的需要使用不同的配置,請創建另一個。
|
Config接口爲mapper提供了一些基本配置。
- 使用構造注入來注入映射器。
- 對於映射,將忽略空值,僅對@MappingTarget註釋有效。
- 使任何DTO轉換爲實體忽略id字段。
用於映射的接口
一個實體對應一個映射器,定義以下方法以區分映射器的不同用法:
- createFrom {DTOName}:將DTO轉換爲新實體,執行映射時將忽略“id”字段,因爲它是最常見的用例作爲主鍵。
- updateFrom {DTOName}:將DTO轉換爲現有實體,實體param是存在的實體,此方法將用DTO的同名字段替換實體的字段。
- convertToDto:使用相同的字段將實體轉換爲DTO。
|
映射器示例
- 將@Mapper註釋與您的自定義配置一起使用並根據需要導入值,MapStruct將自動生成接口的實現,就像Spring中的存儲庫一樣。
- 使用@Mapping註釋來配置方法,註釋爲目標字段值提供表達式。
- 使用@Mapping(target =“targetField”,source =“sourceField”)來指定映射字段,如果字段名稱相同,則無需配置,它將自動映射。
|
示例使用映射器
- 使用構造注入來注入您需要的映射器
- 使用mapper轉換實體或DTO
|