Spring 07 : MVC (동작방식, 세팅, 요청매핑, 스프링 메시지)

LeeWonjin·2022년 8월 31일

2022 백엔드스터디

목록 보기
17/20

교재
책 : 초보 웹 개발자를 위한 스프링5 프로그래밍 입문 챕터 9, 10, 11, 15

pom.xml

<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>
  <groupId>in.wonj</groupId>
  <artifactId>sp5-wonjin</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  
  <dependencies>
	<dependency>
  		<groupId>javax.servlet</groupId>
  		<artifactId>javax.servlet-api</artifactId>
  		<version>4.0.1</version>
  	</dependency>
  	<dependency>
  		<groupId>javax.servlet.jsp</groupId>
  		<artifactId>javax.servlet.jsp-api</artifactId>
  		<version>2.3.3</version>
  		<scope>provided</scope>
  	</dependency>
  	<dependency>
  		<groupId>javax.servlet</groupId>
  		<artifactId>jstl</artifactId>
  		<version>1.2</version>
  	</dependency>
  
  	<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-jdbc</artifactId>
  		<version>5.3.22</version>
  	</dependency>
  	<dependency>
  		<groupId>org.springframework</groupId>
  		<artifactId>spring-webmvc</artifactId>
  		<version>5.3.22</version>
  	</dependency>
  	
  	<dependency>
  		<groupId>org.apache.tomcat</groupId>
  		<artifactId>tomcat-jdbc</artifactId>
  		<version>10.0.23</version>
  	</dependency>
 	<dependency>
  		<groupId>mysql</groupId>
  		<artifactId>mysql-connector-java</artifactId>
  		<version>8.0.30</version>
  	</dependency>
  	
	<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
			<version>1.1.0.Final</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>5.4.2.Final</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.9.4</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.datatype</groupId>
			<artifactId>jackson-datatype-jsr310</artifactId>
			<version>2.9.4</version>
		</dependency>
  </dependencies>
  
  <build>
  	<plugins>
	  	<plugin>
	  		<groupId>org.apache.maven.plugins</groupId>
	  		<artifactId>maven-compiler-plugin</artifactId>
	  		<version>3.10.1</version>
	  		<configuration>
	  			<release>18</release>
	  			<encoding>utf-8</encoding>
	  		</configuration>
	  	</plugin>
  		<plugin>
  			<groupId>org.apache.maven.plugins</groupId>
  			<artifactId>maven-war-plugin</artifactId>
  			<version>3.3.2</version>
  		</plugin>
  	</plugins>
  </build>
  
</project>

스프링MVC

MVC : Model, View, Controller
스프링은 MVC를 개발하기 위한 기능을 지원한다.

웹 애플리케이션 구조

아래 구조를 사용할 수 있다.

  • 프론트 서블릿 - 컨트롤러 - 서비스 - DAO
  • UI - 서비스 - 도메인 - 인프라

구성요소

SpringMVC - JSP 로 구성된 프로젝트의 경우 아래와 같은 구성요소를 가질 수 있다.

  • 클라이언트 요청
  • DispatcherServlet (프론트 서블릿)
  • HandlerMapping
  • HandlerAdapter
  • 컨트롤러
  • ViewResolver

아래와 같은 흐름을 가진다.

  1. 요청
    1) 클라이언트가 --> DispathcerServlet : 특정 경로(URL)로 요청
  2. 컨트롤러 검색
    1) DispathcerServlet --> HandlerMapping : 요청을 처리할 컨트롤러 검색 위임
    2) HandlerMapping -> DispathcerServlet : 컨트롤러 객체 리턴
  3. 컨트롤러 실행
    1) DispatcherServlet --> HandlerAdapter : 2-2에서 리턴받은 컨트롤러 전달 및 실행
    2) HandlerAdapter --> DispatcherServlet : 실행 후 ModelAndView 리턴
  4. 뷰 생성/찾기
    1) DispatcherServlet --> ViewResolver : 3-2에서 리턴받은 내용으로 뷰 생성 또는 찾기 요청
    2) ViewResolver --> DispatcherServlet : 뷰 객체 리턴
  5. 응답
    1) DispatcherServlet --> 뷰 객체 : 응답 생성 요청
    2) 뷰 객체 --> JSP : 응답 생성
    3) JSP --> 클라이언트 : 응답

세팅

구현 개요

maven project를 생성할 때 패키징을 war로 선택해야 한다.
생성한 프로젝트에는 아래와 같은 디렉토리, 파일이 필요하다.

프로젝트 루트
└─ pom.xml
└─ [target]
    └─ ...
└─ [src]
    └─ [main]
        └─ [java] : 아래는 편의상의 패키지 구분
            └─ config패키지
                └─ MvcConfig.java ★
                └─ ControllerConfig.java ★
                └─ (그 외 설정파일들)
            └─ controller패키지
                └─ (컨트롤러 java파일들) ★
            └─ 그 외 패키지
                └─ (그 외 java파일들)
        └─ [webapp]
            └─ [WEB-INF]
                └─ web.xml ★
                └─ [view]
                    └─ (jsp파일들)
        └─ [resource]
            └─ 소스코드 외 파일 ( properties 파일 등 )

MvcConfig.java

MVC동작을 위한 스프링 설정파일이 필요하다.

