[Spring] - MVC2 구조 구현

2020. 9. 3. 23:31개발공부/Spring

728x90

#DispatcherServlet #HandlerMapping #HandlerAdapter #HomeController

1. Hello World 가 페이지에 출력되는 이유

Spring project를 생성했다. 프로젝트를 서버로 실행해보면 Hello World 문자와 함께 현재 시각(년,월,일,시,분,초)가 뜬다. xml파일에 UTF-8을 업데이트 해주기 전이라 ?? 물음표가 많이 뜬다. 

서버만 올려줬을 뿐인데 페이지는 어떻게 자동으로 올라가며 URL과 페이지 내 내용은 어떻게 설정된 것일까?

 1) 페이지가 실행된 원리

 프로젝트가 가진 폴더들 중 페이지를 올려주는데 관여하는 곳은 web.xml, HomeController, servlet-config.xml, home.jsp 다. 순서대로 살펴볼까. 

  - web.xml

  일단 Bean 등록을 담당하는 config.xml 파일을 <param> jstl으로 설정해두었다.  Spring legacy 장점 중 자율성이 있는데, mvc-config.xml을 원하는대로 이름은 변경 가능하다. 아래 DispatchServlet연관 jstl 태그로 내려가보자. 어제 업로드 한 MVC2 구조에 자세한 설명이 있는데, Spring Framework에서 Browser가 요청을 전달했을 때 최초로 받는 단계가 DispatchServlet 이다. web.xml 에선 name, class, value를 설정해준다. value를 보면 실행하는 xml파일이 어디 경로에 있는지 입력되어 있다. 자동으로 설정돼 있었고, 변경해준 사항은 없다. 

 (문장이 많아져 문단을 바꿔줬다.) <servelt-mapping>은 HandlerMapping, Adapter의 처리와 관련있다. <url-pattern> jstl 태그에 / (슬래시)가 들어가 있는데, "/"로 처리된 모든 URI는 내가 처리하겠다. 라는 표시이다. JSP에서 @WebServlet("*.do*")와 같은 기능이다.(앞에 뭐가 쓰여있던 .do로 끝나는 uri는 내가 다 처리하겠다 라는 뜻).

조금 더 자세히. HanlderAdpter는 HomeController에서 @RequestMapping(value = "/", ... ) 의 value 값을 찾아 URI로 판단해 ViewResolver로 이어지는 데 토스를 해준다. HandlerMapping은 해당 메서드를 찾고, servlet-config.xml에서 return  되는 문자열을 ViewResolver로 보내 jsp 형식의 파일을 View로 구현하기까지 길을 터준다.

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

	<!-- mvc와 관련된 스프링 설정파일의 위치를 지정하는 태그 (Bean 등록)-->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/spring/mvc-config.xml</param-value>
	</context-param>
	
	<!-- Creates the Spring Container shared by all Servlets and Filters -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<!-- DispathServlet 등록 설정 -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/servlet-config.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
		
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
		<!-- JSP에서 @WebServlet("*.do")와 같음. "/"로 처리되어 있으면 뭐든지 다 처리하겠다. FrontController임. -->
	</servlet-mapping>

</web-app>

  - serlvet-config.xml

  web.xml의 DispatcherServlet이 실행되는 곳이다. 아노테이션을 이용해 자동 bean 주입 명령을 처리하는 태그<context: annotation-config />, <annotation-driven>가 들어가고, 정적 자원을 절대 경로로 매핑해줄 <resources> 태그도 들어간다. 더욱 중요한 부분은 그 다음 있는 ViewResolver <bean>을 등록하는 태그다. <property>를 사용해 setter 방식으로 객체 주입을 진행했다. prefix(접두사) /WEB-INF/views/ 절대경로가 작성되었고, suffix(접미사)는 .jsp 파일 형식이 붙게 되어있다. 뒤에 설명할 HomeController 메서드를 보면 return 되는 String type 문자열이 있다. return된 문자열은 prefix, suffix 안에 들어가 ViewResolver가 알맞은 URI 경로를 만들고 View에 전달해주도록 해준다.

