스프링 MVC 핵심 기능과 구성 요소 이해

스프링 MVC 개요

스프링 MVC는 스프링 프레임워크에서 제공하는 웹 개발용 모듈로, MVC(Model-View-Controller) 아키텍처를 구현하는 대표적인 프레임워크입니다. 이는 요청 경로 매핑, 뷰 해석, 데이터 바인딩 등 웹 애플리케이션의 주요 기능을 지원합니다.

MVC 패턴 구성 요소

  • Model(모델): 비즈니스 로직 처리 및 데이터 저장을 담당하는 자바 객체 (예: 도메인 클래스, 서비스 계층).
  • View(뷰): 사용자에게 보여줄 출력 결과를 생성하는 템플릿 파일 (HTML, Thymeleaf, JSP 등).
  • Controller(컨트롤러): 클라이언트 요청을 수신하고, 적절한 비즈니스 로직을 호출하며, 결과를 뷰에 전달하는 역할.

핵심 컴포넌트 구조

  • DispatcherServlet: 모든 요청의 진입점으로, 요청을 처리하기 위한 하위 컴포넌트들을 조율하는 중심 역할.
  • HandlerMapping: 요청 경로와 해당 처리 메서드(핸들러) 간의 매핑을 결정.
  • HandlerAdapter: 다양한 컨트롤러 타입(예: @RequestMapping, @GetMapping 등)에 맞춰 호출 가능하도록 어댑터 제공.
  • HandlerInterceptor: 요청 처리 전/후에 특정 작업을 수행할 수 있는 인터셉터.
  • ModelAndView: 처리 결과로 반환되는 모델 데이터와 뷰 이름을 포함.
  • ViewResolver: 논리적 뷰 이름을 실제 파일 경로(물리적 뷰)로 변환.

요청 처리 흐름

  1. 클라이언트 요청이 DispatcherServlet에 도착.
  2. HandlerMapping이 요청 경로에 맞는 Handler를 찾음.
  3. HandlerAdapter를 통해 핸들러 메서드 실행.
  4. 비즈니스 로직 처리 후 ModelAndView 반환.
  5. ViewResolver가 뷰 이름을 물리적 경로로 변환.
  6. 뷰에 모델 데이터를 결합하여 응답을 클라이언트에 전송.

@RequestMapping 사용법

기본적으로 @RequestMapping은 요청 경로를 정의하며, 다음과 같은 속성을 제공합니다:

  • value 또는 path: 매핑할 경로 (필수).
  • method: HTTP 메서드 제한 (GET, POST 등).
  • params: 특정 파라미터 존재 여부 확인.
  • headers: 요청 헤더 조건 설정.
  • consumes, produces: 미디어 타입 지정.

경로 패턴 예시:

@RequestMapping("/api/user/{id}")
public String getUser(@PathVariable("id") Long userId) {
    return "userDetail";
}

URL 패턴은 * (0개 이상), ** (하위 디렉토리 포함), ? (1글자) 등을 지원하며, {variable} 형태로 경로 변수를 활용할 수 있습니다.

HTTP 메서드 별 애노테이션

대표적인 파생 애노테이션:

  • @GetMapping: GET 요청만 처리.
  • @PostMapping: POST 요청만 처리.
  • @PutMapping, @DeleteMapping: PUT/DELETE 요청 처리.

브라우저는 기본적으로 GET/POST만 지원하므로, 다른 메서드를 사용하려면 _method 숨김 필드를 사용해 요청 방식을 위조해야 합니다.

파라미터 처리 방법

  • 기본 파라미터 바인딩: 메서드 매개변수 이름과 요청 파라미터 이름이 일치하면 자동 매핑.
  • @RequestParam: 명시적 매핑, required=falsedefaultValue 지원.
  • 엔티티 객체 바인딩: 폼 데이터가 객체의 필드명과 일치하면 자동 생성.
  • @RequestHeader, @CookieValue: 헤더 및 쿠키 값 추출.

문자 인코딩 처리

요청 본문의 인코딩 문제를 해결하기 위해 CharacterEncodingFilter를 등록합니다.

<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>
    <init-param>
        <param-name>forceEncoding</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

공유 데이터 전달 방식

다양한 방법으로 요청 스코프에 데이터를 공유할 수 있습니다:

  • Model, Map, ModelMap 사용.
  • HttpServletRequest.setAttribute().
  • HttpSession 또는 ServletContext를 통해 세션/애플리케이션 범위 데이터 저장.

뷰 처리 방식

  • 전달(Forward): forward:/target 형식으로 내부 요청 전달.
  • 리다이렉트(Redirect): redirect:/target 형식으로 클라이언트 재요청 유도.
  • 뷰 컨트롤러: XML 또는 구성 클래스에서 경로와 뷰 이름을 직접 매핑.

RESTful 설계 적용

URI에 리소스와 동작을 포함시키며, 각 메서드에 따라 동작을 구분합니다. 예시:

@DeleteMapping("/users/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
    // 삭제 로직
    return ResponseEntity.noContent().build();
}

@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody User user) {
    // 생성 로직
    return ResponseEntity.ok(user);
}

HTTP 메시지 변환

  • @RequestBody: 요청 본문을 자바 객체로 변환.
  • @ResponseBody: 메서드 반환 값을 응답 본문으로 전송.
  • RequestEntity, ResponseEntity: 요청/응답의 전체 정보를 제어 가능.

파일 업로드 처리

MultipartFile 타입 파라미터를 사용하여 파일을 받고, transferTo()로 저장합니다.

<form method="post" enctype="multipart/form-data">
    <input type="file" name="file" />
    <button type="submit">업로드</button>
</form>
@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file) throws IOException {
    String fileName = UUID.randomUUID() + "_" + file.getOriginalFilename();
    Path uploadPath = Paths.get("uploads");
    Files.write(uploadPath.resolve(fileName), file.getBytes());
    return "success";
}

인터셉터 설정

HandlerInterceptor 인터페이스를 구현하여 요청 전/후에 로직을 삽입할 수 있습니다.

public class AuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (request.getSession().getAttribute("user") == null) {
            response.sendRedirect("/login");
            return false;
        }
        return true;
    }
}

설정은 WebMvcConfigurer 인터페이스의 addInterceptors() 메서드에서 수행.

예외 처리 전략

  • @ControllerAdvice + @ExceptionHandler로 전역 예외 처리 가능.
  • SimpleMappingExceptionResolver를 통해 예외 발생 시 뷰 이름 매핑.

구성 클래스 기반 설정

@Configuration@EnableWebMvc를 사용해 스프링 부트 외 환경에서도 설정 가능.

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/login", "/css/**");
    }

    @Bean
    public MultipartResolver multipartResolver() {
        CommonsMultipartResolver resolver = new CommonsMultipartResolver();
        resolver.setMaxInMemorySize(1024 * 1024); // 1MB
        return resolver;
    }
}

스프링 MVC 실행 순서 요약

  1. DispatcherServlet가 요청을 수신.
  2. HandlerMapping을 통해 핸들러를 검색.
  3. HandlerAdapter를 통해 핸들러 실행.
  4. 모델과 뷰 정보를 포함한 ModelAndView 반환.
  5. ViewResolver를 통해 뷰 이름을 실제 파일로 변환.
  6. 최종 렌더링된 결과를 클라이언트에 전송.

태그: Spring MVC RESTful RequestMapping HandlerInterceptor ModelAndView

6월 24일 23:42에 게시됨