0. DTO (data transfer object) 란?
데이터 전송 객체
DTO는 기능은 없고 데이터를 전달만 하는 용도로 사용되는 객체를 뜻한다.
참고로 DTO에 기능이 있으면 안되는가? 그것은 아니다.
객체의 주 목적이 데이터를 전송하는 것이라면 DTO라 할 수 있다.
객체 이름에 DTO를 꼭 붙여야 하는 것은 아니다.
대신 붙여두면 용도를 알 수 있다는 장점은 있다.
이전에 설명한 ItemSearchCond 도 DTO 역할을 하지만,
이 프로젝트에서 Cond 는 검색 조건으로 사용한다는 규칙을 정했다. 따라서 DTO를 붙이지 않아도 된다.
ItemSearchCondDto 이렇게 하면 너무 복잡해진다.
그리고 Cond 라는 것만 봐도 용도를 알 수 있다.
참고로 이런 규칙은 정해진 것이 없기 때문에 해당 프로젝트 안에서 일관성 있게 규칙을 정하면 된다.
1. @RequestBody의 동작방식
@Getter만 존재하는데 어떻게 동작하는것일까?
ObjectMapper가 @Getter나 @Setter의 메소드 즉 getName() 과 같은 메소드의 prefix를 때고 첫글자를 소문자로 바꾼뒤
name이라는 값을 얻어서 해당 속성들을 모아 매핑해준다고한다.
https://jwdeveloper.tistory.com/306
https://kim-jong-hyun.tistory.com/60
https://keeeeeepgoing.tistory.com/183
클래스를 생성하면 기본으로 빈생성자가 존재한다.
객체 접근연산자(.)를 이용해서 GetReviewReq.속성이름 = 값 을 통해 값을 넣어주고
그렇게 객체를 반환해주는것 같다.
예)
@Getter
@ToString
public class AddReviewReq {
private long userId;
private long roomId;
private long reviewId;
private long reservationId;
private String content;
}
가 잘동작함. @Getter를 통해 어떤 속성들이 있는지체크, 객체를 생성하고 접근연산자를 통해 값을 넣어서
그 객체를 반환해준다.
2. 날짜관련해서 어떻게 받을까?
sql에서 TimeStamp 형식으로 저장을 해놓은상태에서
DTO에서는 LocalDateTime,LocalDate 등의 타입으로 받는다.
private LocalDateTime updatedAt;
https://keeeeeepgoing.tistory.com/197
예시
public void calculateWeeksAgo() {
LocalDate now = LocalDate.now(ZoneId.of("Asia/Seoul"));
int nowYear = now.getYear();
int updatedYear = updatedAt.getYear();
int nowMonth = now.getMonth().getValue();
int updatedMonth = updatedAt.getMonth().getValue();
int nowDay = now.getDayOfMonth();
int updatedDay = updatedAt.getDayOfMonth();
if (now.isEqual(updatedAt)) {
weeksAgo = "오늘";
return;
}
if (nowYear != updatedYear) {
int gap = nowYear - updatedYear;
weeksAgo = Integer.toString(gap) +"년전";
return;
}
if (nowMonth != updatedMonth) {
int gap = nowMonth - updatedMonth;
weeksAgo = Integer.toString(gap) +"개월전";
return;
}
if (nowDay != updatedDay) {
int gap = nowDay - updatedDay;
weeksAgo = Integer.toString(gap) +"일전";
}
}
위와 같이 하지않아도 날짜 차이를 구할 수 있다. 아래를 참고
[Java] LocalDate, LocalDateTime 날짜 차이 계산하기
JAVA8 의 Time 패키지에서 날짜 차이를 구하는 방법을 알아보자. Duration 사용 Period 사용 ChronoUnit 사용 Duration 두 시간 사이의 간격을 나타낸다. between() 정적 메서드를 사용하면, Duration 객체를 생성해
cornswrold.tistory.com
3. 여러 파라미터를 받아야한다면 DTO를 만들어서 받자.
http Form은 Post방식이지만 쿼리파라미터형식으로 데이터가 들어오기 때문에
컨트롤러에서 파라미터값을 받아야한다.
그럴때 파라미터들을 받을 객체를 만들어두고 @ModelAttribute를 이용해서 한번에 객체로 변환되게끔해서 받자.
4. DTO의 위치는 어디있는게 맞을까?
계층상 작업 순서는 컨트롤러 -> 서비스 -> 리포지토리일것이다.
만약 아이템의 정보를 수정하는 ItemUpdateDto라는 DTO가 있다고할때
Controller
@PostMapping("/{itemId}/edit")
public String edit(@PathVariable Long itemId, @ModelAttribute ItemUpdateDto updateParam) {
itemService.update(itemId, updateParam);
return "redirect:/items/{itemId}";
}
Service
@Override
public void update(Long itemId, ItemUpdateDto updateParam) {
itemRepository.update(itemId, updateParam);
}
Repository
@Override
public void update(Long itemId, ItemUpdateDto updateParam) {
Item findItem = findById(itemId).orElseThrow();
findItem.setItemName(updateParam.getItemName());
findItem.setPrice(updateParam.getPrice());
findItem.setQuantity(updateParam.getQuantity());
}
이렇게 3가지 계층모두에서 ItemUpdateDto를 사용한다.
이때 어느계층에 ItemUpdateDto를 둬야할까? ( 파일을 둬야할까)
ItemUpdateDto가 어디서 사용되기 위해 만들어진 객체인지를 생각한다.
즉, 마지막으로 사용되는곳을 보면된다.
컨트롤러는 서비스의 update메소드를 사용하기 위해 ItemUpdateDto가 필요한거고
서비스도 리포지토리의 update메소드를 사용하기 위해 ItemUpdateDto가 필요한것이다.
즉 결과적으로 리포지토리의 update 메소드에 필요한 객체라는것이다.
(당연한것, 리포지토리에서 데이터에 접근하고 처리하기때문)
그러므로 리포지토리와 같은 계층에 ItemUpdateDto파일을 두는것이 맞다.

결론 - 마지막으로 사용하는곳에서 가지고있으면 된다.
예) 서비스까지만 해당 dto가 전달되고 리포지토리까지 전달되지않는다면 서비스계층에서 해당 dto를 두면된다.
만약 애매하다 그러면 그냥 DTO라는 패키지를 하나 만들어서 사용하면 된다.
'Backend > Spring' 카테고리의 다른 글
| 서버사이드 렌더링 프로젝트 파일위치 주의점 (0) | 2024.04.16 |
|---|---|
| 예외처리 유의점2 (0) | 2023.02.07 |
| insert할때 자동으로 생성되는 키값 가져오기 [미완] (0) | 2023.02.01 |
| Spring) 등록된 Bean 확인하기 (0) | 2023.01.31 |
| Spring] 예외처리 (@ExceptionHandler , @ControllerAdvice,@RestControllerAdvice), 에러코드,실제 적용 (0) | 2023.01.24 |