맨 아래 <context: component-scan> 태그는 아노테이션을 사용해 자동으로 bean 등록해주는 설정이다. 쉽게 말해서 @Controller 아노테이션을 입력하면 DispatchServlet이 의존 객체로 주입되고 HomeController가 실행될 때 자동으로 같이 실행된단 얘기다. Trigger처럼. 그때 윗 문단 마지막 문장의 value"/home" 경로를 찾아 URI에 전달해 페이지를 열 수 있게 해준다!

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

	<!-- DispatcherServlet 관련 설정 -->
	
	<!-- -->
	<context:annotation-config />
	<!-- 아노테이션을 통한 자동 Bean 주입 명령을 처리하는 태그 -->
	<annotation-driven />

	<!-- 정적 자원(HTML, CSS, IMG, JS)을 절대 경로로 쉽게 매핑하는 태그 -->
	<resources mapping="/resources/**" location="/resources/" />

	<!-- ViewResolver Bean 등록 설정 -->
	<!--  - 컨트롤러가 리턴한 view문자열을 해석하여 경로를 만들어서
	파일을 찾아 응답하는 ViewResolver의 Bean 등록 코드 
		- prefix 필드와 suffix 필드의 setter 주입을 통해 
		컨트롤러에서 return된 문자열을 조합해줌-->
	<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>
	
	<!-- 아노테이션을 사용하여 자동으로 Bean 등록을 하게 해주는 설정 -->
	<context:component-scan base-package="com.spring.web" />
	
	
	
</beans:beans>

- HomeController

  Browser(Client)에서 요청이 왔을 때, DispatcherServlet이 제일 처음 받고, HandlerAdapter와 HandlerMapping에 처리를 할당해준 뒤 정보를 긁어가는 곳이다. 따라서 정보를 주는 명령어가 입력되는 곳이라고 말할 수 있다. 이후 BoardController, MemberController와 같이 용도에 따라 생겨날 예정이고 그때마다 Handler 형제들이 받아서 Response 할 수 있게 전달해준다. 

아노테이션! Spring의 자동화를 구현시켜주는 약속어? 위주로 볼필요가 있다. 첫 번째로 @Controller. 앞서 설명한 servlet-config.xml(DispatchServlet 관련 설정을 해주는 곳)에서 자동으로 의존 객체가 돼 주입까지 이루어진다고 했다. 즉 @Controller가 있어야만 컨트롤러가 받은 요청을 ViewResolver로 주고 View까지 닿는 교두보 역할을 해줄 수 있다.

그리고 @RequestMapping은 Handler에서 "컨트롤러야, Browser가 www.cafe.naver.com/test 란 요청을 보내왔어. 여기에 맞는 메서드를 찾아 URI를 가져갈게." 라고 응답하게 해준다. value에 들어가는 "/test"는 HandlerAdapter여기있네! 하면서 찾아간다. 절대경로 "/" 앞에는 server.xml에 설정해놓은 <Context path="/web2">가 들어간다. method는 HTTP 응답처리 방식인데 GET은 일반적인 입력을 그대로 처리해주는 방식이며 POST는 암호화하여 민감한 정보(ID, PW)를 처리할 때 쓰는 방식이다. JSP 강의 때 들은게 맞다면 GET 방식은 Client에 노출되는 화면일 때 사용해주고 POST 방식은 개발자들만 보고 처리해주는 방식이다. 

@Controller
public class HomeController {
	
	private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
	
	/**
	 * Simply selects the home view to render by returning its name.
	 */
	@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);
		
		//session.setAttribute, request.setAttribute와 유사한 형태
		//저장해두면 jsp파일에서 EL로 사용할 수 있음
		model.addAttribute("serverTime", formattedDate );
		
		return "home";
	}
	
	//test.jsp를 열기 위한 요청 메서드 구성
	
	//Handler가 요청메서드를 돌려주기 위한 uri를 작성
	@RequestMapping(value="/test", method = RequestMethod.GET)
	public String test() {
		
		System.out.println("/test 요청이 들어옴 : GET 방식");
		return "test";
	}
	
}

 

자 다시 한번 web2/ 페이지를 보자. MVC2 구조로 구동된 원리가 보인다.