Spring MVC

2025. 4. 27. 00:03·BackEnd/Spring Framework

웹 애플리케이션을 개발하다 보면 많은 요청과 응답을 처리해야 합니다. 이런 복잡한 과정을 효율적으로 관리하기 위해 스프링 프레임워크는 MVC 패턴을 기반으로 한 모듈을 제공합니다. 스프링 MVC의 기본 구조와 동작 원리, 그리고 실제 개발에서 어떻게 활용하는지 알아보겠습니다.

스프링 MVC란 무엇인가?

스프링 MVC는 Model-View-Controller(Model2) 아키텍처를 기반으로 하는 스프링 프레임워크의 하위 모듈입니다. 이 구조는 애플리케이션의 관심사를 효과적으로 분리하여 유지보수성과 확장성을 높여줍니다.

주요 구성 요소

스프링 MVC는 크게 세 가지 영역으로 구성됩니다.

  1. DispatcherServlet: 스프링 MVC의 핵심 컴포넌트로, 모든 클라이언트 요청을 가장 먼저 받아 적절한 컨트롤러로 전달하는 프론트 컨트롤러 역할을 합니다.
  2. 스프링 MVC 인프라 컴포넌트:
    • HandlerMapping: 요청 URL을 기반으로 적절한 컨트롤러를 찾아주는 역할
    • HandlerAdapter: 컨트롤러의 메서드를 호출하여 요청을 처리
    • ViewResolver: 컨트롤러가 반환한 뷰 이름을 실제 뷰 객체로 변환
  3. 개발자가 작성하는 영역:
    • 모델(Model): 데이터와 비즈니스 로직을 담당
    • 뷰(View): 사용자에게 보여지는 화면 담당
    • 핸들러(Handler/Controller): 클라이언트의 요청을 처리하는 컴포넌트

스프링 MVC의 동작 흐름

스프링 MVC가 요청을 처리하는 과정은 다음과 같습니다.

  1. 클라이언트가 DispatcherServlet으로 요청을 보냅니다.
  2. DispatcherServlet은 HandlerMapping에게 요청을 처리할 적합한 컨트롤러가 무엇인지 문의합니다.
  3. HandlerMapping은 URL 패턴을 분석하여 해당 요청을 처리할 컨트롤러를 결정하고 반환합니다.
  4. DispatcherServlet은 선택된 컨트롤러를 실행하기 위해 HandlerAdapter에게 요청을 전달합니다.
  5. HandlerAdapter는 컨트롤러(@Controller)에게 요청 처리를 위임합니다.
  6. 컨트롤러는 비즈니스 로직 수행을 위해 서비스 계층을 호출합니다.
  7. 컨트롤러는 처리 결과를 모델 객체에 저장합니다.
  8. 컨트롤러는 뷰 이름을 반환하고, HandlerAdapter는 이를 DispatcherServlet에게 전달합니다.
  9. DispatcherServlet은 ViewResolver에게 뷰 이름을 전달하여 실제 뷰 객체를 요청합니다.
  10. ViewResolver는 뷰 이름을 분석하여 적합한 뷰 객체를 찾아 반환합니다.
  11. DispatcherServlet은 뷰 객체에게 렌더링을 요청합니다.
  12. 뷰는 모델 데이터를 사용하여 응답을 생성하고 클라이언트에게 반환합니다.

이 흐름은 마치 오케스트라의 지휘자와 같이 DispatcherServlet이 요청 처리의 전체 과정을 조율하는 구조입니다.

컨트롤러 작성하기

스프링 MVC에서 컨트롤러는 @Controller 어노테이션을 사용하여 정의합니다. 컨트롤러는 클라이언트의 요청을 받아들이고 적절한 응답을 제공하는 역할을 합니다.

@RequestMapping 어노테이션

@RequestMapping은 요청 URL과 컨트롤러 메서드를 연결하는 어노테이션입니다.

  • 클래스 레벨 매핑: 컨트롤러 클래스의 모든 메서드에 공통으로 적용되는 기본 경로
  • 메서드 레벨 매핑: 특정 메서드에만 적용되는 경로
  • HTTP 메서드 지정: GET, POST 등의 HTTP 메서드를 지정할 수 있으며, @GetMapping, @PostMapping과 같은 축약형 어노테이션도 제공
