6 분 소요

📚 SPRING


📚 Spring MVC

MVC ( Model - View - Controller ) Pattern 이란


  • MVC Pattern
    • 어플리케이션의 확장을 위해 Model, View, Controlle 세가지 영역으로 분리
    • 컴포넌트의 변경이 다른 영역 컴포넌트에 영향을 미치지 않음 ( 유지보수 용이 )
    • 컴포넌트 간의 결합성이 늦아 프로그램 수정이 용이 ( 확장성이 뛰어남 )
    • 장점
      • 화면과 비즈니스 로직을 분리해서 작업 가능
      • 영역별 개발로 인하여 확장성이 뛰어남
      • 표준화된 코드를 사용하므로 공동작업이 용이하고 유지보수성이 좋음
    • 단점
      • 개발과정이 복잡해 초기 개발 속도가 늦음
      • 초보자가 이해하고 개발하기에 다소 어려움


  • 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 실행 순서
    1. DispatcherServlet이 Client 요청을 수신 ( 그림 1 )
      • 단일 Front Controller Servlet
      • 요청을 수신하여 처리를 다른 컴포넌트에 위임
      • 어느 Controller에 요청을 전송할지 결정
    2. DispatcherServlet은 Handler Mapping에 어느 Controller를 사용할 것인지 문의 ( 그림 2, 3 )
      • URL과 Mapping
    3. DispatcherServlet은 요청을 Controller에게 전송하고 Controller는 요청을 처리한 후 결과 리턴 ( 그림 4 )
      • Business Login 수행 후 결과 정보 (Model)가 생성되어 JSP와 같은 view에서 사용됨
    4. ModelAndView Object에 수행결과가 포함되어 DispatcherServlet에 리턴 ( 그림 5 )
    5. ModolAndView는 실제 JSP정보를 갖고 있지 않으며 ( 이름만 가지고 있다 ), ViewResolver가 논리적 이름을 실제 JSP 이름으로 변환 ( 그림 6, 7 )
    6. View는 결과정보를 사용하여 화면을 표현함 ( 그림 8, 9 )


  • 시나리오 식으로 정리 ( 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
    1. web.xml에 DispatcherServlet 등록 및 Spring 설정 파일 등록 ( 최소 3개의 xml file 생성 - web.xml, web( Controller ), NonWeb( Service, DAO ) / DI는 반드시 !! ( xml, java ))
    2. 설정 파일에 HandlerMapping 설정
    3. Controller 구현 및 Context 설정 파일(servlet-context.xml)에 등록
    4. Controller와 JSP 연결을 위해 View Resolver 설정
    5. 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를 사용하면 기존 기능들을 안쓰는 것이 아니라 내부적으로 작업을 해주는 것이다.