🌐 Spring Boot 없이 IntelliJ 유료버전으로 전통적인 Spring MVC 프로젝트 구성하기

Spring Boot 없이 IntelliJ 유료버전으로 전통적인 Spring MVC 프로젝트를 구성하겠습니다.

1. IntelliJ에서 Maven 프로젝트 생성

  1. File → New → Project
  2. 좌측메뉴 Generators에서 Maven Archetype 선택
  3. name : 임의의 값 설정 예) spring-mvc-app
  4. archetype select box 선택 
  5. maven-archetype-webapp 선택
  6. Advanced Settings 선택 
  7. GroupId: 임의의 값 설정 예)  com.example, ArtifactId: spring-mvc-app 입력
  8. Create 버튼 선택
  9. 프로젝트 생성 확인 
[INFO] Archetype repository not defined. Using the one from [org.apache.maven.archetypes:maven-archetype-webapp:1.5] found in catalog remote
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Old (1.x) Archetype: maven-archetype-webapp:1.0
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: basedir, Value: C:\Users\사용자명\AppData\Local\Temp\archetype2tmp
[INFO] Parameter: package, Value: com.example
[INFO] Parameter: groupId, Value: com.example
[INFO] Parameter: artifactId, Value: spring-mvc-app
[INFO] Parameter: packageName, Value: com.example
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: C:\Users\사용자명\AppData\Local\Temp\archetype2tmp\spring-mvc-app2
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  11.405 s
[INFO] Finished at: 2025-08-29T15:11:57+09:00
[INFO] ------------------------------------------------------------------------

Process finished with exit code 0

2. pom.xml 설정

<?xml version="1.0" encoding="UTF-8"?>
<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 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.example</groupId>
    <artifactId>spring-mvc-app</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring.version>5.3.21</spring.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    
    <dependencies>
        <!-- Spring Core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        
        <!-- Spring Context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        
        <!-- Spring Web MVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        
        <!-- Servlet API -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
        
        <!-- JSP API -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.3</version>
            <scope>provided</scope>
        </dependency>
        
        <!-- JSTL -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>
    
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.3</version>
            </plugin>
        </plugins>
    </build>
</project>

3. 디렉토리 구조 생성

다음 디렉토리들을 생성하세요:

spring-mvc-app/
├── pom.xml                           # Maven 설정 파일
├── src/
│   └── main/
│       ├── java/                     # Java 소스 코드
│       │   └── com/example/
│       │       └── controller/       # Spring MVC 컨트롤러
│       ├── resources/                # 설정 파일, 프로퍼티 파일
│       └── webapp/                   # 웹 리소스
│           ├── WEB-INF/              # 외부 접근 차단 디렉토리
│           │   ├── web.xml          # 웹 애플리케이션 설정
│           │   ├── dispatcher-servlet.xml  # Spring 설정
│           │   └── views/           # JSP 파일들
│           └── index.jsp            # 정적 웹 파일
└── target/                          # Maven 빌드 결과물

4. web.xml 설정

src/main/webapp/WEB-INF/web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
    
    <display-name>Spring MVC Application</display-name>
    
    <!-- Spring DispatcherServlet -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    <!-- Character Encoding Filter -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

5. Spring 설정 파일

src/main/webapp/WEB-INF/dispatcher-servlet.xml:

<?xml version="1.0" encoding="UTF-8"?>
<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"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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
           http://www.springframework.org/schema/mvc 
           http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    
    <!-- Component Scan -->
    <context:component-scan base-package="com.example.controller" />
    
    <!-- Enable MVC -->
    <mvc:annotation-driven />
    
    <!-- View Resolver -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>
    
    <!-- Static Resources -->
    <mvc:default-servlet-handler />
</beans>

6. Controller 클래스

src/main/java/com/example/controller/MainController.java:

package com.example.controller;

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

@Controller
public class MainController {
    
    @GetMapping("/main")
    public String main(Model model) {
        model.addAttribute("message", "Hello World");
        return "main";
    }
    
    @GetMapping("/")
    public String home() {
        return "redirect:/main";
    }
}

7. JSP 파일

src/main/webapp/WEB-INF/views/main.jsp:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Spring MVC Hello World</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            margin-top: 100px;
        }
        h1 {
            color: #4CAF50;
        }
    </style>
</head>
<body>
    <h1>${message}</h1>
    <p>Spring MVC without Spring Boot</p>
    <p>현재 시간: <%= new java.util.Date() %></p>