WebMvcConfigurer인터페이스를 구현한 설정파일에 @EnableWebMvc어노테이션을 붙이면 기본구현된 메소드를 통해 많은 부분을 자동설정 한다.

  • ViewResolverRegistry.jsp(접두어, 접미어) : 뷰를 찾을 때 뷰 이름 앞뒤에 붙일 문자열을 지정한다.
  • DefaultServeltHandlerConfigurer.enable()
    • 아래 두 개의 Bean객체를 등록한다.
    • DefaultServletHttpRequestHandler : 클라이언트의 모든 요청을 WAS의 디폴트 서블릿에 전달
    • SimpleUrlHandlerMapping

아래 코드는 2개의 HandlerMapping을 등록한다.

  • RequestMappingHandlerMapping : @EnableWebMvc가 등록한다. 어떤 컨트롤러가 @RequestMapping()등에 걸리면 이 핸들러매핑이 동작한다.
  • SimpleUrlHandlerMapping : configurer.enable()이 등록한다. RequestMappingHandlerMapping으로 처리되지 않은 요청에 대해 DefaultServletHttpRequestHandler를 리턴하고 결과적으로 WAS의 디폴트 서블릿이 요청을 처리한다.
package config;

import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
	@Override
	public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
		configurer.enable();
	}
	
	@Override
	public void configureViewResolvers(ViewResolverRegistry registry) {
		registry.jsp("/WEB-INF/view/", ".jsp");
	}
}

ControllerConfig.java

그냥 스프링 설정파일이다. 컨트롤러들을 Bean으로 등록한다.

// ControllerConfig.java
package config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import controller.SomethingController;

@Configuration
public class ControllerConfig {
	@Bean
	public SomethingController somethingController() {
		return new SomethingController();
	}
}

// SomethingController.java
package controller;

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

@Controller
public class SomethingController {
	@RequestMapping("/요청경로")
	public String someMethod() {
		return "뷰 이름";
	}
}

web.xml

크게 아래 내용을 어플리케이션에 알려준다

  • dispatcher : dispatcher서블릿이 어디있냐
  • contextClass : 어디있냐
  • contextConfigLocation : 스프링 설정파일들 이름이 뭐냐
  • encodingFilter : 인코딩 뭐냐
<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	version="3.1" metadata-complete="true">

	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>
			org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
      
		<init-param>
			<param-name>contextClass</param-name>
			<param-value>
                org.springframework.web.context.support.AnnotationConfigWebApplicationContext
			</param-value>
		</init-param>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>
				config.MvcConfig
				config.ControllerConfig
			</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>

	<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>

요청 매핑

요청이 들어온 경로와 요청 메소드에 따라 컨트롤러의 특정 메소드를 호출하도록 매핑한다.

어노테이션으로 요청 매핑

package controller;

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

@Controller
public class SomethingController {
	@RequestMapping("/요청경로")
	public String methodForAnyReq() {
		return "뷰 이름";
	}
    
    @GetMapping("/요청경로")
    public String methodForGet() {
        return "뷰 이름";
    }
    
    @PostMapping("/요청경로")
    public String methodForPost() {
        return "뷰 이름";
    }
}

WebMvcConfigurer.addViewControllers()로 요청 매핑

package config;

import ...

@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
	...
    @Override
	public void addViewControllers(ViewControllerRegistry reg) {
        reg.addViewController("/경로").setViewName("뷰 이름");
    }
}

요청매핑으로 JSP응답

// ControllerConfig.java
package config;

import controller.TestController;
import ...

@Configuration
public class ControllerConfig {
	@Bean
	public TestController testController() {
		return new TestController();
	}
}

// TestController.java
package controller;

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

@Controller
public class TestController {
	@GetMapping("test/something")
	public String somethingMethod(Model model) {
		model.addAttribute("testData", "I like gorani");
		return "testView";
	}
}
<!-- testView.jsp -->
<%@ page contentType="text/html; charset=utf-8" %>

<!DOCTYPE html>
<html>
<head><title>I am testView.jsp</title></head>
<body>
	<h1>I am Header</h1>
	<p> ${testData} </p>
</body>
</html>

톰캣에서 실행

프로젝트 우클릭 - Run As - Run on Server

Tomcat Server 선택 - Next - Finish

http://localhost:8080/프로젝트이름/요청경로 로 접속

스프링 메시지

// MvcConfig.java
package config;

...
import org.springframework.context.support.ResourceBundleMessageSource;

@Configuration
@EnableWebMvc
public class MvcConfig implements WebMvcConfigurer {
	...
	@Bean
	public MessageSource messageSource() {
		ResourceBundleMessageSource ms = new ResourceBundleMessageSource();
        
        // main/resource/message 디렉토리의 label.properties 파일
		ms.setBasename("message.label");
		ms.setDefaultEncoding("UTF-8");
		return ms;
	}
}

// label.properties
msg.test=나는 메시지다
<!-- testView.jsp -->
<%@ page contentType="text/html; charset=utf-8" %>
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>

<!DOCTYPE html>
<html>
<head><title>I am testView.jsp</title></head>
<body>
	<h1>I am Header</h1>
	<p> ${testData} </p>
	
	<h3 style="color:red;">
		<spring:message code="msg.test" />
	</h3>
</body>
</html>
profile
노는게 제일 좋습니다.

0개의 댓글