SPRING_WEB MVC_1
📚 SPRING
📚 Spring MVC
MVC ( Model - View - Controller ) Pattern 이란
- Model
- 어플리케이션 상태의 캡슐화
- 상태 쿼리에 대한 응답
- 어플리케이션의 기능 표현
- 변경을 view에 통지
- View
- 모델을 화면에 시각적으로 표현
- 모델에게 업데이트 요청
- 사용자의 입력을 컨트롤러에 전달
- 컨트롤러가 view를 선택하도록 허용
- Controller
- 어플리케이션의 행위 정의
- 사용자 액션을 모델 업데이트와 mapping
- 응답에 대한 view 선택
- MVC Pattern
- Model 2 ( Web MVC ) 요청 흐름
Spring MVC 란
- Spring은 DI 나 AOP 같은 기능 뿐만 아니라 Servlet 기반의 WEB 개발을 위한 MVC Framework를 제공
- Spring MVC는 Mode2 Architecture와 Front Controller Pattern을 Framework 차원에서 제공
- 기존 작업들은 Servlet 안에 같이 있었지만 안에서 Auto로 처리할 수 있는 부분과 아닌 부분을 나눈다.
- 기존 동일 반복 작업 같은 경우를 Auto로 처리하고 이 부분이 Framework로 넘어가며 Front Controller 역할을 Spring이 한다.
- 개발자는 Controller 부분 (data)만 신경써서 작업하면 된다.
- Spring MVC Framework는 Spring을 기반으로 하고 있기 때문에 Spring이 제공하는 Transaction 처리나 DI 및 AOP등을 손쉽게 사용
Spring MVC 구성요소
-
DispatcherServlet ( Front Controller )
- 모든 클라이언트의 요청을 전달받음
- Controller에게 클라이언트의 요청을 전달하고, Controller가 리턴 한 결과값을 View에게 전달하여 알맞은 응답을 생성
-
HandlerMapping
- 클라이언트의 요청 URL을 어떤 Controller가 처리할지를 결정
- URL과 요청 정보를 기준으로 어떤 핸들러 객체를 사용할지 결정하는 객체이며, DispatcherServlet은 하나 이상의 핸들러 매핑을 가질 수 있다.
-
Controller
- 클라이언트의 요청을 처리한 뒤, Model을 호출하고 그 결과를 DispatcherServlet에 알려준다.
- 우리가 신경써야할 부분 !!
-
ModelAndView
- Controller가 처리한 데이터 및 화면에 대한 정보를 보유한 객체
-
ViewResolver
- Controller가 리턴 한 뷰 이름을 기반으로 Controller의 처리 결과를 보여줄 View를 결정
- 매번 똑같은 경로글을 생략할 수 있다.
-
View
- Controller의 처리 결과를 보여줄 응답화면 생성
Spring MVC 요청 흐름
- Spring MVC 실행 순서
- DispatcherServlet이 Client 요청을 수신 ( 그림 1 )
- 단일 Front Controller Servlet
- 요청을 수신하여 처리를 다른 컴포넌트에 위임
- 어느 Controller에 요청을 전송할지 결정
- DispatcherServlet은 Handler Mapping에 어느 Controller를 사용할 것인지 문의 ( 그림 2, 3 )
- URL과 Mapping
- DispatcherServlet은 요청을 Controller에게 전송하고 Controller는 요청을 처리한 후 결과 리턴 ( 그림 4 )
- Business Login 수행 후 결과 정보 (Model)가 생성되어 JSP와 같은 view에서 사용됨
- ModelAndView Object에 수행결과가 포함되어 DispatcherServlet에 리턴 ( 그림 5 )
- ModolAndView는 실제 JSP정보를 갖고 있지 않으며 ( 이름만 가지고 있다 ), ViewResolver가 논리적 이름을 실제 JSP 이름으로 변환 ( 그림 6, 7 )
- View는 결과정보를 사용하여 화면을 표현함 ( 그림 8, 9 )
- DispatcherServlet이 Client 요청을 수신 ( 그림 1 )
- 시나리오 식으로 정리 ( login을 예를 들어 )
먼저 옛날에는 Client로 부터 ‘Control?act=login’ 으로 입력을 받았다. 이것이 요즘은 ../login 으로 입력을 받는다.
그 입력을 받아 DispatcherServlet에게 요청을 한다.
그리고 Controller를 요청한다. 이 과정은 ‘if(act==login){ … }’ 을 진행했던 과정이다.
login을 받았는데 어떻게 처리해야 하냐? HanlderMapping을 통해 어떤 Controller가 있는데 그 Controller 가 가지고 있는 method를 호출해야 함을 결정한다.
그래서 그 Controller에 처리 요청을 보낸다.
그러면 이제 Controller의 처리 과정이 우리 개발자들이 집중적으로 해야할 일이다. ( Model 처리 ) 그 Controller가 해야하는 기능이나 역할 등에 따라 달라진다.
지금은 login이니 login 메서드가 있을 것이다. 여기 뒤에 service, dao 과정이 포함된다.
처리를 하고 ModelAndView ( 처리과정 포함 )를 DispatcherServlet에 리턴해준다. 여기서 ModelAndView가 정보를 가지고 있는게 아니라 단지 이름만 가지고 있다. 예를 들면 list라는 jsp의 이름만 가지고 있다.
이 정보를 ViewResolver에 객체 요청을 하여 거기서 앞, 뒤로 여러 정보들을 붙여서 리턴해준다. 예를 들면 ‘../../list.jsp’ 가 된다.
그 정보를 이제 기본 값은 forward 고 redirect로 설정가능한 응답생성 요청을 한다.
그러고 View에서 이제 Client에게 JSP를 사용하여 화면을 표현한다.
여기서 DispatcherServlet에 설정을 해주어야한다 !! ( 자동적으로 되는 것이 아님 ! )
xml을 만들거나 Annotation을 등록하거나.. -> 설정이 끝나면 내부적으로 자동 완성 된다.
Spring MVC 구현
- Spring MVC를 이용한 Application 구현 Step
- web.xml에 DispatcherServlet 등록 및 Spring 설정 파일 등록 ( 최소 3개의 xml file 생성 - web.xml, web( Controller ), NonWeb( Service, DAO ) / DI는 반드시 !! ( xml, java ))
- 설정 파일에 HandlerMapping 설정
- Controller 구현 및 Context 설정 파일(servlet-context.xml)에 등록
- Controller와 JSP 연결을 위해 View Resolver 설정
- JSP 코드 작성
- Controller 작성
-
web.xml -> DispatcherServlet 설정
- DispatcherServlet을 여러 개 설정가능
- 각 DispatcherServlet마다 각각의 ApplicationContext 생성
- 최상위 Root ContextLoader 설정
- Context 설정 파일들을 로드하기 위해 web.xml 파일에 리스너 설정 ( ContextLoaderListener )
- 리스너 설정이 되면 /WEB-INF/spring/root-context.xml 파일을 읽어서 공통적으로 사용되는 최상위 Context를 생성
- 그 외의 다른 Context 파일들을 최상위 어플리케이션 Context에 로드하기 위해서는 밑에 코드에서 2번을 처럼..
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- 프로젝트가 was에 올라가는 순간에 밑에 xml을 읽어서 contextConfigLocation에 호출하는 것-->
<!-- root-context가 servlet-context 보다 먼저 실행된다 -->
<!-- context-param은 변수를 선언하는 것이다 -->
1.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
2.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml
classpath:com/test/web/application.xml
<!-- classpath에 위치한 설정파일로부터 로드 -->
<!-- src(java) 에 있으면 통상적으로 classpath에 있다고 한다. -->
<!-- src에 있으면 'classpath:...' 으로 작성하고
WebContent에 있으면 full 경로를 작성한다.
-->
</param-value>
</context-param>
<!-- web 응용 프로그램 -> 서블릿, 리스너, 필터 ( 이름이 정의되어 있다. ) -->
<!-- ContextLoaderListener 리스너 설정 !!! -->
<!-- context가 로딩이 되는 순간 위에것을 읽어라 라는 뜻이다 ( 메모리가 로드되는 순간 ) -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- dispatcherservlet의 객체를 만들고 이안에 밑에 것을 집어넣으세요 라는 파라미터이다 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- '/' 를 사용하면 다 dispatcher가 봐줄 것이다 -->
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
-
Application Context 분리
- 어플리케이션 레이어에 따라 Application Context 분리
- Security Layer => board-security.xml
- Web Layer => board-servlet.xml
- Service Layer => board-service.xml
- Persistence Layer => board-dao.xml
-
Controller Class 작성
예시로 HomeController.java를 작성한다.
여기서 Context 설정파일에 Controller를 꼭 등록해야한다. ( servlet-context.xml )
파일이 있는 주소를 적어준다.
Controller 등록
<context:component-scan base-package="com.ssafy.hello" />
HomeController.java
package com.ssafy.hello;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
model.addAttribute("msg", "안녕 스프링 !!!");
return "index";
}
}
Controller 와 response page 연결을 위한 ViewResolver를 설정한다. ( servlet-context.xml )
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!-- property 는 setter 역할 -->
<!-- 앞에 (prefix) value를 삽입 -->
<!-- 뒤에 (suffix) value를 삽입 -->
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
<!-- 결과는 /WEB-INF/views/index.jsp 가 된다. -->
</beans:bean>
<context:component-scan base-package="com.ssafy.hello" />
JSP ( index.jsp )
HomeController.java에서 설정해준 msg ( 안녕 스프링 !! )를 화면에 출력해준다.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>${msg}</h3>
</body>
</html>
생성, 설정
- 프로젝트 생성
Spring Legacy Project -> Spring mvc project - 설정
pom.xml -> java version ( 1.8 ) , spring version ( 5.3.18 ), 141.142 ( 1.8 ) -> project -> maven -> update project -> force check -> ok
스프링은 코드로 공부하는 것이 아니다 !!!
구조 파악 !!!!! ( 설정 중요 !! ) -> 에러잡기가 힘들다.
web에 대한 정보는 web.xml을 보면 dispatcherServlet이 설정되어 있다.
여기서 servlet-context.xml을 확인한다. servlet-context.xml에는 Controller에 대한 정보들이 저장되어 있다.
Non web에 대한 정보는 root-context.xml 에 있다. ( service, dao에 대한 정보 )
MVC 패턴은 절대 JSP를 직접 호출하지 않는다 !!
항상 Controller를 거쳐서 호출한다.
그리고 Spring Framework를 사용하면 기존 기능들을 안쓰는 것이 아니라 내부적으로 작업을 해주는 것이다.