</body>
</html>

8. Tomcat 서버 설정 (IntelliJ)

  1. Run → Edit Configurations
  2. + 버튼 클릭 → Tomcat Server → Local
  3. Server 탭에서 Tomcat 경로 설정
  4. Deployment 탭에서:
    • + 클릭 → Artifact
    • spring-mvc-app:war exploded 선택
    • Application context: '/' 로 설정
    • OK 버튼 선택 

9. 실행

  1. Maven 의존성 다운로드: 터미널에서 mvn clean compile 실행 
  2. IntelliJ에서 Tomcat 서버 실행
  3. 브라우저에서 http://localhost:8080/main 접속

이제 "Hello World"가 출력되는 전통적인 Spring MVC 웹 애플리케이션이 완성되었습니다. JSP를 통해 동적 콘텐츠를 렌더링하고, Spring MVC의 컨트롤러가 요청을 처리합니다.


10. HTTP 요청 처리 과정

전체 흐름도

Client Request → Tomcat → DispatcherServlet → HandlerMapping → Controller → ViewResolver → JSP → Response

상세 처리 과정

1단계: 클라이언트 요청

브라우저에서 http://localhost:8080/main 요청

2단계: 서블릿 컨테이너 (Tomcat)

  • Tomcat이 HTTP 요청을 받음
  • web.xml을 확인하여 어떤 서블릿이 처리할지 결정
  • / 패턴이므로 DispatcherServlet으로 전달

3단계: DispatcherServlet 처리1

// 내부적으로 다음과 같은 과정을 거침
1. HandlerMapping을 통해 요청 URL에 맞는 컨트롤러 메소드 찾기
2. HandlerAdapter를 통해 컨트롤러 메소드 실행
3. 컨트롤러 실행 결과(ModelAndView) 받기
4. ViewResolver를 통해 뷰 이름을 실제 뷰로 변환
5. 뷰 렌더링 및 응답 생성


4단계: 컨트롤러 실행

@GetMapping("/main")
public String main(Model model) {
    model.addAttribute("message", "Hello World");  // 모델에 데이터 추가
    return "main";  // 뷰 이름 반환
}


5단계: 뷰 처리

  • ViewResolver가 "main"을 "/WEB-INF/views/main.jsp"로 변환
  • JSP 엔진이 JSP 파일을 처리
  • EL 표현식 ${message}를 "Hello World"로 치환

6단계: 응답 생성

  • 최종 HTML이 생성되어 클라이언트로 전송

 

11. Spring MVC 핵심 구성 요소

1. DispatcherServlet

// Spring이 제공하는 핵심 서블릿
public class DispatcherServlet extends FrameworkServlet {
    // 모든 HTTP 요청의 진입점
    // Front Controller 패턴의 구현체
}

2. HandlerMapping

  • URL과 컨트롤러 메소드를 매핑
  • @RequestMapping 어노테이션을 분석하여 매핑 정보 생성

3. Controller

@Controller  // Spring이 이 클래스를 컨트롤러로 인식
public class MainController {
    
    @GetMapping("/main")  // GET 요청 "/main"을 이 메소드가 처리
    public String main(Model model) {
        // 비즈니스 로직 처리
        model.addAttribute("message", "Hello World");
        // 뷰 이름 반환
        return "main";
    }
}

4. Model

  • 컨트롤러와 뷰 사이의 데이터 전달 객체
  • 뷰에서 사용할 데이터를 저장

5. ViewResolver

  • 컨트롤러가 반환한 뷰 이름을 실제 뷰 객체로 변환
  • JSP, Thymeleaf, FreeMarker 등 다양한 뷰 기술 지원

6. JSP와 EL(Expression Language)

JSP 태그들

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!-- JSP 페이지 설정 -->

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- JSTL 코어 태그 라이브러리 사용 -->


EL 표현식

${message}  <!-- model.addAttribute("message", "Hello World")로 설정한 값 출력 -->

7. 개발 및 배포 과정

Maven 빌드 과정

mvn clean compile  # 컴파일
mvn package        # WAR 파일 생성


생성되는 파일들

target/
├── classes/                    # 컴파일된 .class 파일들
├── spring-mvc-app-1.0-SNAPSHOT.war  # 배포용 WAR 파일
└── spring-mvc-app-1.0-SNAPSHOT/     # Exploded WAR (개발용)