@Controller
@RequestMapping("/simple")
@RequiredArgsConstructor
public class SimpleController {
    private final SimpleService sService;
    
    @GetMapping("/forward")
    public String forward(Model model) {
        String value = sService.helloMVC();
        model.addAttribute("data", value);
        return "mvc/simple";
    }
    
    @GetMapping("/redirect")
    public String redirect() {
        return "redirect:/simple/forward";
    }
    
    @GetMapping("/json")
    @ResponseBody
    public Map<String, Object> json() {
        return Map.of("name", "hong", "age", 30);
    }
}

요청 처리 메서드의 동작

컨트롤러의 요청 처리 메서드는 다음과 같은 단계로 동작합니다.

  1. 요청 분석: 클라이언트의 요청 데이터(파라미터, 헤더, 쿠키 등)를 분석합니다.
  2. 비즈니스 로직 수행: 서비스 계층을 호출하여 필요한 비즈니스 로직을 처리합니다.
  3. 결과 저장: 처리 결과를 Model 객체에 저장합니다.
  4. 뷰 이름 반환: 결과를 표시할 뷰의 논리적 이름을 반환합니다.

뷰 리졸버 (ViewResolver)

뷰 리졸버는 컨트롤러가 반환한 논리적인 뷰 이름을 실제 뷰 파일의 위치로 변환하는 역할을 합니다. 스프링 부트에서는 application.properties 파일에서 다음과 같이 설정할 수 있습니다.

spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

이 설정은 컨트롤러가 "home"이라는 뷰 이름을 반환하면, "/WEB-INF/views/home.jsp" 파일을 찾아 렌더링하도록 합니다.

컨트롤러 단위 테스트

스프링 MVC 컨트롤러는 MockMvc를 사용하여 효과적으로 테스트할 수 있습니다. MockMvc는 실제 서버 환경 없이도 스프링 MVC의 동작을 시뮬레이션할 수 있습니다.

@WebMvcTest(SimpleController.class)
public class SimpleControllerTest {
    @Autowired
    private MockMvc mockMvc;
    
    @MockBean
    private SimpleService simpleService;
    
    @Test
    public void testForward() throws Exception {
        // 서비스 동작 모의 설정
        when(simpleService.helloMVC()).thenReturn("Hello, MVC!");
        
        // 요청 수행 및 검증
        mockMvc.perform(get("/simple/forward"))
               .andExpect(status().isOk())
               .andExpect(view().name("mvc/simple"))
               .andExpect(model().attributeExists("data"))
               .andExpect(model().attribute("data", "Hello, MVC!"));
    }
}

테스트 과정은 일반적으로 다음 단계로 진행됩니다.

  1. 요청 만들기 (MockMvcRequestBuilders 사용)
  2. 실행 (perform 메서드)
  3. 검증 (andExpect 메서드로 상태, 뷰, 모델 등 확인)
  4. 결과 확인 (필요한 경우 andDo 메서드로 추가 작업 수행)

핸들러 메서드의 파라미터

스프링 MVC의 컨트롤러 메서드는 다양한 타입의 파라미터를 지원합니다. 파라미터의 순서에 관계없이 필요한 객체를 주입받을 수 있습니다.

@RequestParam

@RequestParam은 HTTP 요청의 파라미터를 메서드 파라미터로 바인딩합니다.

@GetMapping("/calc")
@ResponseBody
public Map<String, Integer> calc(
    @RequestParam Integer num1,
    @RequestParam Integer num2,
    @RequestParam String oper
) {
    int result = switch(oper) {
        case "+" -> num1 + num2;
        default -> num1 * num2;
    };
    return Map.of("result", result);
}

이 메서드는 /calc?num1=10&num2=20&oper=+와 같은 요청을 처리합니다.

@ModelAttribute

@ModelAttribute는 요청 파라미터를 객체의 프로퍼티에 바인딩합니다. 객체의 프로퍼티 이름과 요청 파라미터의 이름이 일치하면 자동으로 값이 설정됩니다.

