Spring MVC

하마·2025년 3월 20일

Spring

목록 보기
12/22

MVC 패턴에 프론트 컨트롤러 패턴, 어댑터 패턴이 적용된 구조를 가지고 있음

Spring MVC 구조


  • DispatcherServlet : Spring의 프론트 컨트롤러
  • View : 인터페이스로 구성되어 있고, 확장성을 가지고 있다.

1. 실행 순서


  1. Client로 부터 HTTP 요청(Request)을 받는다.
  2. Handler 조회
    • Handler Mapping을 통해 요청 URL에 Mapping된 Handler를 조회
  3. Handler를 처리할 Adapter 조회
    • Handler를 처리할 수 있는 Handler Adapter를 조회
  4. Handler Adapter 실행 (handle)
    • 알맞은 어댑터가 존재한다면 Handler Adapter에게 요청을 위임한다.
  5. Handler 실행 (호출)
    • Handler Adapter가 실제 Handler를 호출하여 실행 및 결과 반환
  6. Model And View 반환 (return)
    • Handler Adapter는 Handler가 반환 하는 정보를 ModelAndView 객체로 변환하여 반환
  7. ViewResolver 호출 (알맞은 View 요청)
    • View Resolver를 찾고 실행
  8. View 반환
    • View Resolver는 View의 논리 이름을 물리 이름으로 전환하는 역할을 수행하고 Rendering 역할을 담당하는 View 객체를 반환
  9. View Rendering
    • View를 통해서 View를 Rendering

2. 요약


  • DispatcherServlet
    • 클라이언트 HTTP Request를 알맞게 파싱하고 클라이언트에게 알맞은 응답을 반환
    • 핸들러 목록 정보를 알고있다.
    • 핸들러 어댑터 목록 정보를 알고있다.
  • HandlerAdapter
    • 자신이 처리할 수 있는 Handler인지 확인할 수 있는 기능(Method)이 필요하다.
    • 프론트 컨트롤러에서 요청을 위임받았을 때 핸들러에게 요청을 지시하는 기능이 필요하다.
    • return 시 Handler로부터 전달받은 결과를 알맞은 응답으로 변환한다.
  • Handler
    1. 요청에 대한 비즈니스 로직을 수행한다.

3. 주요 인터페이스


  • org.springframework.web.servlet
    1. HandlerMapping
    2. HandlerAdapter
    3. ViewResolver
    4. View

Controller Interface


Controller Interface를 implements 해서 구현하게 되면
개발자가 원하는 핸들러를 사용할 수 있게 됨

1. 예시 코드


package com.example.springbasicmvc.controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

// Spring Bean 이름을 URL로 설정
@Component("/example-controller")
public class ExampleController implements Controller {

    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("example-controller가 호출 되었습니다.");
        return null;
    }
}

@Component

  • Spring Bean에 등록하는 역할을 수행한다.
    • Spring Bean은 애플리케이션의 구성 요소를 정의하는 객체이다.
    • 마치 Servlet이 Servlet Container에 등록되는 것과 같다.

ExampleController는 어떻게 호출되는가?

  • Handler Mapping
    • 핸들러 매핑에서 ExampleController를 찾을 수 있어야 한다.
      → Spring Bean의 이름으로 핸들러를 찾을 수 있는 핸들러 매핑이 필요하다.
  • Handler Adapter
    • Handler Mapping을 통해 찾은 핸들러를 실행할 수 있는 Handler Adapter가 필요
      → Controller Interface를 실행할 수 있는 Handler Adapter를 찾고 실행한다.

2. Spring Boot의 Handler Mapping과 Handler Adapter


우선 순위

  • HandlerMapping
    1. RequestMappingHandlerMapping
      • 우선순위가 가장 높다
      • Annotation 기반 Controller의 @RequestMapping 에 사용
    2. BeanNameUrlHandlerMapping (위 예시코드에 사용)
      • Spring Bean Name으로 HandlerMapping
  • HandlerAdapter
    1. RequestMappingHandlerAdapter
      • Annotation 기반 Controller의 @RequestMapping 에 서 사용
    2. HttpRequestHandlerAdapter
      • HttpRequestHandler 처리
    3. SimpleControllerHandlerAdapter (위 예시코드에 사용)
      • Controller Interface 처리

3. HttpRequestHandler


// 인터페이스
public interface HttpRequestHandler {
	void handleRequest(HttpServletRequest request, HttpServletResponse response)
					throws ServletException, IOException;

}
// 구현체
@Component("/request-handler")
public class ExampleRequestHandler implements HttpRequestHandler {

