티스토리 뷰

스프링 프레임워크를 실습하기 이전에 MVC Model2 구조를 한번 다룬 적이 있다. 그 때는 web.xml 문서를 이용하여 HandlerMapping과 viewResolver, DispatcherServlet을 등록해서 사용했지만, Spring 프레임워크는 이 구조를 모두 자동으로 구현해준다. 

 

이는 아주 편리한 feature이긴 하지만, 데이터의 흐름을 눈으로 따라가기가 쉽지 않아서 전체적인 이해나 디버깅이 쉽지 않았다. 

 

그래서 이번에는 HandlerMapping과 viewResolver, DispatcherServlet 클래스들을 직접 구현하면서 각각의 모듈들이 어떤 기능을 하고 어떻게 사용되는 지 한번 확인해보려고 한다.

 

바로 들어가보자.


우선, model2의 대략적인 처리 순서는 다음과 같다.

1. 클라이언트가 특정 버튼을 클릭하여 "~.do" 요청을 전송하면 DispatcherServlet이 요청을 받는다.

2. DispatcherServlet은 HandlerMapping 객체를 통해 해당 요청을 처리할 Controller를 검색하고,

3. 검색된 Controller의 handleRequest() 메서드를 호출하여 로직을 처리한다.

4. 로그인 처리 후에 이동할 화면 정보가 리턴되면

5. DispatcherServlet은 ViewResolver를 통해 접두사와 접미사가 붙은 JSP 파일의 이름과 경로를 리턴받는다.

6. 최종적으로 JSP를 실행하고 실행결과가 브라우저에 응답된다.

 

정리해보면,

클래스 기능
DispatcherServlet 유일한 서블릿 클래스로서 모든 클라이언트의 요청을 가장 먼저 처리하는 Front Controller
HandlerMapping 클라이언트의 요청을 처리할 Controller 맵핑
Controller 실질적인 클라이언트의 요청 처리
ViewResolver Controller가 리턴한 View 이름으로 실행될 JSP 경로 완성

로그인 기능을 예로 들어, 각 클래스들을 구현해보겠다.

 

◎Controller.java (Interface)

package com.choonham.view.controller;

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

public interface Controller {
	String handleRequest(HttpServletRequest request, HttpServletResponse response);
}

◎LoginController.java

package com.choonham.view.user;

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

import com.choonham.biz.service.UserVO;
import com.choonham.biz.service.impl.UserDAO_Temp;
import com.choonham.view.controller.Controller;

public class LoginController implements Controller{

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

	@Override
	public String 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());
		
		if(user != null) {
			return "getBoardList.do";
		} else {
			return "login";
		}

	}

}

◎HandlerMapping.java

package com.choonham.view.controller;

import java.util.HashMap;
import java.util.Map;

import com.choonham.view.board.DeleteController;
import com.choonham.view.board.GetBoardController;
import com.choonham.view.board.GetListController;
import com.choonham.view.board.InsertController;
import com.choonham.view.user.LoginController;
import com.choonham.view.user.LogoutController;

public class HandlerMapping {

	private Map<String, Controller> mappings;
	
	public HandlerMapping() {
		mappings = new HashMap<String, Controller>();
		mappings.put("/login.do", new LoginController());
		mappings.put("/getBoardList.do", new GetListController());
		mappings.put("/getBoard.do", new GetBoardController());
		mappings.put("/insertBoard.do", new InsertController());
		mappings.put("/deleteBoard.do", new DeleteController());
		mappings.put("/logout.do", new LogoutController());
	}
	
	public Controller getController(String path) {
		return mappings.get(path);
	}

}

◎ViewResolver.java

package com.choonham.view.controller;

public class ViewResolver {

	public String prefix;
	public String suffix;
	
	public ViewResolver() {
		
	}

	public void setPrefix(String prefix) {
		this.prefix = prefix;
	}

	public void setSuffix(String suffix) {
		this.suffix = suffix;
	}
	
	public String getView(String viewName){
		return prefix + viewName + suffix;
	}

}

◎DispatcherServlet.java

package com.choonham.view.controller;

import java.io.IOException;
import java.util.List;

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

import com.choonham.biz.service.BoardVO;
import com.choonham.biz.service.UserVO;
import com.choonham.biz.service.impl.BoardDAO;
import com.choonham.biz.service.impl.BoardDAO_Temp;
import com.choonham.biz.service.impl.UserDAO_Temp;


public class DispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
    private HandlerMapping handlerMapping;
    private ViewResolver viewResolver;
    
    //servlet 객체가 생성된 후에 자동 호출
    public void init() throws ServletException {
    	handlerMapping = new HandlerMapping();
    	viewResolver = new ViewResolver();
    	viewResolver.setPrefix("./");
    	viewResolver.setSuffix(".jsp");
    	
    }

    public DispatcherServlet() {
        super();
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//response.getWriter().append("Served at: ").append(request.getContextPath());
		process(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");
		process(request, response);
	}
	
	private void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 1. 클라이언트의 요정 path 정보를 추출한다.
		String uri = request.getRequestURI();
		String path = uri.substring(uri.lastIndexOf("/"));
		
		// 2. HandlerMapping을 통해 path에 해당하는 Controller를 검색한다.
		Controller ctrl = handlerMapping.getController(path);
		
		// 3. 검색된 Controller를 실행한다.
		String viewName = ctrl.handleRequest(request, response);
		
		// 4. ViewResolver를 통해 viewName에 해당하는 화면을 검색한다.
		String view = null;
		if(!viewName.contains(".do")) {
			view = viewResolver.getView(viewName);
		} else {
			view = viewName;
		}
		
		response.sendRedirect(view);
		
	}

}
Comments