Tomcat 배포

  1. 개발 시: Exploded WAR를 사용하여 실시간 반영
  2. 운영 시: WAR 파일을 Tomcat의 webapps 디렉토리에 배치

8. 전체 아키텍처 이해

이 프로젝트는 3-Tier Architecture를 따릅니다:

1. Presentation Layer (프레젠테이션 계층)

  • JSP, HTML, CSS, JavaScript
  • 사용자 인터페이스 담당

2. Business Layer (비즈니스 계층)

  • Spring MVC Controller
  • 비즈니스 로직 처리

3. Data Layer (데이터 계층)

  • 현재는 없지만, 보통 Repository, DAO가 위치
  • 데이터베이스 연동 담당

 

🌐 [Spring] 웹 요청 처리의 핵심, dispatcher-servlet.xml 완벽 분석 (Java Config 전환 포함)

web.xml 분석에 이어, 오늘은 Spring MVC의 실질적인 웹 동작을 정의하는 심장부, dispatcher-servlet.xml 파일에 대해 깊이 있게 파헤쳐 보겠습니다.

web.xml이 웹 서버(Tomcat)에게 "모든 요청을 DispatcherServlet에게 넘겨!"라고 지시했다면, 이 dispatcher-servlet.xml 파일은 DispatcherServlet에게 "요청을 받으면 이렇게 처리해!" 라고 상세한 행동 강령을 알려주는 역할을 합니다. 즉, 컨트롤러를 찾고, 뷰(View)를 연결하고, 어노테이션을 동작시키는 모든 마법이 바로 여기서 시작됩니다.

📝 전체 코드 살펴보기

먼저 분석할 dispatcher-servlet.xml 파일의 전체 코드입니다.

<?xml version="1.0" encoding="UTF-8"?>
<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"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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
           http://www.springframework.org/schema/mvc
           http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 1. Component Scan: 컨트롤러를 찾아서 빈으로 등록 -->
    <context:component-scan base-package="com.example.controller" />

    <!-- 2. Enable MVC: 어노테이션 기반 MVC 기능 활성화 -->
    <mvc:annotation-driven />

    <!-- 3. View Resolver: 뷰(JSP) 경로를 완성 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/" />
        <property name="suffix" value=".jsp" />
    </bean>

    <!-- 4. Static Resources: 정적 리소스(CSS, JS, 이미지 등) 처리 위임 -->
    <mvc:default-servlet-handler />
</beans>

 

📝 핵심 설정 분석

이 파일은 크게 4가지의 핵심적인 역할을 수행하도록 구성되어 있습니다.

1. 컴포넌트 스캔 (Component Scan)

<context:component-scan base-package="com.example.controller" />

• 역할: Spring 컨테이너에게 지정된 패키지(com.example.controller)를 스캔하여 특정 어노테이션(@Controller, @Service 등)이 붙은 클래스를 찾아 자동으로 빈(Bean)으로 등록하라고 지시합니다.
• 핵심: 이 설정 덕분에 우리는 컨트롤러 클래스를 만들고 @Controller 어노테이션만 붙이면, Spring이 알아서 해당 객체를 관리해 주므로 XML에 일일이 빈을 등록하는 수고를 덜 수 있습니다.


2. MVC 기능 활성화 (Enable MVC)

<mvc:annotation-driven />

• 역할: 마법의 한 줄입니다. 어노테이션 기반의 현대적인 Spring MVC 기능을 사용하기 위한 필수 설정입니다.
• 주요 기능: 이 태그 하나가 보이지 않는 곳에서 다음과 같은 필수적인 빈들을 등록하고 활성화합니다.
    • @RequestMapping, @GetMapping 등을 처리하는 RequestMappingHandlerMapping.
    • 컨트롤러 메서드를 호출하고 파라미터(@RequestParam 등)를 처리하는 RequestMappingHandlerAdapter.
    • JSON 데이터 변환, 데이터 검증(@Valid) 등 다양한 고급 기능.
• 결론: 이 태그가 없으면 @RequestMapping을 비롯한 대부분의 Spring MVC 어노테이션이 동작하지 않습니다.

3. 뷰 리졸버 (View Resolver)

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/" />
    <property name="suffix" value=".jsp" />
</bean>