	@Override
	public void handleRequest(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {
		System.out.println("request-handler Controller 호출");
		// 구현 로직
	}

}

실행 순서

  1. HandlerMapping 으로 핸들러 조회
    • BeanName으로 Handler 조회 (BeanNameUrlHandlerMapping 실행)
    • ExampleRequestHandler 반환
  2. HandlerAdapter 조회
    • HandleAdapter의 supports()를 우선순위 순서대로 호출
    • HttpRequestHandlerAdapter가 HttpRequestHandler Interface를 지원한다
      • HttpRequestHandlerAdapter.supports()
  3. HandlerAdapter 실행
    • DispatcherServlet이 조회한 HttpRequestHandlerAdapter 를 실행하며 Handler 정보도 넘긴다
    • HttpRequestHandlerAdapter 는 ExampleRequestHandler를 내부에서 실행 후 결과를 반환
      • HttpRequestHandlerAdapter.handle()
        → 단순히 handleRequest를 호출한다 = 오버라이딩된 handleRequest() 호출
      • DispatcherServlet에서 호출 → ha.handle()

View Resolver


반환된 ModelAndView 객체를 알맞은 View로 전달하기 위해 DispatcherServlet에서 ViewResolver를 호출하여 View 정보를 설정하는 역할을 수행한다.

  • application.properties 설정 파일에서 View Resolver를 지정한다.
  • 설정을 기반으로 Spring Boot가 InternalResourceViewResolver를 만든다.
spirng.mvc.view.prefix=/WEB-INF/views/
spirng.mvc.view.suffix=.jsp

1. 예시 코드


package com.example.springbasicmvc.controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

// Spring Bean 이름을 URL로 설정
@Component("/view-controller")
public class ViewController implements Controller {
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {

        System.out.println("view-controller가 호출 되었습니다.");

        // "test"는 논리적인 ViewName이다. ViewResolver가 물리적인 이름으로 변환해야 한다.
        return new ModelAndView("test");
    }
}
<!-- webapp/WEB-INF/form.jsp -->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
  <meta charset="UTF-8">
  <title>블로그 포스트 작성 페이지</title>
</head>
<body>
<h1>블로그 글쓰기</h1>
<form action="save" method="post">
  title: <input type="text" name="title" placeholder="제목" />
  content: <input type="text" name="content" placeholder="내용" />
  <button type="submit">저장</button>
</form>

</body>
</html>

2. 실행 순서

  1. Client로 부터 HTTP 요청(Request)을 받는다.
  2. Handler 조회
    • Handler Mapping을 통해 요청 URL에 Mapping된 Handler를 조회
  3. Handler를 처리할 Adapter 조회
    • Handler를 처리할 수 있는 Handler Adapter를 조회
  4. Handler Adapter 실행 (handle)
    • 알맞은 어댑터가 존재한다면 Handler Adapter에게 요청을 위임한다.
  5. Handler 실행 (호출)
    • Handler Adapter가 실제 Handler를 호출하여 실행 및 결과 반환
  6. Model And View 반환 (return)
    • Handler Adapter는 Handler가 반환 하는 정보를 ModelAndView 객체로 변환하여 반환
  7. ViewResolver 호출 (알맞은 View 요청)
    • View Resolver를 찾고 실행
  8. View 반환
    • View Resolver는 View의 논리 이름을 물리 이름으로 전환하는 역할을 수행하고 Rendering 역할을 담당하는 View 객체를 반환
  9. View Rendering
    • View를 통해서 View를 Rendering

Spring Boot의 ViewResolver


Spring Boot를 사용하면 개발에 필요한 ViewResolver들이 자동으로 등록된다.

1. 우선순위


  • BeanNameViewResolver
    • Bean Name으로 View를 찾아 반환
  • InternalResourceViewResolver (위 예시코드)
    • application.properties 설정 파일에 등록한 prefix, suffix 설정 정보를 사용하여 ViewResolver 등록
// 아래 코드를 자동으로 해주는것과 마찬가지이다.
@Bean
InternalResourceViewResolver internalResourceViewResolver() {
	return new InternalResourceViewResolver("/WEB-INF/views", ".jsp");
}

참고자료


Spring 입문 - 3주차

  • Spring MVC 1강
  • Spring MVC 2강
  • Spring MVC 3강

0개의 댓글