[LG U+ 유레카 3기]Spring MVC 요청 흐름 & 매핑 실습 — Boot 위에서 레거시 구조 이해하기

2025. 11. 4. 16:12Java/Spring

0️⃣ 실습 개요

오늘은 STS4(Spring Boot 환경)에서 Spring MVC 구조를 직접 구현하고, 요청 매핑(@RequestMapping, @GetMapping 등), PathVariable, 와일드카드 매핑을 실습했다.

Spring Boot 위에서 실행했지만, 내부 동작은 전통적인 Spring Legacy MVC 구조였다. 즉, DispatcherServlet 중심의 JSP 기반 MVC 흐름을 Boot 환경에서 재현한 형태다.


1️⃣ pom.xml (의존성 설정)

JSP를 사용하기 위해서는 Spring Boot 기본 Web Starter 외에 tomcat-embed-jasper 의존성을 반드시 추가해야 한다.


<project xmlns="http://maven.apache.org/POM/4.0.0" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.5.7</version>
  </parent>

  <groupId>com.mycom</groupId>
  <artifactId>SpringMVCPractice</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <dependencies>
    <!-- 기본 웹 스타터 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- JSP 렌더링을 위한 Jasper 추가 -->
    <dependency>
      <groupId>org.apache.tomcat.embed</groupId>
      <artifactId>tomcat-embed-jasper</artifactId>
    </dependency>

    <!-- 개발 편의용 (자동 리빌드 등) -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <scope>runtime</scope>
      <optional>true</optional>
    </dependency>

    <!-- 테스트 관련 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

2️⃣ application.properties (뷰 리졸버 설정)


spring.application.name=SpringBootMVC

# JSP 위치 설정
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp

JSP 파일은 /WEB-INF/jsp 폴더 아래에 위치해야 하며, 직접 브라우저 접근이 불가능하다 (보안상 접근 불가). 즉, 반드시 Controller → ViewResolver → JSP 흐름으로 접근해야 한다.

수업을 듣기전에는 이런 에러가 나오면 정확히 무슨뜻인지는 몰랐지만 느낌상으로만 진행해왔었다.

하지만 강사님의 디버그 느낌으로 설명해주시니 이런 에러들의 정확한 속뜻도 이해하게되고 디버그 실력을 늘리는 느낌을 받았다.


3️⃣ aspect.xml (Spring 설정 파일)

이번 실습에서는 별도의 Bean 설정은 하지 않았지만, Spring XML 설정 형식을 복습하기 위해 아래 예시를 참고했다.


<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context.xsd">

  <!-- Component Scan (Controller, Service 등 자동 탐색) -->
  <context:component-scan base-package="com.mycom.myapp.controller" />

</beans>

4️⃣ HelloController.java


package com.mycom.myapp.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class HelloController {

    // http://localhost:8080/hello
    @GetMapping("/hello")
    public String hello() {
        System.out.println("/hello 요청됨");
        return "hello"; // → /WEB-INF/jsp/hello.jsp
    }
}

5️⃣ UrlMappingController.java

요청 매핑(@RequestMapping, @GetMapping 등), PathVariable, 와일드카드 매칭까지 모두 실습했다.


package com.mycom.myapp.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

@Controller
public class UrlMappingController {

    // ❌ 구버전 방식 - 지양
    @RequestMapping(value = "/m1", method = RequestMethod.GET)
    public void m1() {
        System.out.println("/m1");
    }

    // ✅ 최신 RESTful 방식
    @GetMapping("/m2")
    public void m2() {
        System.out.println("/get");
    }

    @PostMapping("/m3")
    public void m3() {
        System.out.println("/post");
    }

    @PutMapping("/m4")
    public void m4() {
        System.out.println("/put");
    }

    @DeleteMapping("/m5")
    public void m5() {
        System.out.println("/delete");
    }

    // PathVariable 실습
    @GetMapping("/books/{bookId}")
    public void m6(@PathVariable("bookId") int bookId) {
        System.out.println("/books");
        System.out.println(bookId);
    }

    @GetMapping("/books/{limit}/{offset}")
    public void m7(@PathVariable("limit") int limit,
                   @PathVariable("offset") int offset) {
        System.out.println("/books");
        System.out.println(limit);
        System.out.println(offset);
    }

    // ❌ 중복 패턴 충돌 (Ambiguous)
    @GetMapping("/books/{abc}")
    public void m9(@PathVariable("abc") int abc) {
        System.out.println("/books");
        System.out.println(abc);
    }

    // 복수 매핑
    @GetMapping(value = { "/url1", "/url2" })
    public void m8() {
        System.out.println("/url1,/url2");
    }

    // 하위 경로 1단계만 허용 (*)
    @PostMapping("/sub1/*")
    public void m10() {
        System.out.println("/sub1");
    }

    // 하위 경로 전체 허용 (**)
    @PostMapping("/sub2/**")
    public void m11() {
        System.out.println("/sub2");
    }
}

6️⃣ hello.jsp (뷰 파일)


<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <title>Hello JSP</title>
</head>
<body>
  <h1>Spring MVC Hello Page</h1>
  <p>이 JSP는 Controller를 통해 DispatcherServlet이 렌더링한 View입니다.</p>
</body>
</html>

7️⃣ Postman 테스트 요약

URL HTTP 메서드 결과 콘솔 출력
/m1 GET /m1
/m2 GET /get
/m3 POST /post
/m4 PUT /put
/m5 DELETE /delete
/books/123 GET /books, 123
/books/10/20 GET /books, 10, 20
/books/456 GET Ambiguous handler exception
/url1 GET /url1,/url2
/url2 GET /url1,/url2
/sub1/abc POST /sub1
/sub1/abc/def POST 매칭 실패
/sub2/abc/def POST /sub2

8️⃣ 실습 핵심 요약

  • DispatcherServlet이 모든 요청을 받아서 Controller로 위임한다.
  • @RequestMapping은 구버전 매핑 방식이며, @GetMapping 등으로 대체된다.
  • @PathVariable로 URL 내 변수를 쉽게 전달할 수 있다.
  • * → 하위 1단계, ** → 모든 하위 단계 매칭
  • tomcat-embed-jasper를 추가해야 JSP 렌더링 가능
  • Spring Boot로 실행되지만, 내부 구조는 전통적인 Spring MVC 동작 방식

✅ 결론

오늘 실습은 Spring Boot 환경에서 JSP 기반 MVC를 직접 구현하면서, DispatcherServlet의 흐름URL 매핑 방식을 이해하고, RESTful 설계 원칙(GET/POST/PUT/DELETE), PathVariable, 와일드카드 패턴(*, **)을 직접 검증해본 시간이었다.

즉, Boot의 자동 구성 위에서 레거시 MVC 패턴을 체험하며 Spring의 전통적인 요청 처리 구조를 완전히 이해하는 실습이었다.