본문 바로가기

JSP/JSP Programming

[JSP] 서블릿 사용자의 요청을 명령어로 전달

반응형

■ 서블릿 사용자의 요청을 명령어로 전달

 -. 모델 2 기반의 MVC 패턴에서 컨트롤러의 역할을 하는 서블릿은 사용자가 어떤 요청을 했는지 분석해야 한다.

    즉, 사용자가 어떤 페이지를 요청하였는지 구분할 수 있어야 이에 알맞은 모델의 기능을 수행할 수 있게 된다.

 -. MVC 패턴에서 컨트롤러는 사용자가 어떤 요청을 했는지를 명령어를 사용하여 파악한다.

 -. 웹 브라우저를 통해서 명령어를 전달하기 위한 방법은 2가지로 구분된다.

  ① 요청 파라미터로 명령어를 전달하는 방법

  ② 요청 URI 자체를 명령어로 사용하는 방법


01. 요청 파라미터로 명령어를 전달하는 방법

 01) 특정한 이름의 파라미터에 명령어 정보를 담아서 전달

 -. 요청 파라미터로 명령어를 전달하는 방법은 특정한 이름의 파라미터에 명령어 정보를 담아서 전달하는 것이다.


 CommandController01.java
packge ch21.controller;

import java.io.IOException;

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

public class CommandController01 extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       
        proRequest(request, response);
    }

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

    protected void proRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       
        // Request 객체로부터 사용자의 요청을 파악하는 코드
        String cmd = request.getParameter("cmd");       
        String view = null;
       
        // 사용자의 요청에 따른 알맞은 작업을 처리하는 코드
        if(cmd.equals("list")) {
           
            request.setAttribute("message", "글목록 보기");    // 글 목록 보기 작업 수행
            view = "/ch21/list.jsp";
        }
       
        else if(cmd.equals("write")) {
           
            request.setAttribute("message", "글 쓰기");        // 글 쓰기 수행
            view = "/ch21/write.jsp";
        }
       
        RequestDispatcher dispatcher = request.getRequestDispatcher(view);
        dispatcher.forward(request, response);
    }
}
 설명

 -. 파라미터의 이름을 cmd로 하여 명령어를 전달한 것이다.(파라미터 이름은 다른 이름을 사용하여도 상관없다.)

 -. 컨트롤러 역할을 하는 서블릿의 이름을 CommandController01 라고 한다면 파라미터 cmd에 저장된 값에 따라 해당 명령어를 수행하도록 한다.

 list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>글 목록</title>
</head>
<body>
<%-- message 속성의 값을 msg 변수에 저장한다.--%>
<c:set var = "msg" value = "${message}" />

<%-- msg 변수의 내용을 화면에 출력한다. --%>
<c:out value = "${msg}" />
</body>
</html>

 write.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix = "c" uri = "http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>글 목록</title>
</head>
<body>
<%-- message 속성의 값을 msg 변수에 저장한다.--%>
<c:set var = "msg" value = "${message}" />

<%-- msg 변수의 내용을 화면에 출력한다. --%>
<c:out value = "${msg}" />
</body>
</html>

 력결과①

 력결과②




 02) 커맨드(Command) 패턴으로 작업

  -. 각 명령어에 따른 로직 처리 코드를 별도의 클래스로 작성하는 커맨드(Command) 패턴으로 작업을 처리할 수 있다.

  -. 커맨드 패턴으로 명령어를 처리하기 위해서는 명령 처리 클래스가 있어야 하는데 이는 요청 파라미터를

     동일한 메소드로 처리하도록 하기 위해서 인터페이스를 슈퍼 클래스로 갖도록 한다.

       


 -. 다음은 명령 처리 클래스의 슈퍼 클래스로 사용할 인터페이스를 정의한 문장이다.

  CommandAction.java

package ch21.controller;

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

public interface CommandAction {

    public String proRequest(HttpServletRequest request, HttpServletResponse response) throws Throwable;
}

 ListAction.java

package ch21.controller;

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

public class ListAction implements CommandAction {

    public String proRequest(HttpServletRequest request, HttpServletResponse response) throws Throwable {
       
        request.setAttribute("message", "글 목록 보기");


        // ListAction 명령 처리 객체는 뷰 페이지로 "/ch21/list.jsp"를 리턴하고 있다.
        return "/ch21/list.jsp";
    }
}

 WriteAction.java

package ch21.controller;

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

public class WriteAction implements CommandAction {

    public String proRequest(HttpServletRequest request, HttpServletResponse response) throws Throwable {
       
        request.setAttribute("message", "글 목록 보기");
       
        // WriteAction 명령 처리 객체는 뷰 페이지로 "/ch21/write.jsp"를 리턴하고 있다.
        return "/ch21/write.jsp";
    }
}

 CommandController02.java