• 역할: 컨트롤러가 반환하는 **논리적인 뷰 이름(Logical View Name)**을 실제 물리적인 뷰 파일 경로로 완성해주는 역할을 합니다.
• 동작 방식:
    1.컨트롤러가 return "home"; 과 같이 문자열을 반환합니다.
    2.ViewResolver는 이 "home"이라는 문자열을 받아, 설정된 prefix와 suffix를 앞뒤에 붙입니다.
    3.최종적으로 /WEB-INF/views/ + home + .jsp  = /WEB-INF/views/home.jsp 라는 실제 파일 경로를 만들어 줍니다.


4. 정적 리소스 처리 (Static Resources)

<mvc:default-servlet-handler />

• 역할: CSS, JavaScript, 이미지 파일 등 동적인 처리가 필요 없는 정적 리소스에 대한 요청을 처리합니다.
• 문제점: web.xml에서 DispatcherServlet의 처리 경로를 /로 지정하면, /css/style.css 같은 정적 파일 요청까지 DispatcherServlet이 가로채게 됩니다. DispatcherServlet은 이 요청을 처리할 컨트롤러를 찾지 못해 404 에러를 발생시킵니다.
• 해결책: 이 태그는 "만약 들어온 요청을 처리할 컨트롤러 매핑이 없다면, 그 요청을 Spring이 처리하지 말고 원래 웹 서버(Tomcat)의 기본 서블릿에게 넘겨라" 라고 설정합니다. 그러면 웹 서버가 정적 파일을 올바르게 찾아 클라이언트에게 제공할 수 있습니다.


📝 
더 나은 코드를 향하여: Java 기반 설정으로의 완전한 전환

XML 설정은 직관적이지만, 현대적인 Spring 개발에서는 타입 안정성(type-safe)과 리팩토링 용이성이 뛰어난 **Java 기반 설정(Java-based Configuration)**을 사용하는 것이 표준입니다.

아래와 같이 web.xml과 dispatcher-servlet.xml을 모두 제거하고 순수 Java 코드로 프로젝트를 설정할 수 있습니다

1단계: dispatcher-servlet.xml을 대체할 WebConfig 클래스 생성

먼저, dispatcher-servlet.xml의 모든 기능을 수행하는 Java 설정 클래스를 만듭니다.

// WebConfig.java
package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

@Configuration
@EnableWebMvc // <mvc:annotation-driven /> 역할
@ComponentScan(basePackages = "com.example.controller") // <context:component-scan /> 역할
public class WebConfig implements WebMvcConfigurer {

    // InternalResourceViewResolver 빈 등록
    @Bean
    public ViewResolver viewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

    // <mvc:default-servlet-handler /> 역할
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}

 

2단계: web.xml을 대체할 MyWebAppInitializer 클래스 생성

다음으로, web.xml의 역할을 수행하며 위에서 만든 WebConfig를 로드하는 초기화 클래스를 만듭니다. 이 방법을 사용하면 web.xml 파일을 프로젝트에서 완전히 삭제할 수 있습니다.

//MyWebAppInitializer.java
package com.example.config;

import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import javax.servlet.Filter;

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    // Root ApplicationContext에 대한 설정 (Service, Repository 등). 현재는 없으므로 null.
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    // DispatcherServlet의 Servlet ApplicationContext에 대한 설정 (Controller, ViewResolver 등)
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[]{WebConfig.class};
    }

    // DispatcherServlet이 처리할 요청 경로 지정
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    // 인코딩 필터 설정
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("UTF-8");
        encodingFilter.setForceEncoding(true);
        return new Filter[]{encodingFilter};
    }
}

 

🎯 마무리

오늘은 Spring MVC의 웹 요청 처리 로직을 담당하는 dispatcher-servlet.xml을 분석하고, 이를 현대적인 Java 설정으로 전환하는 방법까지 알아보았습니다.

요약:
    1.component-scan: @Controller를 찾아 빈으로 등록합니다.
    2.annotation-driven: @RequestMapping 등 MVC 어노테이션을 활성화합니다.
    3.ViewResolver: 컨트롤러가 반환한 뷰 이름을 실제 JSP 파일 경로로 완성합니다.
    4.default-servlet-handler: CSS, JS 같은 정적 리소스 요청을 처리합니다.

비록 Spring Boot가 많은 부분을 자동화해주지만, 그 내부에서 어떤 일들이 일어나는지 이해하는 것은 문제 해결 능력과 애플리케이션 설계 능력을 한 단계 끌어올리는 데 큰 도움이 됩니다. 이 글이 여러분의 Spring 학습에 도움이 되었기를 바랍니다

 

 

