티스토리 뷰

직전 포스팅에서 Spring MVC 구조를 이해하기 위해 Model2 구조를 직접 구현했었다.

 

이번에는 직전 포스팅을 설명하기 위해 구현해놓은 구조를 하나씩 변경해가면서 Spring MVC 모델의 구조를 다시 한번 이해해보는 것이 목적이며, 비슷한 내용을 이전에 한번 포스팅한 적이 있으니 참고하면 이해가 더욱 쉬워질 것이다.

 

- spring.xml 문서 작성: https://til-choonham.tistory.com/168

 

[Spring] spring.xml 문서 작성

요청 사항에 대한 Controller를 반환하기 위한 HandlerMapping을 수행하기 위해서는 해당 역할을 수행하는 xml문서를 따로 작성해야 한다. 그 방법은 다음과 같다. 우선 간단한 게시판 예제를 따라 진행

til-choonham.tistory.com

 

- web.xml 문서에 servlet 등록: https://til-choonham.tistory.com/167

 

[Spring] web.xml 문서에 Servlet 등록

요청을 처리할 DispatcherServlet을 사용하기 위해서는 우선적으로 web.xml 문서에 Servlet 파일들을 등록해야 한다. 방법은 다음과 같다. spring_simple_board 서블릿 이..

til-choonham.tistory.com

 

위 두 포스팅은 STS를 들어가기 전, 일반 Dynamic Web 개발환경에서 spring을 실습한 내용이기 때문에 완전히 같지는 않지만, 참고용으로는 한번 보길 추천한다.

 


우선, 지난 포스팅에서 직접 구현한 Model2의 구조는 다음과 같다.

위 그림에서 4번 리턴 값을 String -> ModelAndView 객체로 변경해주면, 그게 바로 Spring MVC의 전체적인 흐름이라고 할 수 있다. 

 

더 자세하게 다뤄보자.


1. DispatcherServlet 등록

 

STS에서는 Servlet파일을 생성만 하면 알아서 다음과 같이 web.xml 파일에 등록해준다. 

 

◎web.xml

 <servlet>
    <description></description>
    <display-name>action</display-name>
    <servlet-name>action</servlet-name>
    <servlet-class>com.choonham.view.controller.DispatcherServlet</servlet-class>
  </servlet>

하지만, 보시다시피 servlet-class 가 현재 servlet 파일이 위치한 경로를 가리키고 있다. Spring 프레임워크에서 제공하는 DispatcherServlet을 사용하기 위해서, 우선 이 경로부터 변경해줘야 한다.

 

◎web.xml

 <servlet>
    <description></description>
    <display-name>action</display-name>
    <servlet-name>action</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  </servlet>

2. 스프링 컨테이너 구동

 

클라이언트의 요청으로 DispatcherServlet 객체가 생성되고 나면, DispatcherServlet 클래스에 재정의된 init() 메서드가 자동으로 실행되어 XmlWebApplicationContext 라는 스프링 컨테이너가 구동된다. (XmlWebApplicationContext 는 ApplicationContext를 구현한 클래스 중 하나이다. )

Spring MVC 의 구성 요소 중에서 DispatcherServlet 클래스가 유일한 서블릿이다. 따라서 서블릿 컨테이너는 web.xml 파일에 등록된 DispatcherServlet만 생성해준다. 그러나, DispatcherServlet 객체 혼자서는 클라이언트의 요청을 처리할 수 없고, 앞서 언급했듯이 HandlerMapping, Controller, ViewResolver 객체들과 상호작용해야 한다. 이 객체들을 메모리에 생성하기 위해 스프링 컨테이너를 구동하는 것이다.

 

따라서, 이를 위해 web.xml 에 등록된 Servlet-name 뒤에 -servlet.xml을 붙여서 스프링 컨테이너 설정 파일을 생성해줘야 한다. (DispatcherServlet이 스프링 컨테이너를 구동할 때 무조건 /WEB-INF/name-servlet.xml 파일을 찾아 로딩하기 때문에)

 

바로 생성해주자.

굳이 name-servlet.xml로 컨테이너 설정 파일을 생성하기 싫다거나, 특별히 정리해야 할 경우가 있을 때는

web.xml 에서 servlet등록 부분에 <init-param> 태그를 이용하여 다음과 같이 설정해줄 수 있다.

(action-servlet.xml -> presentation-layer.xml 로 파일 이름 변경한 경우)

 

◎web.xml

 <servlet>
    <description></description>
    <display-name>action</display-name>
    <servlet-name>action</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
    	<param-name>contextConfigLocation</param-name>
    	<param-value>/WEB-INF/presentation-layer.xml</param-value>
    </init-param>
  </servlet>

 

