본문 바로가기

청년취업아카데미/DayLog

[ JSP ] Day 14 - ② MVC 2 패턴으로 개발하기

# Project Structure

더보기
Project Example
  • MVC 스타일의 이해를 돕기 위한 프로젝트구조이다.
  • 자바 소스에는 Controller와 Model을 구현하는 control, dao, service 패키지가 있고, WebContent 아래에는 View를 구현하는 jsp 파일이 있다.

 

MVC 2 패턴은 크게 Model, View, Controller로 구성됩니다. Model과 Controller자바 프로그램으로 구성되고, JSP 파일로 구성됩니다.

 

MVC 패턴과 JSP 모델 2 구조의 매핑

  • 컨트롤러(Controller) = 서블릿 = control 패키지
  • 모델(Model) = 로직 처리 클래스, 자바빈 = dao, service 패키지
  • 뷰(View) = JSP = WebContent/*.jsp
  • 사용자(User) = 웹 브라우저 내지 휴대폰과 같은 기기

 


# 컨트롤러와 모델의 흐름

  • 과정1 : 웹 브라우저가 전송한 HTTP 요청을 받는다. 서블릿의 doGet() 메소드나 doPost() 메소드가 호출된다.
  • 과정2 : 웹 브라우저가 어떤 기능을 요청했는지 분석한다. 예를 들어, 게시판 목록을 요청했는지, 글쓰기를 요청했는지 알아낸다.
  • 과정3 : 모델을 사용하여 요청한 기능을 수행한다.
    • 모델에서 처리
      • 과정4 : 컨트롤러의 요청을 받아 비즈니스 로직을 수행한다.
      • 과정5 : request나 session의 setAttribute() 메소드를 사용하여 결과 값을 속성에 저장한다. (저장된 결과 값은 뷰인 JSP에서 사용한다) 또한 사용될 뷰(jsp)를 리턴한다.

 

  • 과정6 : 웹 브라우저에 결과를 전송할 JSP를 선택한 후, 해당 JSP로 포워딩한다. 경우에 따라 리다이렉트를 하기도 한다.

 


# Open Source Controller

  • Controller Source Code and Description
더보기

control 패키지의 Controller입니다. 아래의 소스는 Controller의 유명한 오픈소스로 알려져 있다고 합니다. Controller를 정의하기 전에, 로직을 처리를 정의하기 위해 인터페이스를 만듭니다.

  • service.CommandProcess
package service;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface CommandProcess{
	public String requestPro(HttpServletRequest request, HttpServletResponse response) 
    	throws ServletException, IOException;
}

CommandProcess 인터페이스를 통해 명령어 비지니스 로직 처리 메소드(requestPro)를 정의합니다.

 

  • control.Controller
package control;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import service.CommandProcess;

/**
 * Controller : Service(Command) --> Business Logic
 */
@WebServlet("/Controller")
public class Controller extends HttpServlet{
	private static final long serialVersionUID = 1L;
	private Map<String, Object> commandMap = new HashMap<String, Object>();

	public Controller(){ super(); }

	public void init(ServletConfig config) throws ServletException {
		// web.xml에서 propertyConfig에 해당하는 init-param의 값을 읽어옴.
		String props = config.getInitParameter("config");
		// 명령어와 처리클래스의 매핑정보를 저장할 Properties 객체 생성
		Properties pr = new Properties();
		FileInputStream f = null;
		try {
			String configFilePath = config.getServletContext().getRealPath(props);
			f = new FileInputStream(configFilePath);
			// command.properties 파일의 정보를 Properties 객체에 저장
			pr.load(f);
		} catch (IOException e) {
			throw new ServletException(e);
		} finally {
			if (f != null) try { f.close(); } catch (IOException e) { }
		}
		//Iterator 객체는 Enumeration 객체를 확장시킨 개념의 객체
		Iterator keyIter = pr.keySet().iterator();
		//객체를 하나씩 꺼내서 그 객체명으로 Properties 객체에 저장된 객체에 접근
		while(keyIter.hasNext()) {
			String command = (String)keyIter.next();
			String className = pr.getProperty(command);
			try {
				Class commandClass  = Class.forName(className);//해당 문자열을 클래스로 만든다.
				Object commandInstance = commandClass.newInstance(); //해당 클래스의 객체를 생성
				commandMap.put(command, commandInstance); // Map 객체인 commandMap에 객체 저장
			} catch(Exception e) {
				throw new ServletException();
			}
		}
	}
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		requestPro(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		requestPro(request, response);
	}

	// CommandProcess 인터페이스의 메소드 requestPro(request, response): 사용자의 요청을 분석해서 해당 작업을 처리한다.
	public void requestPro(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String view = null;
		CommandProcess com = null;
		try {
			String command = request.getRequestURI();
			System.out.println(command);
			
			command = command.substring(request.getContextPath().length()); // real path만큼 자름.
			
			com = (CommandProcess)commandMap.get(command);
			System.out.println("command --> "+command);
			System.out.println("com --> "+com);
			
			// view로 이동함.
			view = com.requestPro(request, response);
			System.out.println("view --> "+view);
		}catch(Throwable e) {throw new ServletException(e);}
		RequestDispatcher dispatcher = request.getRequestDispatcher(view);
		dispatcher.forward(request, response);
	}
}

