티스토리 뷰
1. DTO를 왜 사용하는지?
DTO(Data Transfer Object)는 말 그대로 데이터를 전송하는 객체이다.
벨덩에서는 "They are flat data structures that contain no business logic." 이라고 정의해뒀다.
<요청 시 DTO를 사용하는 이유>
1. @RequestParam으로 데이터를 일일히 받을 필요 없이 객체 하나로 한꺼번에 받을 수 있다
2. Bean Validation, Contoller에서 검증 기능을 분리할 수 있다.
3. 엔티티 내부를 캡슐화 할 수 있다 (뜬금없는 곳에서 엔티티의 값이 변경되지 않도록 한다)
<응답 시 DTO를 사용하는 이유>
1. 넘겨줄 필요가 없는 데이터를 보내지 않을 수 있다. (화면에 꼭 필요한 데이터만 보내줄 수 있다)
2. 순환참조를 예방할 수 있다
3. 엔티티 내부를 캡슐화 할 수 있다
* 참고 (https://tecoble.techcourse.co.kr/post/2020-08-31-dto-vs-entity/)
@ToString
@Getter @Setter
public class BoardCreateDto {
@Size(max = 50)
@NotBlank
private String title;
@Size(max = 15)
@NotBlank
private String editor;
@NotBlank
private String content;
}
@Slf4j
@RequiredArgsConstructor
@RequestMapping("/api/boards")
@RestController
public class BoardApiController {
private final BoardService boardService;
@PostMapping
public ResponseEntity<?> create(@Valid BoardCreateDto dto) {
Long boardId = boardService.create(dto);
return ResponseEntity.ok(boardId);
}
...
}
View <-> Controller 에서는 DTO를 왜 사용해야 하는지는 아주 잘 이해가 된다.
근데 다음이 문제다..
#2. DTO를 대체 어디서 Entity로 변환할 것인가??
1. Controller에서 DTO를 Entity로 변환하고, Service에는 Entity 객체를 파라미터로 넘기자
<장점>
- 서비스 계층 입장에서는 특정 DTO에 얽매이지 않고, 엔티티에만 의존하기 때문에 유연하고, 재사용성이 높아진다.
<단점/의문점>
- 하나의 DTO 만으로 완전한(값이 다 들어있는) 엔티티를 만들지 못하는 경우가 대부분이다
- 예를들어 게시글 등록을 위한 DTO의 경우, 게시글 ID값이 아직 부여되지 않은 상태..
- 여러 DTO를 모아 하나의 엔티티를 만들어야 하는 경우도 빈번하다.
-> 여러 DTO를 모아 복잡한 엔티티를 만드는 것 자체가 비즈니스 로직일 확률이 매우 높다.
- 파라미터로 받은 Entity는 영속된 상태가 아니라는 것도 조심해야 한다!
* https://www.inflearn.com/questions/53023
2. Controller에서 받은 DTO를 Service에 그대로 넘기고, Service에서 Entity로 변환하자
책이나 강의를 보면서 만드는 프로젝트는 대부분 이 방법을 사용했었다.
<장점>
- 컨트롤러는 엔티티를 알지 못하고 오직 DTO에 대해서만 알고있도록 만들 수 있다
<단점>
- 컨트롤러와 서비스간 결합도가 높아지는 문제가 생긴다.
3. 서비스 DTO와 Mapper를 별도로 만들자!
서비스 요청/응답 시 서비스 계층의 메서드가 사용하는 서비스 DTO를 별도로 만들고, DTO와 서비스 DTO를 매핑하는 Mapper를 끼워넣는 방법이 있다고 한다.
Mapper를 사용하면 얻을 수 있는 장점으로는 RequestDTO가 변경되더라도 ServiceRequest 객체는 변하지 않기 때문에 Mapper만 수정해주면 서비스 계층에는 아무런 영향을 미치지 않는다는 것이다.
-> 매퍼가 중간다리 역할을 해주면서 컨트롤러와 서비스 계층이 완전히 분리되는 효과를 얻을 수 있다!
* https://techblog.woowahan.com/2711/
3번이 이상적으로 보면 가장 바람직한 구조로 보이나,
View -> Controller 에서 RequestDto 하나
Controller -> Service 에서 ServiceRequestDto 하나
Service -> Controller 에서 ServiceResponseDto 하나
Controller -> View 에서 ResponseDto 하나
하나의 요청에 4개의 Dto를 사용해야 한다는 것일까..?
음...... 장단점이 있는 것으로 보인다..
이 글을 쓰면서 개인적으로 든 생각은 2번 방법, 서비스 계층에서 DTO를 그대로 파라미터로 받아 내부에서 엔티티로 변환하는 방법을 기본으로 사용하다가
-> 프로젝트 규모가 커지고, 컨트롤러와 서비스 계층의 분리/모듈화가 필요하다고 느낄 때 Mapper와 서비스 DTO를 만들어 3번으로 넘어가는 것이 좋지 않을까 싶다.
결국 프로젝트 규모에 따라 유동적으로 선택하는 것이 이번 포스팅의 결론이 될 것 같다.
진리의 케바케..
* 참고
- https://kafcamus.tistory.com/12
(+) https://www.baeldung.com/java-dto-pattern
아주 좋아하는 벨덩에서 역시나 DTO에 대한 내용이 있었다.
#6.Common mistakes 에 관한 내용을 대충 정리해봤다
1. 매 상황마다 DTO를 각각 새로 만드는 것은 피하는 것이 좋다.
- 기존의 DTO를 재사용하는 것과 새로 만드는 것의 trade-off를 고려해 봐야함.
- 너무 큰 하나의 DTO로 퉁치는 것은 대부분의 변수가 자주 사용되지 않는 상황이 생기기도 한다.
2. DTO 내부에 비즈니스 로직을 넣지 마라!
3. "LocalDTOs" 라고 하는데, 여러개의 entity 정보를 하나의 DTO에 전부 때려박지 마라는 이야기인 것 같다.
- 이는 DTO 매핑에 대한 유지보수 비용이 발생한다
프로그래밍에 정답이 없다는 것이 참 매력적이긴 하지만 그만큼 힘들기도 한 것 같다.
더 사람을 어렵게 만드는 것은 정답은 없지만 오답은 있다는 것이다
개발자라는 직업이 최선은 못하더라도 최악은 피하기 위해서 계속 공부를 계속 할 수 밖에 없는 것 같다.. ㅜ
'웹 > Spring' 카테고리의 다른 글
@WebMvcTest 에서 Spring Security 적용, 401/403 에러 해결하기 - csrf (4) | 2022.11.22 |
---|---|
스프링 + Thymeleaf로 게시글 비밀번호 기능 구현하기 (0) | 2022.10.29 |
@Valid를 이용한 회원가입 입력값 검증 - 1단계 (0) | 2022.10.19 |
Swagger (Springfox)를 이용해 스프링 프로젝트의 API 문서 만들어보기 (0) | 2022.09.08 |
스프링 부트 | 상대 경로 현재 디렉토리(./)는 어디를 뜻하는 것일까? (1) | 2022.09.06 |