🌐 [Spring] 스프링 MVC의 심장, web.xml 완벽 분석 (DispatcherServlet, 한글 필터)


오늘은 스프링 부트(Spring Boot) 없이 전통적인 방식으로 Spring MVC 프로젝트를 구성할 때, 가장 먼저 만나게 되는 파일인 web.xml에 대해 깊이 있게 분석해 보겠습니다.

web.xml은 배포 서술자(Deployment Descriptor, DD)라고 불리며, 웹 애플리케이션이 최초에 구동될 때 WAS(Web Application Server, 예: Tomcat)가 가장 먼저 읽는 설정 파일입니다. 즉, 우리 프로젝트의 모든 요청이 어떻게 처리될지 정의하는 매우 중요한 시작점이죠.

📝 전체 코드 살펴보기

먼저 분석할 web.xml 파일의 전체 코드입니다.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">

    <display-name>Spring MVC Application</display-name>

    <!-- Spring DispatcherServlet -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- Character Encoding Filter -->
    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

 

📝 핵심 설정 분석

이 파일은 크게 두 가지 핵심적인 역할을 합니다.
    1.Spring MVC의 핵심 엔진인 DispatcherServlet을 등록하고 설정합니다.
    2.모든 요청에 대한 한글 깨짐을 방지하기 위한 CharacterEncodingFilter를 설정합니다.

하나씩 자세히 살펴보겠습니다.

1. DispatcherServlet: 모든 요청을 받는 프론트 컨트롤러

DispatcherServlet은 Spring MVC의 핵심 엔진이자 심장입니다. 클라이언트의 모든 요청을 가장 먼저 받아서 적절한 컨트롤러(@Controller)에게 작업을 위임하는 프론트 컨트롤러(Front Controller) 역할을 합니다.

<servlet> 태그 분석

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

• <servlet-name>: 서블릿의 별명을 지정합니다. dispatcher라는 이름으로 아래 매핑 설정에서 사용됩니다.
• <servlet-class>: 서블릿으로 사용할 실제 클래스를 지정합니다. Spring MVC의 핵심인 org.springframework.web.servlet.DispatcherServlet을 등록했습니다.
• <init-param>: 서블릿을 초기화할 때 필요한 파라미터를 설정합니다.
    • contextConfigLocation: DispatcherServlet이 사용할 Spring 설정 파일의 위치를 알려줍니다.
      여기서는 /WEB-INF/dispatcher-servlet.xml 파일을 사용하도록 지정했네요.
      이 파일 안에는 @Controller를 스캔할 패키지 위치나 ViewResolver 같은 빈(Bean) 설정이 들어있습니다.
•<load-on-startup>: WAS가 시작될 때 서블릿을 로드하는 순서를 지정합니다. 값이 1이므로 WAS가 구동되면서 가장 먼저 이 서블릿을 초기화합니다. 이를 통해 첫 요청 시 지연 없이 바로 응답할 수 있습니다.

<servlet-mapping> 태그 분석

<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

