서블릿 기반 웹 애플리케이션
서블릿 기반 웹 애플리케이션 (Servlet Web / Spring MVC)
대부분의 Spring Boot 서비스는 HTTP 요청을 받는 웹 애플리케이션이에요. 서블릿 기반으로 웹 앱을 만들 때 Spring Boot는 Spring MVC(또는 Jersey)에 대한 자동 설정을 제공해서, 직접 web.xml이나 긴 설정을 쌓지 않아도 바로 컨트롤러로 요청을 처리할 수 있게 해줘요. 이 글에서는 Spring MVC의 핵심인 컨트롤러 작성과 자동 설정이 준비해 주는 기능들을 중심으로 볼게요.
출처: Servlet Web Applications (Spring Boot Reference Documentation)
Spring Web MVC 프레임워크
@RestController와 @RequestMapping 같은 어노테이션으로 요청 경로와 처리 메서드를 연결하는 게 MVC의 기본 구성이에요. 생성자를 통해 저장소(repository) 같은 의존성을 주입받고, 각 HTTP 메서드에 맞는 어노테이션으로 라우팅을 표현해요.
import java.util.List;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/users")
public class MyRestController {
private final UserRepository userRepository;
private final CustomerRepository customerRepository;
public MyRestController(UserRepository userRepository, CustomerRepository customerRepository) {
this.userRepository = userRepository;
this.customerRepository = customerRepository;
}
@GetMapping("/{userId}")
public User getUser(@PathVariable Long userId) {
return this.userRepository.findById(userId).get();
}
@GetMapping("/{userId}/customers")
public List<Customer> getUserCustomers(@PathVariable Long userId) {
return this.userRepository.findById(userId).map(this.customerRepository::findByUser).get();
}
@DeleteMapping("/{userId}")
public void deleteUser(@PathVariable Long userId) {
this.userRepository.deleteById(userId);
}
}
라우팅과 실제 요청 처리 로직을 분리하고 싶다면, 함수형 스타일인 WebMvc.fn을 쓸 수도 있어요. RouterFunction 빈으로 라우팅 규칙을 정의하고, 처리 로직은 별도 핸들러 컴포넌트에 두는 방식이에요.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.function.RequestPredicate;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.ServerResponse;
import static org.springframework.web.servlet.function.RequestPredicates.accept;
import static org.springframework.web.servlet.function.RouterFunctions.route;
@Configuration(proxyBeanMethods = false)
public class MyRoutingConfiguration {
private static final RequestPredicate ACCEPT_JSON = accept(MediaType.APPLICATION_JSON);
@Bean
public RouterFunction<ServerResponse> routerFunction(MyUserHandler userHandler) {
return route()
.GET("/{user}", ACCEPT_JSON, userHandler::getUser)
.GET("/{user}/customers", ACCEPT_JSON, userHandler::getUserCustomers)
.DELETE("/{user}", ACCEPT_JSON, userHandler::deleteUser)
.build();
}
}
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.function.ServerRequest;
import org.springframework.web.servlet.function.ServerResponse;
@Component
public class MyUserHandler {
public ServerResponse getUser(ServerRequest request) { /* ... */ }
public ServerResponse getUserCustomers(ServerRequest request) { /* ... */ }
public ServerResponse deleteUser(ServerRequest request) { /* ... */ }
}
Spring MVC 자체는 스프링 프레임워크의 일부라서, 더 깊은 내용은 프레임워크 레퍼런스 문서를 보면 돼요. RouterFunction 빈은 여러 개 정의해 라우팅을 모듈화할 수 있고, 우선순위가 필요하면 빈 순서를 정할 수도 있어요.
Spring MVC 자동 설정
Spring Boot는 대부분의 애플리케이션에 잘 맞는 Spring MVC 자동 설정을 제공해요. 이 자동 설정이 @EnableWebMvc의 역할을 대신하므로, 둘을 함께 쓰지 않는 게 원칙이에요. 자동 설정이 기본값 위에 추가로 제공하는 기능은 다음과 같아요.
ContentNegotiatingViewResolver와BeanNameViewResolver빈 포함- WebJars를 포함한 정적 리소스 지원
Converter,GenericConverter,Formatter빈 자동 등록HttpMessageConverters지원 — 필요하면 Jackson으로 객체를 JSON으로, XML 확장이 있으면 Jackson XML로, 없으면 JAXB로 변환해요. 문자열은 기본적으로UTF-8로 인코딩돼요.MessageCodesResolver자동 등록- 정적
index.html지원 ConfigurableWebBindingInitializer빈 자동 사용
요청/응답 변환은 HttpMessageConverter 인터페이스가 담당해요. 컨텍스트에 있는 컨버터 빈은 변환기 목록에 자동으로 추가되고, 기본 컨버터를 같은 방식으로 재정의할 수도 있어요.
알아두면 좋은 점
- embedded 서블릿 컨테이너는
ServletContainerInitializer나WebApplicationInitializer인터페이스를 직접 실행하지 않아요. war 안에서 돌도록 설계된 서드파티 라이브러리가 Spring Boot 애플리케이션을 깨뜨릴 위험을 줄이려는 설계 결정이에요. - 서블릿 컨텍스트 초기화가 필요하면
ServletContextInitializer인터페이스를 구현한 빈을 등록하세요.onStartup메서드 하나가ServletContext에 접근할 수 있고, 기존WebApplicationInitializer를 연결하는 어댑터로도 쓰기 좋아요. server.servlet.context-parameters.*프로퍼티로ServletContext초기화 파라미터를 설정할 수 있어요. 필터 순서를 확인하고 싶다면logging.level.web=debug로 로깅을 켜서 등록된 필터와 URL 패턴을 보면 돼요.
더 알아보기 (Learn more)
- Spring Framework — Spring MVC 레퍼런스 — 컨트롤러·핸들러·뷰 해석의 전체 원리를 다뤄요.
- Spring MVC Guides (spring.io/guides) — REST 서비스, 양식 처리 같은 실전 예제를 따라 해볼 수 있어요.
- Spring Boot 자동 설정 — MVC 자동 설정이 어떻게 뒤에서 작동하는지 이해하는 데 도움이 돼요.