Controller의 init()메소드에서는 설정 파일로 부터 받아온 설정 정보를 저장하고, Properties 객체를 생성하여 command.properties의 파일의 Properties 정보를 저장한다. (command.properties 파일은 명령어와 명령어 처리 클래스를 매핑한 파일이다.)

  • 아래의 코드는 command.properties의 예제를 보여줍니다. ip주소/list.do를 입력하면 listAction이 수행됩니다. 
/list.do = service.ListAction

 

  • 아래의 코드는 Controller 코드의 일부입니다. 이 코드(Class와 Object 처리)를 통해 우리는 Controller 소스 코드를 직접 수정하지 않고, command.properties에 추가함으로써, 명령어와 처리 클래스를 연결할 수 있습니다.
Class commandClass  = Class.forName(className);//해당 문자열을 클래스로 만든다.
Object commandInstance = commandClass.newInstance(); //해당 클래스의 객체를 생성
commandMap.put(command, commandInstance); // Map 객체인 commandMap에 객체 저장

 

  • 우리는 소스파일의 doGet(request, response)doPost(request, response) 메소드에서 처리를 requestPro(request, response)로 넘겨주는 것을 볼 수 있습니다.
    • requestPro에서는 명령을 받아 명령을 분석하고, 명령을 처리할 객체를 생성하여 그 객체를 통해 view를 반환 받는 것을 볼 수 있습니다.
	public void requestPro(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String view = null;
		CommandProcess com = null;
		try {
			String command = request.getRequestURI();
			System.out.println(command);
			
			command = command.substring(request.getContextPath().length()); // real path만큼 자름.
			
			com = (CommandProcess)commandMap.get(command);
			System.out.println("command --> "+command);
			System.out.println("com --> "+com);
			
			// view로 이동함.
			view = com.requestPro(request, response);
			System.out.println("view --> "+view);
		}catch(Throwable e) {throw new ServletException(e);}
		RequestDispatcher dispatcher = request.getRequestDispatcher(view);
		dispatcher.forward(request, response);
	}

# 개발 순서

  1. [Dynamic Web Project] 생성하기
  2. DBMS를 이용해 사용할 데이터베이스 생성
  3. Project의 패키지 나누기(control, dao, service)
    • control은 Controller를 위한 패키지
    • dao와 service는 Model을 위한 패키지
  4. dao 패키지에 DAO와 DTO 클래스 정의하기
    • 생성한 데이터베이스의 형식에 맞는 dto 객체 만들기
    • DBCP를 이용한 DB연결을 위해 WebContent의 META-INF 폴더 아래 context.xml 에 디비 정보 구현
    • dao 객체에는 부가 기능을 제외한 DBCP를 이용하여 데이터베이스 연결 수행
  5. service 패키지에서 명령처리를 위한 인터페이스 생성
    • CommandProcess - requestPro 메소드 
  6. command.properties에 명령어와 명령 처리 클래스 정의
    • ex) /list.do = service.ListAction
  7. control 패키지의 Controller 클래스 정의하기
    • init(config) 메소드에서 WebContent/WEB-INF/command.properties에 설정된 명령어와 명령처리 클래스를 받아와서 명령어에 따른 명령 처리 클래스의 객체를 생성함.
    • requestPro 메소드를 정의하여 명령 받은 것을 분석하고 명령에 따른 명령처리 클래스를 실행하여 받은 view와 request 속성을 view로 포워딩한다.
  8. service의 Action 클래스 정의하기. (ListAction)
    • CommandProcess를 상속받아 requestPro 메소드를 오버라이딩한다.
    • requestPro 메소드에서 request의 속성을 설정하고 페이징 처리를 하고, list.jsp를 반환한다.
  9. WebContent에 jsp 파일(view) 생성하여 기술. (list.jsp)
    • 이때, Action 클래스에서 request나 session을 통해 받은 속성을 이용하여 기술한다.
    •  index.jsp에 메인화면에 등록할 페이지로 이동시키는 코드를 작성한다.
      • <script>location.href="list.do"</script>
      • 하지만 우리는 list.do로 list.jsp로 이동할 수 없으니, 반드시 web.xml의 설정파일에 기술해줘야한다.
  10. Web.xml 파일 설정
    1. web.xml 파일은 Tomcat의 실행환경에 대한 정보를 담당하는 환경설정 파일로, 각종 servlet의 설정과 servlet 매핑, 필터, 인코딩 등을 담당한다. 
    2. web.xml 파일에 서블릿 파일인 Controller와 위치를 등록하고, config파일과 위치를 등록한다. 또한 servlet 파일이 실행될 url 확장자과 Controller를 매핑하는 코드를 작성해준다.
  • web.xml 파일
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>och16</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  
  <servlet>
  	<servlet-name>Controller</servlet-name>
  	<servlet-class>control.Controller</servlet-class>
	<init-param>
		<param-name>config</param-name>
		<param-value>/WEB-INF/command.properties</param-value>
	</init-param>
  </servlet>
  
  <servlet-mapping>
  	<servlet-name>Controller</servlet-name>
  	<url-pattern>*.do</url-pattern>
  </servlet-mapping>
</web-app>

 


[ References ]

  1. 최범균의 JSP2.3 웹 프로그래밍 기초부터 중급까지, 최범균, 가메출판사

 

- 이 포스팅은 청년취업 아카데미 [JAVA Framework 실무 개발자 단기 과정]에서 들은 내용을 바탕으로 기술되었습니다. -