我現在對如何使用 Spring 在 Rest API 中執行 CRUD 感到困惑。
讓我解釋一下,我有兩條路線來 POST 和 PUT 一個物體。我創建了兩個DTO的createPostRequest和updatePostRequest這一點。因為在添加時,屬性不能為空,而在更新時可以(忽略為空的屬性)。
問題1:
在我的前端,要求用戶從資料庫中選擇一個標簽串列(多選 html)。這就是為什么createPostRequest有一個tags屬性型別TagDTO。但是,我如何使用 modelMapper 來映射,例如,確保標簽存在于資料庫中createPostRequest的Post物體?
例如,如果用戶嘗試插入一個不存在的標簽,我正在考慮做這樣的事情:
postEntity.setTags(tagService.findAllByIds(postEntity.getTagsId()));
這在代碼中造成了很多重復,因為我的物體在服務中的 create 和 update 方法之間,有很多相同的代碼。
問題2:
基于我的問題 1,如何在不重復 2 次代碼的情況下輕松地將我的兩個 DTO 映射到同一個物體?
代碼示例 - PostService (見評論)
這是更新的示例,但是 將有幾乎相同的代碼create,那么我該如何進行呢?
@Transactional
public Post update(Integer postId, UpdatePostRequest request) {
return Optional.ofNullable(this.getById(postId)).map(post -> {
// here how to map non-null properties of my request
// into my post taking in consideration my comment above?
postDAO.save(post);
return post;
}).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
}
================================
更新:
根據要求,找到了下面的代碼。
控制器:
@RestController
@RequestMapping("/v1/posts")
public class PostController {
RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json; charset=UTF-8")
public ResponseEntity<Object> update(@Valid @RequestBody CreatePostRequest createPostRequest) {
Post post = postService.create(createPostRequest);
return new ApiResponseHandler(new PostDTO(post), HttpStatus.OK).response();
}
RequestMapping(value = "/{postId}", method = RequestMethod.PUT, consumes = "application/json", produces = "application/json; charset=UTF-8")
public ResponseEntity<Object> update(@Valid @RequestBody UpdatePostRequest updatePostRequest, @PathVariable Integer postId) {
Post post = postService.update(postId, updatePostRequest);
return new ApiResponseHandler(new PostDTO(post), HttpStatus.OK).response();
}
}
創建郵政請求:
@Data
public class CreatePostRequest {
@NotNull
@Size(min = 10, max = 30)
private Sting title;
@NotNull
@Size(min = 50, max = 600)
private String description
@NotNull
@ValidDateString
private String expirationDate;
@NotNull
private List<TagDTO> tags;
public List<Integer> getTagIds() {
return this.getTags().stream().map(TagDTO::getId).collect(Collectors.toList());
}
}
更新發布請求:
@Data
public class UpdatePostRequest {
@Size(min = 10, max = 30)
private Sting title;
@Size(min = 50, max = 600)
private String description
@ValidDateString
private String expirationDate;
private List<TagDTO> tags;
public List<Integer> getTagIds() {
return this.getTags().stream().map(TagDTO::getId).collect(Collectors.toList());
}
}
服務 :
@Service
@Transactional
public class PostService {
@Transactional
public Post create(CreatePostRequest request) {
ModelMapper modelMapper = new ModelMapper();
Post post = modelMapper.map(request, Post.class);
// map will not work for tags : how to check that tags exists in database ?
return postDAO.save(post);
}
@Transactional
public Post update(Integer postId, UpdatePostRequest request) {
return Optional.ofNullable(this.getById(postId)).map(post -> {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration().setSkipNullEnabled(true);
modelMapper.map(request, post);
// map will not work for tags : how to check that tags exists in database ?
postDAO.save(post);
return post;
}).orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
}
}
uj5u.com熱心網友回復:
為了避免重復兩個相似的 DTO,您可以使用@Validated組驗證。這允許您主動設定要對每個屬性進行哪些驗證。您可以在以下在線資源https://www.baeldung.com/spring-valid-vs-validated 中閱讀更多相關資訊。您將從創建兩個市場介面開始:
interface OnCreate {}
interface OnUpdate {}
然后,您可以將這些標記介面與公共 DTO 中的任何約束注釋一起使用:
@Data
public class CreateOrUpdatePostRequest {
@NotNull(groups = OnCreate.class)
@Size(min = 10, max = 30, groups = {OnCreate.class, OnUpdate.class})
private Sting title;
@NotNull(groups = OnCreate.class)
@Size(min = 50, max = 600, groups = {OnCreate.class, OnUpdate.class})
private String description
@NotNull(groups = OnCreate.class)
@ValidDateString(groups = {OnCreate.class, OnUpdate.class})
private String expirationDate;
@NotNull(groups = OnCreate.class)
private List<TagDTO> tags;
public List<Integer> getTagIds() {
return this.getTags().stream().map(TagDTO::getId).collect(Collectors.toList());
}
}
最后,您只需要相應地在 Controller 中注釋您的方法:
@RestController
@RequestMapping("/v1/posts")
@Validated
public class PostController {
@RequestMapping(method = RequestMethod.POST, consumes = "application/json", produces = "application/json; charset=UTF-8")
public ResponseEntity<Object> update(@Validated(OnCreate.class) @RequestBody CreateOrUpdatePostRequest createPostRequest) {
Post post = postService.create(createPostRequest);
return new ApiResponseHandler(new PostDTO(post), HttpStatus.OK).response();
}
@RequestMapping(value = "/{postId}", method = RequestMethod.PUT, consumes = "application/json", produces = "application/json; charset=UTF-8")
public ResponseEntity<Object> update(@Validated(OnUpdate.class) @RequestBody CreateOrUpdatePostRequest updatePostRequest, @PathVariable Integer postId) {
Post post = postService.update(postId, updatePostRequest);
return new ApiResponseHandler(new PostDTO(post), HttpStatus.OK).response();
}
}
有了這個,您就可以擁有一個映射功能。
盡管如此,請記住,鑒于我們混合了不同的關注點,使用驗證組很容易成為一種反模式。對于驗證組,經過驗證的物體必須知道所有使用它的用例的驗證規則。話雖如此,我通常會避免使用驗證組,除非確實有必要。
關于tags我猜你唯一的選擇是查詢資料庫。那些不存在的你應該創建它們(我猜),所以按照以下幾行:
List<Integer> tagsId = createOrUpdatePostRequest.getTagsId();
List<Tag> tags = tagService.findAllByIds(tagsId);
List<Integer> nonExistentTagsId = tagsId.stream().filter(id -> tags.stream().noneMatch(tag -> tag.getId().equals(id)));
if (!nonExistentTagsId.isEmpty()) {
// create Tags and add them to tags List
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/363264.html
上一篇:無法在java中使用intellij(m1chip硅)安裝hibernate(5.6.0)
下一篇:跨微服務的事務
