1. MVC란?
- Model-View-Controller
- Model: 뷰가 렌더링 할 때 필요한 데이터. 사용자가 요청한 상품 목록이나 주문 내역 등
- View: 실제로 보여지는 부분. 모델을 사용해서 렌더링을 함.
- Controller: 사용자의 액션에 응답하는 컴포넌트. 모델을 업데이트하고 다른 액션을 수행함
MVC Model 1 아키텍처
- 브라우저가 요청하면, 해당 요청을 JSP가 받음
- 요청만큼 JSP 페이지가 존재해야 함
- Java Bean을 통해 DB와 연결됨
- 문제점: JSP 자체에 HTML, JAVA 코드가 섞여있음. 유지보수가 어려움
MVC Model 2 아키텍처
- 요청을 Servlet이 받게 함
- Servlet이 Java Bean을 통해 DB에서 데이터를 꺼내옴
- JSP를 통해 결과를 화면에 보여지게 함
- 로직과 뷰를 분리함
MVC Model 2 발전 아키텍처
- 클라이언트가 보내는 모든 요청을 프론트 컨트롤러라고 하는 Servlet 클래스가 받음 (프론트 컨트롤러는 딱 하나만 존재)
- 요청만 받고 실제 일은 컨트롤러가 처리함. 컨트롤러 혹은 핸들러라고 불리는 클래스에게 위임함
- 관련된 URL을 하나의 클래스에서 처리할 수 있도록 함
- 이런 컨트롤러는 자바 Bean들을 이용해 결과를 만듦
- 만든 결과를 모델에 담아 프론트 컨트롤러에게 보냄
- 그럼 프론트는 알맞은 뷰에게 모델을 전달해서 그 결과를 출력하도록 함
- 이러한 MVC 패턴을 지원하는 게 Spring Web Module
2. Spring MVC 패턴의 흐름
- Database 제외 파란색: Spring MVC가 제공해 줌
- 보라색: 개발자가 만들어야 함
- 녹색: Spring 제공 및 개발자가 만듦
1. 클라이언트가 요청을 보내면, 모든 요청을 Dispatcher Servlet이 받음
2. 요청을 처리해 줄 컨트롤러와 메소드가 무엇인지, Handler Mapping에게 물어봄
Handler Mapping이 혼자서 알아낼 수 없음. 어떤 요청에 어떤 Controller가 동작할지, XML 파일이나 Java 파일에 애노테이션으로 설정함. -> 이런 정보들을 Handler Mapping 객체들이 관리함
3. Dispatcher Servlet이 2번을 통해 요청을 처리할 컨트롤러와 메소드를 알아냈다면, Handler Adapter에게 실행을 요청함
4. 결정된 컨트롤러와 메소드가 실행됨
5. 그 결과를 Model에 받아서 Dispatcher Servlet에게 전달함. 이때 View name을 같이 보내줌
6. Dispatcher Servlet은 Controller가 리턴한 View name을 가지고 적절한 View Resolver를 통해서, 어떤 View인지 정확하게 알게 됨
7. View를 통해서
8. 응답함
Spring MVC를 이해한다 == DispatcherServlet이 어떻게 동작하는지 이해한다.
3. Spring MVC를 이용한 웹 페이지 작성 방법
3.1. DispatcherServlet을 FrontController로 설정하기
- DispatcherServlet이 FrontController라고 설정해 주어야 함
- 여러 가지 방법이 있는데 그 중 web.xml 파일에 설정하는 두 가지 방법을 알아보자
방법 1. xml spring 설정 읽어오도록 하기
<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/spring/dispatcher-config.xml</param-value> <!-- xml 파일명이 들어감 -->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
- <servlet></servlet>, <servlet-mapping></servlet-mapping> 태그에 각각의 값을 넣어주기
- 실제로 어떤 일들을 해야 되는지 여기에 저장
방법 2. Java config spring 설정 읽어오도록 하기
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.example.mvcexam.config.DispatcherConfig</param-value> <!-- Java 클래스 명이 들어감 -->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern> <!-- 모든 요청에 대해 dispatcherServlet을 수행한다 -->
</servlet-mapping>
- xml이 아니라 Java config 파일을 읽어옴
Java config spring 설정 읽어 들이도록 DispatcherServlet 설정
- 실습에서는 이 방법을 사용
3.2. Spring MVC 설정
- DispatcherServlet에 대한 정보는 web.xml에서 함
- DispatcherServlet이 읽어들여야 하는 설정은 별도로 해야 함 -> Java Config로 한다.
@Configuration
- Java Config 파일임을 알려줌
@EnableWebMvc
- Web에 필요한 Bean들을 대부분 자동으로 설정해 줌
- DispatcherServlet의 RequestMappingHandlerMapping, RequestMappingHandlerAdapter, ExceptionHandlerExceptionResolver, MessageConverter 등
- @EnableWebMvc가 기본으로 설정해 주는 거 이외에 설정이 필요하다면, WebMvcConfigurerAdapter를 상속받도록 Java Config 클래스를 작성한 후, 필요한 메소드를 오버라이딩 하도록 함
@ComponentScan
- @Controller, @Service, @Repository, @Component이 붙은 클래스를 찾아 스프링 컨테이너가 관리하게 됨
3.3. Controller(Handler) 클래스 작성하기
- @Controller를 클래스 위에 붙임
- 맵핑을 위해 @RequestMapping을 클래스나 메소드에서 사용함
(어떤 url로 들어온 요청인지 알아내서, 실제로 처리해야 하는 컨트롤러와 그 컨트롤러에서 구현하고 있는 메소드가 뭔지 알아내기 위해)
@RequestMapping
- Http 요청과 이를 다루기 위한 Controller의 메소드를 연결하는 애노테이션
- @GetMapping, @PostMapping 등
4. Spring MVC를 이용한 웹 페이지 작성 실습
4.0. Spring MVC 프로젝트 생성
# 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>mvcexam</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mvcexam</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4.1. Configuration 파일 작성하기
- DispatcherServlet이 읽어 들여야 하는 설정 정보 작성하기
# WebMvcContextConfiguration.java
package com.example.mvcexam.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration // 이 클래스는 설정 파일임. DispatcherServlet이 실행될 때 읽어들이는 설정 파일
@EnableWebMvc // 기본적인 설정들을 함
@ComponentScan(basePackages = {"com.example.mvcexam.controller"}) // 스캔해서 Bean들을 찾을 거임
public class WebMvcContextConfiguration implements WebMvcConfigurer {
// 해당 서브 도메인에 대한 요청은 다음과 같이 지정한 곳에서 찾으라는 설정
// 만약 이 부분이 없다면, 컨트롤러가 가진 RequestMapping에서 찾으려고 하면서 오류를 발생시킬 것임
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/assets/**").addResourceLocations("classpath:/META-INF/resources/webjars/").setCachePeriod(31556926);
registry.addResourceHandler("/css/**").addResourceLocations("/css/").setCachePeriod(31556926);
registry.addResourceHandler("/img/**").addResourceLocations("/img/").setCachePeriod(31556926);
registry.addResourceHandler("/js/**").addResourceLocations("/js/").setCachePeriod(31556926);
}
// 매핑 정보가 없는 요청을 처리하기 위해, default servlet handler를 사용하게 함
// @Override
// public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
// configurer.enable();
// }
// 특정 URL에 대한 처리를 컨트롤러 클래스를 작성하지 않고 매핑할 수 있도록 해줌
@Override
public void addViewControllers(final ViewControllerRegistry registry) {
System.out.println("addViewControllers가 호출됨");
registry.addViewController("/").setViewName("main"); // "/"로 요청이 들어오면 "main"이라는 뷰를 보여주도록 함
}
// 뷰 이름만으로는 실제 뷰 정보를 찾을 수 없기에, ViewResolver를 사용해야 함
@Bean
public InternalResourceViewResolver getInternalResourceViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
// 뷰 이름 앞뒤로 붙여서 뷰 파일 경로를 찾음
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
}
4.2. web.xml에 DispatcherServlet을 FrontController로 설정하기
- DispatcherServlet을 FrontController로 설정함
- DispatcherServlet이 실행될 때 4.1에서 작성한 설정 정보를 담은 클래스를 읽어다가 실행하도록 함
# web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<display-name>Spring JavaConfig Sample</display-name>
<servlet>
<servlet-name>mvc</servlet-name> <!-- 2. 해당 이름을 찾아감. 확인하니 스프링이 제공하는 DispatcherServlet을 FrontController로 할 것임을 명시하고 있음 -->
<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> <!-- 3. 작성한 설정 정보를 담은 클래스 등록 -->
<param-value>com.example.mvcexam.config.WebMvcContextConfiguration</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc</servlet-name> <!-- 1. 모든 요청에 대하여 mvc라는 이름의 Servlet 클래스가 실행되어라 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
4.3. main.jsp 생성해서 Mapping 연동 여부 확인하기
/main/webapp/WEB-INF/view/main.jsp 생성
# main.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Main Page</title>
</head>
<body>
<h1>메인 페이지입니다 :)</h1>
</body>
</html>
'강의 노트 > 웹 프로그래밍(풀스택)' 카테고리의 다른 글
[boostcourse] 3.10. Layered Architecture - BE (1) (0) | 2023.06.27 |
---|---|
[boostcourse] 3.9. Spring MVC - BE (2) (0) | 2023.06.26 |
[boostcourse] 3.8. Spring JDBC - BE (0) | 2023.06.25 |
[boostcourse] 3.7. Spring Core - BE (0) | 2023.06.24 |
[boostcourse] 2.11. Web API - BE (0) | 2023.06.21 |