[Spring] MVC

이승준·2025년 3월 7일

스프링

목록 보기
2/3
post-thumbnail
  • Spring Web MVC는 Servlet API를 기반으로 구성된 웹 개발 프레임워크이다.

Spring MVC의 폴더 구조

  • 우선 webapp/spring/appServlet/servlet-context.xml을 살펴보자.
<annotation-driven />

	<resources mapping="/resources/**" location="/resources/" />

	<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>
	
	<context:component-scan base-package="dev.mvc.spring" />
	
</beans:beans>
  • <annotation-driven> 어노테이션 기반으로 동작하고
  • org.springframework.web.servlet.view.InternalResourceViewResolver를 빈으로 등록해주었는데, 컨트롤러에서 /WEBINF/views/.jsp로 return 하지 않고, return "home"이라고만 써줘도 prefix와 suffix로 "/WEBING/views/"+ + *".jsp"로 붙여주어서 jsp 파일로 편하게 이동해주도록 한다.
  • 실제 InternalResourceViewResolver 객체 내부를 확인해보면 suffix와 prefix를 생성자 주입 방식으로 설정해주는것을 볼 수 있다.



  • webapp/resources: 정적 리소스(image, css 등)가 위치한 폴더
  • webapp/WEB-INF/spring/root-context.xml: 상위(Root) 스프링 컨테이너 설정 파일
  • webapp/WEB-INF/views: .jsp, .html 파일들이 위치한 폴더
  • web.xml: 웹 기반 프로젝트의 최상위(Root) 설정 파일 다른 스프링 설정 파일(root-context.xml, servlet-context.xml)들의 경로 지정

DispatcherServlet

  • 스프링이 적용된 서블릿 클래스로, Spring MVC에서 FrontController 패턴으로 구현된 프론트 컨트롤러, HTTP 요청의 진입점이다.


역할

  • 기본적인 사용자의 요청 처리를 담당하고, 요청한 경로에 맞게 적합한 Controller나 Handler를 찾아 전달한다.
    • 우리가 사용하는 Controller를 얘가 찾아주는게 아닐까?
  • SRP 원칙을 준수한다. -> 요청 처리를 얘가 혼자서 담당하는게 아니고, 각각의 역할을 세분화해서 다른 클래스들과 상호작용하면서 처리한다.

    예를들면, 요청에 맞는 컨트롤러를 찾는것은 HandlerMapping.java가 담당하고, 컨트롤러 정보를 HandlerAdapter가 컨트롤러를 실행시킨다. 이런식으로 다른 클래스들과 상호작용하면서 실제 요청을 처리한다.



사용 방법

  • 결국 DispatcherServlet로 서블릿이다. 스프링 빈으로 관리되는 것이 아닌 서블릿 컨테이너에서 하나의 서블릿으로 관리된다.
  • 즉, DispatcherServlet으로 사용하기 위해서는 이 서블릿을 컨테이너에 등록해야한다.
    • 우리는 서블릿을 xml을 통해 등록해보았다.
<web-app>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/app-context.xml</param-value>
	</context-param>

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

	<servlet-mapping>
		<servlet-name>app</servlet-name>
		<url-pattern>/app/*</url-pattern>
	</servlet-mapping>

</web-app>
  • <servlet> 블럭을 보면 DispathcerServlet을 빈으로 등록하고 있고, Servlet-mapping으로 /app 요청으로 오는 요청을 DispatcherServlet이 요청을 받게된다.





DispatcherServlet의 세부 동작 과정

  • 파란색은 개발자가 설정하는 정보나 구현체, 녹색은 스프링 자체적으로 제공하는 부분들
  • HTTP 요청이 오면 Dispatcher servlet이 요청을 받는다
  • HandlerMapping을 통해 사용자의 요청 URL에 해당하는 컨트롤러를 조회
  • Handler Adapter가 해당 컨트롤러를 실행 시킴.
  • 이후 ModelAndView 값에 따라 ViewResolver가 view의 실제 주소를 return
  • return된 뷰의 경로에 있는 jsp(view)를 return 함.

한마디로 우리가 쉽게 사용하는 @Controller, @Service, DAO 같은 의존성들을 탐색하고, 실행시켜주는 전반적인 과정들이 이렇게 추상화되어 있는것이다.


package com.example.demo.controller;

import com.example.demo.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HelloController {

    private final HelloService helloService;

    @Autowired
    public HelloController(HelloService helloService) {
        this.helloService = helloService;
    }

    @GetMapping("/hello")
    public ModelAndView sayHello() {
        // 서비스 계층을 통해 DB에서 결과 값을 가져옴
        String result = helloService.getHelloMessage();

        // ModelAndView 객체 생성
        ModelAndView modelAndView = new ModelAndView();
        
        // 결과 값을 모델에 추가
        modelAndView.addObject("message", result);
        
        // 뷰 이름 설정 (DispatcherServlet이 /WEB-INF/views/list.jsp로 포워딩)
        modelAndView.setViewName("list");

        return modelAndView;
    }
}




DispatcherServlet HTTP 요청 처리

  • 디스패쳐 서블릿이 Web 요청을 처리하려면 브라우저로부터 받은 경로에 해당하는 처리를 수행할 핸들러가 있는지 찾아야한다. -> HandlerMapping이 담당
  • Controller를 핸들러가 찾으려면 해당 클래스가 Controller인지 명시 해주어야 한다. Annotaion 기반으로 핸들러를 맵핑해보자.



@Component 어노테이션 기반


  • 스프링 초기버전에서 하용하던 방식으로 Url을 value로 매핑시켜서 사용할 수 있다.
  • 메서드에서 @RequestMapping으로 이후 경로를 매핑시켜줄 수 있다.
@Component(value = "/mice")
public class HomeController {

@Controller 어노테이션 기반

  • @Controller는 @Component Annotation의 스테레오타입이기 때문에,
    본질적으로는 @Component이자 Spring Bean이라고 볼 수 있음
  • Controller라는 구체적인 네이밍을 사용하는 덕분에 클래스의 역할을 한 눈에 알 수 있다는 장점이 있다

@Controller // 클래스 레벨에 작성(class키워드 위에 작성한 Annotation)

public class HomeController {
	@RequestMapping(value = "/", method = RequestMethod.GET)
	public String home(Locale locale, Model model) {
		logger.info("Welcome home! The client locale is {}.", locale);
profile
들은것은 잊어버린다 본것은 기억된다 해본것은 내것이 된다

0개의 댓글