◇ PART · MVC

DispatcherServlet 깊이 보기

URL 분배의 마법

학습 목표

  • DispatcherServlet 의 역할을 안다
  • HandlerMapping 이 URL 을 어떻게 컨트롤러에 매칭하는지 안다
  • ViewResolver 가 ViewName 을 어떻게 JSP 로 변환하는지 안다
  • 「Front Controller」 패턴이 무엇인지 안다

⚠️ 마법처럼 보이는 일

학생이 자주 느끼는 의문

"@GetMapping("/list") 한 줄만 썼는데 — 어떻게 브라우저 요청이 정확히 그 메서드로 도달하지?"

중간에 무언가가 「URL → 메서드」 매핑을 책임지고 있어야 합니다. 그게 DispatcherServlet.

🛠️ DispatcherServlet — 안내데스크

모든 요청의 단일 진입점

큰 식당의 안내데스크처럼, 모든 손님(요청)을 한 곳에서 받아 적절한 종업원(Controller)에게 안내하는 부품.

요청 1 → ┐ 요청 2 → │ 요청 3 → ├→ DispatcherServlet → 적절한 Controller 요청 4 → │ 요청 N → ┘

👉 이 패턴을 「Front Controller」 라고 부릅니다.

web.xml 에 한 번만 등록


<web-app>
    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>     <!-- 모든 URL -->
    </servlet-mapping>
</web-app>

👉 url-pattern=/ = 「모든 URL 을 이 Servlet 으로 보내라」.

한 요청의 9 단계 여정

① 브라우저: GET /board/view/3 ↓ ② Tomcat 이 받음 ↓ ③ DispatcherServlet 에 위임 ↓ ④ DispatcherServlet → HandlerMapping "이 URL 누가 처리?" → BoardController.view 메서드 ↓ ⑤ DispatcherServlet → HandlerAdapter Controller 메서드 호출 ↓ ⑥ Controller 실행 → Service → DB → 결과 Model 에 데이터 담고 ViewName 반환 ↓ ⑦ DispatcherServlet → ViewResolver "board/view" → /WEB-INF/views/board/view.jsp ↓ ⑧ JSP 가 Model 데이터로 HTML 생성 ↓ ⑨ 응답

핵심 부품 3 가지

부품역할
HandlerMappingURL → Controller 메서드 매칭
HandlerAdapter실제로 메서드를 호출하는 부품
ViewResolverViewName → 실제 View 파일 매핑

👉 우리가 직접 다루지 않음. Spring 이 자동으로 사용. 단 ViewResolver 만 설정에서 prefix/suffix 지정.

HandlerMapping — URL 매칭


// Spring 이 시작될 때 모든 @Controller 를 스캔해서
// HandlerMapping 에 다음 같은 표를 만듦:

URL 패턴               메서드
─────────────────────────────────────────
GET /board/list        BoardController.list
GET /board/view/{id}   BoardController.view
POST /board/write      BoardController.write
GET /api/boards        BoardApiController.list
...

👉 요청이 오면 이 표에서 매칭되는 메서드를 찾아 호출.

ViewResolver — 이름을 경로로


<!-- servlet-context.xml -->
<bean id="viewResolver"
      class="...InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/" />
    <property name="suffix" value=".jsp" />
</bean>
Controller 가 return "board/view" 했다면: prefix + ViewName + suffix /WEB-INF/views/ + board/view + .jsp ↓ /WEB-INF/views/board/view.jsp ↓ 해당 JSP 파일을 찾아 모델 데이터로 HTML 렌더링

왜 「Front Controller」 패턴인가

모든 요청이 하나의 진입점을 거치면 좋은 점:

  • 공통 처리 한 곳 — 인코딩·로깅·인증 등을 매 컨트롤러에서 반복 안 해도 됨
  • 일관된 요청 처리 흐름
  • 인터셉터·필터 등을 쉽게 끼워넣을 수 있음
  • 매핑 규칙을 중앙에서 관리

인터셉터와의 관계

요청 ↓ DispatcherServlet ↓ HandlerMapping (어느 컨트롤러?) ↓ ⭐ Interceptor.preHandle() ├─ false → 컨트롤러 호출 안 함 (예: 비로그인 차단) └─ true → 다음으로 ↓ Controller 실행 ↓ ⭐ Interceptor.postHandle() (응답 전 후처리) ↓ ViewResolver → JSP ↓ ⭐ Interceptor.afterCompletion() (응답 완료 후) ↓ 응답

👉 인터셉터가 끼어들 자리도 DispatcherServlet 이 만들어준 흐름의 일부.

그림으로 한 번 더 — 매핑 단계

┌────────────┐ 요청 GET /board ─→│ │ │ Dispatcher│ │ Servlet │ │ │ └─────┬──────┘ │ ▼ HandlerMapping "GET /board?" → BoardController.list │ ▼ HandlerAdapter 호출: BoardController.list(model)

그림으로 한 번 더 — 응답 단계

┌────────────┐ │ Controller │ │ Service → │ │ Mapper → │ │ DB │ └─────┬──────┘ │ "board/list" ▼ ViewResolver /WEB-INF/views/board/list.jsp │ ▼ JSP 렌더링 │ ▼ 응답 ←

실험 — 자세한 로그 켜기


<!-- log4j2.xml -->
<Logger name="org.springframework.web" level="DEBUG" />
<Logger name="org.springframework.web.servlet" level="TRACE" />

이렇게 하면 콘솔에 다음 같은 로그:


DispatcherServlet : GET "/board/view/3"
RequestMappingHandlerMapping : Mapped to BoardController#view(int, Model)
BoardController : view(3) called
View : Resolved to '/WEB-INF/views/board/view.jsp'
DispatcherServlet : Completed 200 OK

👉 매 요청의 9 단계 여정이 그대로 보임.

「URL 안 됨」 시 진단

증상의심할 곳
404HandlerMapping 에 등록 안 됨 — @Controller·component-scan 확인
405 Method Not Allowed매핑된 HTTP 메서드와 요청 메서드 불일치
"Could not resolve view"ViewResolver prefix/suffix 또는 JSP 파일 경로
정적 파일(CSS·JS·이미지) 안 보임servlet-context.xml 의 <mvc:resources> 매핑

Spring Boot 와의 비교

Spring Boot 도 내부적으로 DispatcherServlet 을 사용 — 단지 자동 등록.

  • Boot: @SpringBootApplication 한 줄에 자동
  • Legacy: web.xml 에 직접 등록

기본 동작은 동일. Legacy 에서 한 번 명시적으로 보면 — Boot 가 무엇을 자동화하는지 보임.

🔄 Before / After

전 차시 끝

DispatcherServlet 의 이름은 알지만 무슨 일을 하는지 막연.

이번 차시 끝

URL 매칭 → 메서드 호출 → ViewResolver 의 9 단계 여정을 그릴 수 있다.

이번 차시의 데이터 흐름

URL
DispatcherServlet
HandlerMapping
Controller
ViewResolver
JSP
「안내데스크」 와 두 부품이 흐름에 자리 잡음

정리

오늘 들고 가는 것

  • DispatcherServlet = 모든 요청의 단일 진입점 (Front Controller)
  • HandlerMapping 이 URL → 컨트롤러 메서드 매칭
  • ViewResolver 가 ViewName → 실제 View 파일
  • 인터셉터 끼어드는 자리도 이 흐름의 일부

다음: Controller 해부.