이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.

  • Controller 메서드의 파라미터는 누가 만들어 주는가?
  • Controller 반환값은 어떻게 View 렌더링 또는 Response Body로 갈라지는가?
  • Fat Controller를 피하려면 요청 처리 책임을 어떻게 나누어야 하는가?

개요

Spring MVC의 Controller는 HTTP 요청을 애플리케이션 로직으로 연결하는 handler다. HandlerAdapter는 Controller 메서드를 호출하기 전에 파라미터를 준비하고, 호출 후 반환값을 해석한다.

기존 MVC 문서의 Request Response Cycle은 이 흐름을 “요청 수신, 핸들러 결정, 핸들러 실행, 서비스 처리, 모델 바인딩, 뷰 렌더링”으로 나누어 설명한다. 새 문서에서는 이 단계를 하나의 실행 흐름으로 압축한다.

원리

Controller 메서드는 선언적이다.

@GetMapping("/members/{id}")
public String member(@PathVariable Long id, Model model) {
    Member member = memberService.find(id);
    model.addAttribute("member", member);
    return "member/detail";
}

여기서 idmodel을 개발자가 직접 만들지 않는다. HandlerAdapter가 적절한 ArgumentResolver를 통해 값을 준비한다. 일반 @Controller에서 반환값 "member/detail"은 view name으로 해석되고 ViewResolver가 실제 View를 찾는다.

REST API에서는 흐름이 다르다.

@GetMapping("/api/members/{id}")
public MemberResponse member(@PathVariable Long id) {
    return memberService.findResponse(id);
}

@RestController@ResponseBody 맥락에서는 반환 객체가 View 이름이 아니라 response body로 처리된다. 이때 HttpMessageConverter가 객체를 JSON 등으로 직렬화한다. 같은 String 반환이라도 일반 MVC Controller에서는 view name이 될 수 있고, REST 맥락에서는 body가 될 수 있으므로 애너테이션 맥락을 함께 봐야 한다.

Controller의 적절한 책임

Controller가 맡기 좋은 책임은 다음과 같다.

  • 요청 경로와 method를 선언한다.
  • 요청 데이터를 DTO나 파라미터로 받는다.
  • 입력 검증 결과를 확인한다.
  • Service를 호출한다.
  • View model 또는 response DTO를 반환한다.
  • HTTP 상태 코드, 헤더, body 모양을 결정한다.

Controller가 맡지 않는 편이 좋은 책임은 다음과 같다.

  • 핵심 비즈니스 규칙
  • 트랜잭션 경계의 복잡한 조정과 도메인 상태 변경 규칙
  • 외부 시스템 호출 정책
  • 긴 분기와 계산 로직

실전 팁

  • Controller는 HTTP adapter로 보고, 업무 규칙은 Service와 Domain으로 밀어낸다.
  • 요청 DTO와 응답 DTO를 분리하면 API 변경과 내부 모델 변경을 독립적으로 다루기 쉽다.
  • Model에 Entity를 그대로 넣을지 DTO를 넣을지는 화면 요구사항과 lazy loading 위험, OSIV 설정, 템플릿에서 접근할 필드 범위를 함께 고려한다.
  • REST API에서 String 반환은 view name인지 body인지 애너테이션 맥락을 반드시 확인한다.
  • Controller 테스트는 “요청 조건, 바인딩, 상태 코드, 응답 구조”를 중심으로 잡는다.

위험 신호!

  • Controller 메서드 하나가 수십 줄의 업무 분기를 가진다.
  • Controller에서 repository를 직접 호출한다.
  • Entity를 그대로 JSON 응답으로 노출한다.
  • 요청 파라미터 파싱을 수동으로 반복한다.
  • View 렌더링 Controller와 REST API Controller의 반환값 의미를 혼동한다.

확인 질문

확인 질문

  • Controller 메서드 파라미터는 누가 준비하는가?
    • HandlerAdapter가 ArgumentResolver를 사용해 준비한다.
  • Controller의 적절한 책임은 무엇인가?
    • HTTP 요청을 해석하고 Service를 호출한 뒤 View model이나 response DTO를 반환하는 것이다.
  • @RestController에서 객체를 반환하면 어떤 일이 일어나는가?
    • 반환 객체가 View 이름이 아니라 response body로 처리되고 MessageConverter가 직렬화한다.

참고 문서