• <servlet-name>: 위에서 정의한 dispatcher 서블릿에 대한 매핑임을 알려줍니다.
• <url-pattern>/</url-pattern>: 가장 중요한 부분입니다. 이 설정은 모든 요청(http://.../)을 DispatcherServlet이 처리하도록 만듭니다. (정확히는 JSP 요청을 제외한 모든 요청)

💡 Tip: url-pattern을 /*로 설정하면 JSP 파일 요청까지 가로채서 뷰(View)가 제대로 렌더링되지 않는 문제가 발생할 수 있습니다. 따라서 Spring MVC에서는 일반적으로 /를 사용합니다.

2. CharacterEncodingFilter: 한글 깨짐 방지를 위한 필수 설정

웹 애플리케이션에서 한글로 된 데이터를 POST 방식으로 전송할 때, 별도 설정이 없으면 글자가 깨지는 현상이 발생합니다. 이를 방지하기 위해 모든 요청에 대해 UTF-8 인코딩을 강제하는 필터를 설정합니다.

<!-- Character Encoding Filter -->
<filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>

<filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

• <filter-class>: Spring에서 제공하는 CharacterEncodingFilter를 사용합니다.
• <init-param>: 필터에 encoding 값을 UTF-8로 설정합니다.
• <filter-mapping>: 이 필터를 어떤 요청에 적용할지 설정합니다. url-pattern을 /*로 지정하여 이 애플리케이션에 들어오는 모든 요청에 대해 인코딩 필터가 동작하도록 합니다.

 

📝 더 나은 코드를 위한 제안: Java 기반 설정으로 전환

web.xml을 사용하는 XML 기반 설정은 전통적이고 직관적이지만, 최근에는 Java 클래스를 이용한 설정(Java-based Configuration)이 더 선호됩니다. XML 파일을 없애고 100% Java 코드로만 프로젝트를 관리할 수 있어 더 깔끔하고 타입-세이프(type-safe)한 장점이 있습니다.

web.xml의 내용을 다음과 같은 Java 클래스로 대체할 수 있습니다.

/src/main/java/com/example/config/MyWebAppInitializer.java (새 파일)

package com.example.config;

import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import javax.servlet.Filter;

public class MyWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    // Root-Context (root-context.xml)에 해당하는 설정 클래스를 지정합니다. (현재 프로젝트에는 없으므로 null)
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }

    // DispatcherServlet (servlet-context.xml)에 해당하는 설정 클래스를 지정합니다.
    @Override
    protected Class<?>[] getServletConfigClasses() {
        // dispatcher-servlet.xml을 대체할 Java 설정 클래스를 만들어야 합니다.
        // 예: return new Class<?>[] { WebConfig.class };
        return null; // 지금은 예시이므로 null로 둡니다.
    }

    // DispatcherServlet이 매핑될 경로를 지정합니다.
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    // 인코딩 필터 등 각종 필터를 설정합니다.
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("UTF-8");
        encodingFilter.setForceEncoding(true);
        return new Filter[]{encodingFilter};
    }
}

주의: 위와 같이 Java 설정을 사용하려면 pom.xml에 spring-web 의존성을 추가하고, dispatcher-servlet.xml의 내용도 Java @Configuration 클래스로 옮겨야 합니다.

 

🎯 마무리

오늘은 Spring MVC 애플리케이션의 관문 역할을 하는 web.xml 파일에 대해 알아보았습니다.

요약:
    1.DispatcherServlet을 등록하여 모든 요청을 Spring 컨테이너로 연결합니다.
    2.CharacterEncodingFilter를 설정하여 안정적인 한글 처리를 보장합니다.

비록 Spring Boot의 등장으로 web.xml을 직접 작성하는 일이 줄었지만, 그 내부 동작 원리를 이해하는 것은 Spring MVC의 근간을 파악하는 데 매우 중요합니다. 이 글이 여러분의 Spring 학습에 도움이 되었기를 바랍니다

 

 

 

 

🌐 [Maven] Spring 프로젝트의 설계도, pom.xml 완벽 해부

오늘은 Maven 기반의 Spring 프로젝트에서 가장 핵심적인 파일, 바로 pom.xml에 대해 상세히 분석해 보겠습니다. pom.xml은 Project Object Model의 약자로, 프로젝트의 모든 정보를 담고 있는 설계도와 같습니다.이 파일 하나에 어떤 라이브러리를 사용할지(의존성), 어떤 버전의 자바로 만들지, 그리고 최종적으로 어떻게 빌드하고 패키징할지에 대한 모든 정보가 정의되어 있습니다. Spring Boot 없이 전통적인 방식으로 프로젝트를 구성할 때, 이 파일을 정확히 이해하는 것은 필수입니다.

📝 전체 코드 살펴보기

먼저 분석할 pom.xml 파일의 전체 코드입니다.

<?xml version="1.0" encoding="UTF-8"?>
<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
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>spring-mvc-app</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring.version>5.3.21</spring.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- Spring Core -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- Spring Context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- Spring Web MVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- Servlet API -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <!-- JSP API -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.3</version>
            <scope>provided</scope>
        </dependency>

        <!-- JSTL -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.3</version>
            </plugin>
        </plugins>
    </build>
</project>

 

📝 핵심 설정 분석

pom.xml은 크게 4가지 영역으로 나눌 수 있습니다.
1.프로젝트 기본 정보 (Project Coordinates)
2.설정값 변수 (Properties)
3.프로젝트 라이브러리 (Dependencies)
4.빌드 방법 (Build)

하나씩 자세히 살펴보겠습니다.

1. 프로젝트 기본 정보 (Project Coordinates)

프로젝트를 식별하는 고유 정보입니다. Maven Central Repository 등에서 이 프로젝트를 유일하게 찾아낼 수 있는 주소와 같습니다.

<groupId>com.example</groupId>
<artifactId>spring-mvc-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>

<groupId>: 프로젝트를 만든 그룹이나 조직의 고유 ID입니다. 보통 회사의 도메인을 역순으로 사용합니다.
<artifactId>: 프로젝트의 이름입니다. groupId 내에서 유일해야 합니다.
<version>: 프로젝트의 버전입니다. SNAPSHOT은 아직 개발 중인, 불안정한 버전임을 의미합니다.
<packaging>: 프로젝트를 빌드한 결과물의 형태를 지정합니다. war는 Web Application Archive의 약자로, Tomcat 같은 웹 애플리케이션 서버(WAS)에 배포하기 위한 패키지 형식입니다


2. 설정값 변수 (Properties)

pom.xml 파일 내에서 공통적으로 사용될 값들을 변수로 정의하는 곳입니다. 이렇게 하면 버전 등을 한 곳에서 관리할 수 있어 매우 편리합니다.

<properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <spring.version>5.3.21</spring.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<maven.compiler.source> & <target>: 이 프로젝트가 Java 11 문법으로 작성되었고, Java 11 환경에서 실행되도록 컴파일하라는 설정입니다.
<spring.version>: 사용할 스프링 프레임워크의 버전을 5.3.21로 지정했습니다. 아래 의존성(Dependencies) 부분에서 ${spring.version} 형태로 이 값을 참조합니다.
<project.build.sourceEncoding>: 소스 코드의 인코딩을 UTF-8로 설정하여 한글 깨짐을 방지합니다.

3. 프로젝트 라이브러리 (Dependencies)

pom.xml의 심장부입니다. 이 프로젝트가 동작하기 위해 필요한 외부 라이브러리(JAR 파일)들을 명시하는 곳입니다. Maven은 여기에 명시된 라이브러리들을 자동으로 다운로드하고 클래스패스에 추가해 줍니다.

<!-- Spring Web MVC -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${spring.version}</version>
</dependency>

<!-- Servlet API -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>

* Spring Framework Dependencies: spring-core, spring-context, spring-webmvc는 Spring MVC 애플리케이션을 구동하기 위한 핵심 라이브러리입니다. 버전은 위 <properties>에 정의된 ${spring.version}을 사용하고 있습니다.
* Servlet/JSP API: javax.servlet-api와 javax.servlet.jsp-api는 서블릿과 JSP를 사용하기 위한 라이브러리입니다.
    💡 <scope>provided</scope>란? 이 설정은 매우 중요합니다. provided는 '제공된다'는 의미로, 컴파일할 때는 이 라이브러리가 필요하지만, 서버(Tomcat 등)에서 이미 제공하므로 최종 war 파일에는 포함하지 말라는 뜻입니다. 만약 이 설정을 빼면 서버에 내장된 라이브러리와 충돌이 발생할 수 있습니다.

* JSTL: JSP에서 c:forEach, c:if 같은 태그를 사용하기 위한 라이브러리입니다.

4. 빌드 방법 (Build)

프로젝트를 컴파일하고 패키징하는 방법을 정의합니다. 여기서는 Maven 플러그인을 사용합니다.

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>11</source>
                <target>11</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>3.2.3</version>
        </plugin>
    </plugins>
</build>

* maven-compiler-plugin: 자바 소스 코드를 바이트코드로 컴파일하는 역할을 합니다. <configuration>을 통해 <properties>에서 정의한 자바 11 버전을 사용하도록 설정했습니다.
* maven-war-plugin: 프로젝트를 <packaging>에 명시된 war 파일로 묶어주는 역할을 합니다.

🎯마무리

오늘은 Maven 프로젝트의 설계도인 pom.xml을 분석해 보았습니다.

요약:  
  1.프로젝트 정보: groupId, artifactId 등으로 프로젝트를 식별합니다.
  2.의존성 관리: <dependencies>를 통해 필요한 라이브러리를 선언하고 자동으로 관리합니다.
  3.빌드 설정: <build>와 플러그인을 통해 컴파일 및 패키징 과정을 제어합니다.

pom.xml을 이해하는 것은 의존성 충돌 문제를 해결하고, 프로젝트의 구조를 파악하는 데 큰 도움이 됩니다. 이 글이 여러분의 개발 여정에 도움이 되었기를 바랍니다

 

 

 

 

 

 

 

 

 

+ Recent posts