package ch21.controller;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CommandController02 extends HttpServlet {

    // 명령어와 명령 처리 클래스를 쌍으로 저장할 HashMap 객체를 생성한다.
    private Map commandMap = new HashMap();

    // init 메소드는 서블릿이 실행될 때 가장 먼저 단 한번 자동으로 실행된느 메소드이다.
    // init 메소드에서는 명령어와 명령 처리 핸들러의 인터페이스를 HashMap인 commandMap에 키와 값으로 매핑해 둔다.
    public void init(ServletConfig config) throws ServletException {
   
        Object handlerInstance;
        String command;
       
        // list란 명령어를 키로 ListAction 명령 처리 핸들러 인터페이스를 값으로 해쉬맵에 저장한다.
        command = "list";
        handlerInstance = new ListAction();
        commandMap.put(command, handlerInstance);
       
        // write란 명령어를 키로 WriteAction 명령 처리 핸들러 인터페이스를 값으로 해쉬맵에 저장한다.
        command = "write";
        handlerInstance = new WriteAction();
        commandMap.put(command, handlerInstance);
    }

   
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       
        proRequest(request, response);
    }

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

    protected void proRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       
        // 사용자의 요청을 분석한다. 즉 "..CommandController02?cmd=list"와 같이

        // cmd란 쿼리스트링에 list란 값이 저장되어 있다면 cmd 변수에 list를 저장해 둔다.
        String cmd = request.getParameter("cmd");
        String view = null;
       
        CommandAction com = null;
       
        try {
           
            // 문자열 변수 cmd에 저장된 값을 키로 하여 해쉬 맵에서 이에 해당되는 값을 얻어온다.
            // 즉 cmd에 저장된 값이 "list"이면 ListAction 명령 처리 핸들러 레퍼런스가 얻어진다.
            // CommandAction 인터페이스로 선언된 레퍼런스인 com에 저장한다.
            com = (CommandAction) commandMap.get(cmd);
           
            // 해쉬 맵에서 얻어온 명령 처리 핸들러로 proRequest 메소드를 호출한다.
            // 만일 com에 ListAtion 레퍼런스 값이 저장되어 있다면 이 메소드 내에 기술된 비즈니스 로직이 수행된 후
            // 리턴값인 "ch21/list.jsp"가 view에 저장된 값은 proRequest 메소드의 리턴값은 포워딩될 JSP 페이지다.
            view = com.proRequest(request, response);
        }
       
        catch(Throwable e) {
           
            e.printStackTrace();
        }
       
        // 해당 뷰로 포워딩 하기 위해서 RequestDispatcher 객체를 생성하여 포워딩 한다.
        RequestDispatcher dispatcher = request.getRequestDispatcher(view);
        dispatcher.forward(request, response);
    }
}

 력결과①

 력결과②



 03) 설정 파일 명령어 정보를 담아서 전달

  ① 설정파일에 명령어와 클래스의 관계 명시하기

   -. CommandController02 컨트롤러 서블릿은 명령어와 명령 처리 클래스를 요청이 있을 때 직접 매핑해 주었지만,

      일반적으로 명령어에 따라 처리할 서블릿 클래스가 달라질 수 있도록 하기 위해서 따로 설정 파일을 작성한다.

   -. WEB_INF 폴더에 파일명을 Command.properties로 하여 명령어와 이에 대응하는 명령어처리 클래스를 매핑시킨다.

  Command.properties

 list = ch21.controller.ListAction
 write = ch21.controller.WriteAction

    -. <명령어, 명령어 처리 클래스>와 같은 매핑 구조로 설정 파일에 저장해 두면 새로운 명령어가 추가될 경우 명령어와

       이를 처리할 명령어 핸들러 클래스를 설정 파일에 추가만 시키면 되므로 쉽게 매핑시킬 수 있다는 장점이 있다.


  ② 설정 파일의 정보를 web.xml 파일에 저장하기

    -. Command.properties 파일을 컨트롤러인 CommandController에서 읽어올 수 있도록 설정 파일의 정보를 web.xml 파일에 기록한다.

    -. web.xml 파일에 아래의 문장을 추가해야 한다. 이때 주의할 점은 반드시 이 문장이

       <web_app> 태그 바로 다음에 제일 먼저 나와야 한다는 점이다.

 web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xmlns="http://java.sun.com/xml/ns/javaee"

  xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"

  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

  http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">


<!-- 요청 파라미터로 명령어를 전달하는 방법 -->

  <!-- <servlet> 태그는 서블릿의 설정 정보를 처리할 수 있도록 한다. -->

  <servlet>
      <!-- <servlet-name> 태그에는 서블릿명을 기술한다. -->
      <!-- 이 태그를 사용하면 해당 서블릿이 ch21.controller.CommandController에 위치하더라도 -->
      <!-- http://localhost:8181/ch21/servlet/ch21.controller.CommandController 대신 -->
      <!-- http://localhost:8181/ch21/servlet/CommandController로 기술할 수 있다. -->
      <servlet-name>CommandController</servlet-name>
      <!-- <servlet-class> 태그에는 실제 서블릿 경로를 기술해 준다. -->
      <servlet-class>ch21.controller.CommandController</servlet-class>
      <!-- <init-param> 태그는 initial parameter를 설정한느 부분으로 -->
      <!-- 이 태그는 config.getInitParameter("configFile") 메소드를 통해 -->

     <!-- 파라미터의 이름을 읽어들여 파라미터의 값을 얻어낸다. -->
      <init-param>
          <!-- <param-name> 태그에는 config.getInitParameter 메소드의 전달인자로 -->

        <!-- 사용할 파라미터의 이름을 기술한다. -->
          <param-name>configFile</param-name>
          <!-- <param-value>는 설정 파일인 Command.properties 파일의 경로명을 기술한다. -->
          <param-value>C:\Workspace\ch21\WebContent\WEB-INF\Command.properties</param-value>
      </init-param>
  </servlet>


  ~~~~~~~~