@GetMapping("/regist")
@ResponseBody
public Map<String, Object> regist(@ModelAttribute Member member, Model model) {
    log.debug("member: {}", member);
    model.addAttribute("member", member);
    return Map.of("result", member);
}

이 메서드는 /regist?name=hong&email=hong@example.com&password=1234와 같은 요청을 처리하여 Member 객체의 각 프로퍼티에 값을 설정합니다.

@CookieValue

@CookieValue는 HTTP 요청의 쿠키 값을 메서드 파라미터로 바인딩합니다.

@GetMapping("/welcome")
public String welcome(@CookieValue(value = "userId", required = false) String userId, Model model) {
    if (userId != null) {
        model.addAttribute("message", "Welcome back, " + userId);
    } else {
        model.addAttribute("message", "Welcome new user");
    }
    return "welcome";
}

리다이렉션과 플래시 스코프

스프링 MVC에서는 리다이렉션을 통해 다른 URL로 요청을 전달할 수 있습니다. 리다이렉션 시 데이터를 전달하는 방법에는 여러 가지가 있습니다.

리다이렉션 방법

@GetMapping("/redirect")
public String redirect() {
    return "redirect:/simple/forward";
}

리다이렉션 시 데이터 전달

리다이렉션 시 데이터를 전달하는 방법은 크게 두 가지가 있습니다.

  1. URL 쿼리 파라미터: URL 뒤에 쿼리 스트링을 추가하여 데이터 전달
  2. 플래시 스코프: 리다이렉션이 완료될 때까지만 유지되는 일회성 세션

RedirectAttributes

RedirectAttributes는 리다이렉션 시 데이터 전달을 위한 특별한 객체입니다.

@PostMapping("/process")
public String processForm(RedirectAttributes redirectAttributes) {
    // 처리 로직
    redirectAttributes.addAttribute("status", "success"); // URL 쿼리 파라미터로 추가
    redirectAttributes.addFlashAttribute("message", "처리가 완료되었습니다."); // 플래시 속성으로 추가
    
    return "redirect:/result";
}

플래시 스코프는 요청 스코프보다는 오래 지속되지만 세션 스코프보다는 짧게 유지되며, 리다이렉션 완료 후 자동으로 제거됩니다.

마무리

스프링 MVC는 웹 애플리케이션 개발에 필요한 강력한 구조와 기능을 제공합니다. DispatcherServlet을 중심으로 한 구조는 요청 처리의 흐름을 체계적으로 관리하며, 다양한 어노테이션과 컴포넌트를 통해 개발자가 핵심 비즈니스 로직에 집중할 수 있게 도와줍니다.

컨트롤러 개발부터 뷰 처리, 파라미터 바인딩, 리다이렉션 처리까지, 스프링 MVC는 웹 개발의 다양한 측면을 포괄적으로 지원합니다. 이러한 특성들로 인해 스프링 MVC는 현대 자바 웹 애플리케이션 개발의 표준으로 자리 잡았습니다.

'BackEnd > Spring Framework' 카테고리의 다른 글

MyBatis  (3) 2025.05.03
Interceptor | ErrorPage | FileUpload  (0) 2025.04.30
Spring AOP  (0) 2025.04.26
SpringBoot  (3) 2025.04.24
SLF4J와 JUnit  (2) 2025.04.24
'BackEnd/Spring Framework' 카테고리의 다른 글
  • MyBatis
  • Interceptor | ErrorPage | FileUpload
  • Spring AOP
  • SpringBoot
leve68
leve68
leve68 님의 블로그 입니다.
  • leve68
    leve68
    leve68
  • 전체
    오늘
    어제
    • 분류 전체보기
      • BackEnd
        • Spring Framework
        • Database
      • FrontEnd
        • JavaScript
        • Vue
      • Infra
        • Docker
        • CI CD
      • CS
        • Algorithm
      • Project
        • Web
  • 인기 글

  • 태그

    DATABASE
    sql
    MySQL
    compose
    MyBatis
    springboot
    spring security
    Spring
    SSAFY
    docker
  • 링크

    • github
    • portfolio
  • 최근 글

  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
leve68
Spring MVC
상단으로

티스토리툴바