@RequestParam 대신 @ModelAttribute 를 선택한 이유

Lui.Slki·2026년 3월 12일

SpringBoot

목록 보기
1/2

@RequestParam 가독성 이슈

검색 기능을 만들면서 검색 조건이 점점 많아졌다.

처음에는 각각 @RequestParam 으로 받을 수도 있었지만, 조건이 늘어날수록 컨트롤러 메서드 시그니처가 복잡해지고 가독성이 떨어질 수 있었다.

예를 들면 이런 식이다.

@GetMapping
public ResponseEntity<?> searchArtists(
        @RequestParam(required = false) String keyword,
        @RequestParam(required = false) InstrumentCategory instCategory,
        @RequestParam(required = false) List<Long> instIds,
        @RequestParam(required = false) List<Long> styleTagIds
) {
    ...
}

검색 조건이 더 추가될 가능성까지 생각하면, 이 방식은 유지보수에 불리하다고 판단했다.


해결 방식

검색 조건을 하나의 DTO로 묶고, 컨트롤러에서는 @ModelAttribute 로 받도록 구성했다.

  • DTO
@GetMapping
public ResponseEntity<?> searchArtists(
        @RequestParam(required = false) String keyword,
        @RequestParam(required = false) InstrumentCategory instCategory,
        @RequestParam(required = false) List<Long> instIds,
        @RequestParam(required = false) List<Long> styleTagIds
) {
    ...
}
  • Controller
@GetMapping
public ResponseEntity<List<ArtistSearchResponse>> searchArtists(
        @ModelAttribute ArtistSearchRequest req
) {
    return ResponseEntity.ok(artistSearchService.searchArtists(req));
}

@ModelAttribute가 하는 일

@ModelAttribute 는 요청 파라미터를 보고 DTO 객체를 자동으로 바인딩해준다.
예를 들어 다음과 같은 GET 요청이 들어오면

GET /artists?keyword=플룻&instCategory=WOODWIND&instIds=1&instIds=2&styleTagIds=3

스프링은 이를 자동으로 다음과 같은 형태의 객체로 묶어준다.

new ArtistSearchRequest(
    "플룻",
    InstrumentCategory.WOODWIND,
    List.of(1L, 2L),
    List.of(3L)
)

즉, 검색 조건을 하나의 의미있는 객체로 관리할 수 있게 된다.


왜 @RequestBody 가 아닌 @ModelAttribute인가

이번 검색 API는 GET 요청 기반이다.
일반적으로 GET 요청 검색 조건은 body가 아니라 query parameter로 전달된다.
따라서 해당 조건에서는 @ModelAttribute가 더 자연스럽다.


언제 @RequestParam이 더 낫고, 언제 @ModelAttribute가 더 낫냐

@RequestParam 이 괜찮은 경우

  • 파라미터 개수가 적음
  • DTO 따로 만들기 애매함
  • 검색 조건이 자주 안바뀜
  • 빠르게 구현할 때

@ModelAttribute 가 더 Best 인 경우

  • 검색 조건이 많음
  • 앞으로 조건이 늘어날 가능성이 큼
  • 컨트롤러 시그니처가 너무 길어짐
  • 서비스/레포까지 검색 조건 객체를 그대로 넘기고 싶음

정리

이번 검색 API 에서는 @ModelAttribute 를 사용해 검색 조건을 하나의 DTO로 묶었다.
그 결과:

  • 컨트롤러 메서드 시그니처가 단순해졌고
  • 검색 조건 추가 시 확장성이 좋아졌으며
  • 서비스, 레포지토리 계층으로 객체를 그대로 넘길 수 있어 구조도 더 명확해졌다.

검색 조건이 늘어나는 조회 API라면 @ModelAttribute는 실용적인 선택이었다고 판단한다.

0개의 댓글