위와 같이 설정하면, 스프링에서 제공하는 DispatcherServlet 이 init() 메서드를 자동 호출할 때, contextConfigLocation 이라는 파라미터로 설정한 정보를 추출하여 스프링 컨테이너를 구동할 때 사용한다.


3. Controller 구현

 

이제, 직접 구현하며 생성했던 Controller를 Spring 에서 제공하는 Controller로 변경하여야 한다.

따라서 Controller를 구현받았던 다른 모든 Cotroller 객체들의 implements를 변경한다.

 

또한 앞서 언급했듯, String 타입을 반환하는 것이 아닌 ModelAndView 객체를 반환해야 하기 때문에 이 부분도 변경한다.

 

◎LoginController.java

package com.choonham.view.user;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import com.choonham.biz.service.UserVO;
import com.choonham.biz.service.impl.UserDAO_Temp;


public class LoginController implements Controller{

	public LoginController() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
		System.out.println("로그인 처리");
		String id = request.getParameter("id");
		String password = request.getParameter("password");
		
		UserVO user = null;
		UserVO vo = new UserVO();
		vo.setId(id);
		vo.setPassword(password);

		UserDAO_Temp dao = new UserDAO_Temp();
		
		user = dao.getUserInfo(vo);
		System.out.println(user.getName());
		
		ModelAndView mav = new ModelAndView();
		
		if(user != null) {
			mav.setViewName("getBoardList.do");
		} else {
			mav.setViewName("login.jsp");
		}
		
		return mav;

	}

}

 

◎BoardListController.java

package com.choonham.view.board;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import com.choonham.biz.service.BoardVO;
import com.choonham.biz.service.impl.BoardDAO_Temp;


public class GetListController implements Controller {

	public GetListController() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
		System.out.println("글 목록 검색 처리");
		BoardVO vo = new BoardVO();
    	BoardDAO_Temp dao = new BoardDAO_Temp();
    	List<BoardVO> boardList = dao.getBoardList(vo);
    	
    	HttpSession session = request.getSession();
    	session.setAttribute("boardList", boardList);
    	session.setAttribute("name", request.getParameter("name"));
    	
    	ModelAndView mav = new ModelAndView();
    	mav.addObject("boardList", boardList);
    	mav.setViewName("getBoardList");
    	
		return mav;
	}

}

4. HandlerMapping 등록

 

작성된 LoginController가 클라이언트의 "/login.do" 요청에 대하여 동작하게 하려면, 스프링 설정 파일인

action-servlet.xml에 HandlerMapping과 LoginController를 bean 객체로 등록해야 한다.

 

◎action-servlet.xml


5. ViewResolver 활용하기

 

viewResolver를 이용하면 클라이언트로부터의 직접적인 JSP 호출을 차단할 수 있어서 대부분 웹 프로젝트에서 ViewResolver 사용은 거의 필수이다.

 

◎action-servlet.xml

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

<!--  HandlerMapping 등록 -->
<bean class = "org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	<property name = "mappings">
		<props>
			<prop key = "/login.do">login</prop>
			<prop key = "/getBoardList.do">getBoardList</prop>
		</props>
	</property>
</bean>

<!-- Controller 등록 -->
<bean id = "login" class = "com.choonham.view.user.LoginController"></bean>
<bean id = "getBoardList" class = "com.choonham.view.board.GetListController"></bean>

<!--  ViewResolver 등록 -->
<bean id = "viewResolver" class = "org.springframework.web.servlet.view.InternalResourceViewResolver" >
	<property name = "prefix" value = "/"></property>
	<property name = "suffix" value =".jsp"></property>
</bean>

</beans>

 

또한 ViewResolver를 적용시킨 뒤에는 Controller -> .do 로 요청을 보낼 때,  반드시 다음과 같이 redirect: 를 붙여줘야 VirwResolver 를 무시하고 요청을 보낸다.

 

◎LoginController.java

package com.choonham.view.user;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

import com.choonham.biz.service.UserVO;
import com.choonham.biz.service.impl.UserDAO_Temp;


public class LoginController implements Controller{

	public LoginController() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
		System.out.println("로그인 처리");
		String id = request.getParameter("id");
		String password = request.getParameter("password");
		
		
		UserVO vo = new UserVO();
		vo.setId(id);
		vo.setPassword(password);

		UserDAO_Temp dao = new UserDAO_Temp();
		
		UserVO user = dao.getUserInfo(vo);
		System.out.println(user.getName());
		
		ModelAndView mav = new ModelAndView();
		
		if(user != null) {
        	//redirect: 없을 시: getBoardList.do.jsp 로 요청을 보냄
			mav.setViewName("redirect:getBoardList.do");
		} else {
			mav.setViewName("redirect:login.jsp");
		}
		
		return mav;

	}

}

 

Comments