</web-app>


  ③ 컨트롤러 서블릿 작성하기

   -. 컨트롤러 서블릿은 명령어와 이를 처리할 클래스가 매핑되어 있는 properties 파일에서 읽어 온다.

   -. 명령어와 명령 처리 클래스를 읽어와서 명령 처리 클래스로 인스턴스를 생성하여

      HashMap 객체에 명령어를 키로 명령 처리 인스턴스에 대한 레퍼런스를 값으로 저장해 둔다.

   -. proRequest 메소드에서 명령어에 따른 명령 처리 인스턴스를 접근해서 해당 비즈니스 로직을 수행한 후

      뷰 페이지를 알아내서 해당 페이지로 포워딩 한다.

CommandController.java

package ch21.controller;

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.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CommandController extends HttpServlet {
   
    // 명령어와 명령 처리 클래스를 쌍으로 저장할 해쉬 맵 객체 생성
    private Map commandMap = new HashMap();
   
    public void init(ServletConfig config) throws ServletException {
       
        // web.xml 파일의 configFile 태그의 초기화 파라미터(init-param)로 부터
        // 매핑정보를 저장하고 있는 설정 파일(Command.properties)의 경로를 구한다.
        String configFile = config.getInitParameter("configFile");
       
        if(configFile == null) {
           
            configFile = "C:/Workspace/ch21/WebContent/WEB-INF/Command.properties";
        }
       
        // 명령어와 이를 처리할 클래스의 매핑 정보를 저장할 Properties 객체 생성
        Properties prop = new Properties();
        FileInputStream fis = null;
       
        try {
           
            // 설정 파일(Command.properties)로 부터 파일 내용(매핑 정보)을 읽어온다.
            fis = new FileInputStream(configFile);
           
            // Command.properties 파일의 정보를 Properties 객체에 저장
            prop.load(fis);
        }
       
        catch(IOException e) {
           
            throw new ServletException(e);
        }
       
        finally {
           
            if(fis != null) {
               
                try {
                   
                    fis.close();
                }
               
                catch(IOException e) {
                   
                    e.printStackTrace();
                }
            }
        }
       
        // Properties 객체에서 키값들을 Set으로 얻어와서 iterator 메소드를 호출한다.
        Iterator keyIter = prop.keySet().iterator();
       

        // Iterator 객체로 다음 명령어가 있는지 판단해서 있다면 명령어를 얻어옴
        while(keyIter.hasNext()) {   
           
            String command = (String)keyIter.next();
           
            // 해당 명령어랑 매핑된 클래스 이름을 문자열 형태로 얻어옴
            String className = prop.getProperty(command);
           
            try {
               
                // 클래스의 이름이 문자열 형식이므로 이에 해당되는 클래스 생성
                Class handlerClass = Class.forName(className);
               
                // 해당 클래스로 객체 생성
                Object handlerInstance = handlerClass.newInstance();
               
                // <명령어, 핸들러 인스턴스>의 매핑정보를 해쉬맵에 저장한다.
                commandMap.put(command, handlerInstance);
            }
           
            catch(ClassNotFoundException e) {
               
                throw new ServletException(e);
            }
           
            catch(InstantiationException e) {
               
                throw new ServletException(e);
            }
           
            catch(IllegalAccessException e) {
               
                throw new ServletException(e);
            }
        }
    }
   
    // GET 방식으로 요청을 받음 : proRequest 메소드로 전달
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       
        proRequest(request, response);
    }
   
    // GET 방식으로 요청을 받음 : proRequest 메소드로 전달
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       
        proRequest(request, response);
    }
   
    protected void proRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       
        // Request 객체로부터 사용자의 요청을 파악하는 코드
        String cmd = request.getParameter("cmd");
        CommandAction com = null;
       
        // 사용자의 요청에 따른 알맞은 작업을 처리하는 코드
        String view = null;
       
        try {
           
            // 사용자의 요청인 명령어가 저장된 cmd 변수로 이에 해당되는 명령 처리
            com = (CommandAction) commandMap.get(cmd);
           
            // 인스턴스의 레퍼런스 값을 얻어와서 해당 명령처리 클래스의 proRequest 메소드를 수행 후
            // 포워딩 할 JSP 페이지를 리턴값으로 얻어와 view에 저장한다.
            view = com.proRequest(request, response);
        }
       
        catch(Throwable e) {
           
            throw new ServletException(e);
        }
       
        // RequestDispatcher를 사용하여 알맞은 뷰(JSP 페이지)로 포워딩
        RequestDispatcher dispatcher = request.getRequestDispatcher(view);
        dispatcher.forward(request, response);
    }
}

 력결과①

 력결과②


반응형