작년에 사이드프로젝트를 진행하면서 api서버를 개발했다. 프론트에서 http 요청 바디에 데이터를 넘겨주면 api서버에서는 무조건 dto로 받기로 했다. 팀원이 그렇게 처음부터 정하고 프로젝트를 진행했기 때문에 왜 dto를 사용해야 되는지 고민해보지를 않았다.
dto를 쓰지 않은 코드를 보면서 역체감으로? 왜 dto를 쓰는게 좋은 지 느끼게 된 바가 있어 글을 작성해보겠습니다. 어디까지나 제 주관적인 생각입니다.
HttpServletRequest getParameter 사용
@RequestMapping("/messages")
public ModelAndView make(HttpServletRequest request) {
String title = request.getParameter("title");
String vGrade = request.getParameter("vGrade");-
String name = request.getParameter("name");
String age = request.getParameter("age");
// 비즈니스 로직 ..
ModelAndView mv = new ModelAndView("/messageView.jsp");
return mv;
}
Http 요청을 통해 데이터를 전송하는 방법은 크게 3가지가 있습니다.
- url 쿼리파라미터(혹은 쿼리스트링)
- post 요청의 form data
- 요청 body의 데이터
1, 2번은 HttpServletRequest의 getParameter로 바로 값을 얻을 수 있다.
(3번은 @RequestBody + dto로 받는 편이 깔끔하다)
이런 방식을 사용할 경우 몇가지 단점이 있다.
1. 파라미터 이름으로 값의 의미를 파악하기 힘들다.
title, age, name 같은 직관적인 이름은 괜찮지만 , vGrade같은 이름은 코드를 처음 보는 사람이 이해하기 힘들다.
2. 어떤 방식으로 데이터가 넘어왔는지 구분할 수 없다.
vGrade가 어떤 값인지 궁금해서 /messages로 요청을 보내는 view 파일을 찾아볼 수 있다. 간단한 파일이라면 상관 없지만, view가 복잡하면 찾는 데 시간이 오래 걸린다. 심지어 form data인지 쿼리스트링인지 모르기 때문에 form 부분, 요청을 보내는 부분의 url을 모두 확인해야 할 수도 있다.
3. 형변환 과정이 필요하다.
age는 나이이므로 int값으로 사용할 것이지만 getParameter로 받으면 String 타입이라 형변환이 필요하다.
(getAttribute 메서드를 사용하면 Object 타입으로 반환받을 수 있긴 하다)
4. 중복이 발생한다.
컨트롤러마다 getParameter로 값을 가져오는 과정이 중복되어 발생한다.
@RequestParam 사용
@RequestMapping("/messagesV2")
public ModelAndView makeV2(@RequestParam String title, @RequestParam(required = true, defaultValue = "19") int age,
@RequestParam String vGrade, @RequestParam String name) {
// 비즈니스 로직 ..
ModelAndView mv = new ModelAndView("/messageView.jsp");
return mv;
}
@RequestParam 애노테이션을 사용할 수 있다.
getParameter의 중복이 해소되고, 형변환 과정도 사라졌다.
추가로 required, defaultValue같은 제한도 둘 수 있어서 유용하다.
하지만 여전히 vGrade가 무엇인지 알기는 어렵고, 쿼리스트링인지 form data인지 알 수 없다.
dto + @ModelAttribute 사용
// Controller
@RequestMapping("/messagesV3")
public ModelAndView makeV3(@ModelAttribute MessageMakeRequest messageMakeRequest,
@ModelAttribute MemberInfoRequest memberInfoRequest,
@RequestParam int page) {
// 비즈니스 로직 ..
ModelAndView mv = new ModelAndView("/messageView.jsp");
return mv;
}
//dto
@Getter
@RequiredArgsConstructor
@ToString
@EqualsAndHashCode
public class MemberInfoRequest {
private final int age;
@NotBlank(message = "NAME 값이 BLANK 입니다")
private final String name;
}
@Getter
@RequiredArgsConstructor
@ToString
@EqualsAndHashCode
public class MessageMakeRequest {
private final String title;
private final String vGrade;
}
dto를 만들고 @ModelAttribute를 사용할 수 있다.
dto를 사용하면 vGrade가 MessageMakeRequest의 필드이기 때문에 메세지를 등록할 때 필요한 값 중 하나라는 것을 쉽게 이해할 수 있다. @RequestParam만 사용한 컨트롤러를 보면 vGrade가 무엇을 위한 값인지 알기 어렵다.
사실 @ModelAttribute와 @RequestParam 모두 쿼리스트링 또는 html form 방식 둘 다 인식한다. 즉 @ModelAttribute로 dto를 사용한다고 해서 이 값은 form으로 넘어왔다고 할 순 없다. 하지만 "쿼리스트링인 경우 @RequestParam을, form data인 경우 관련있는 값 끼리 dto로 묶어서 @ModelAttribute를 사용하자" 와 같은 약속을 한다면 애노테이션을 보고 넘어온 방식을 알 수 있다. 이건 사실 쓰고 보니 좀 억지같다..
추가로 Bean Validation을 사용해 간편하게 검증할 수 있다. 예외메세지도 애노테이션 속성값으로 적을 수 있고 예외도 묶어서 편하게 처리할 수 있어서 편리하다.
결론
사실 별 대단한 내용은 아니지만, 내가 실제로 느낀 점을 토대로 글을 작성하니 뿌듯하다.
개인적인 취향으로는 관련있는 값은 @ModelAttribute로 dto로 묶어서 받고, 쿼리스트링은 @RequestParam으로 받는 편이 깔끔한 것 같다.
'스프링' 카테고리의 다른 글
spring 요청 Validation 검증, 예외 처리 (0) | 2025.01.16 |
---|---|
테스트 시 @Value 사용 (0) | 2024.11.04 |
ApplicationContext (0) | 2024.08.28 |
서블릿과 MVC 패턴과 프론트 컨트롤러 패턴 (1) | 2024.08.27 |
카카오 로그인 (0) | 2024.08.02 |