https://tavi.tistory.com/50?category=1086720
MVC 패턴 정의
0. 모델 1 구조 모델 1 구조는 JSP를 이용한 단순한 모델이다. (기존에 했던 모든 것들..) JSP에서 요청 처리 및 뷰 생성을 처리해서 구현이 쉽지만 요청 처리 및 뷰 생성 코드가 뒤섞여 코드가 복잡
tavi.tistory.com
컨트롤러가 알맞은 로직을 수행하려면 클라이언트가 어떤 기능을 요청하는 지 구분할 수 있어야 하는데
웹 브라우저를 통해 명령어를 전달하는 방법에는 두 가지가 있다.
- 특정 이름의 파라미터에 명령어 정보를 전달 (ex. url에 ?type=date 를 입력)
- 요청 URI 자체를 명령어로 사용
특정 파라미터에 명령어 정보를 전달하는 방법은 컨트롤러 서블릿이 명렁어에 알맞은 로직 코드를 실행한 후 결과를 보여줄 뷰로 이동 해야 한다. 이때 명령어와 관련된 로직의 처리를 컨트롤러 서블릿에서 모두 다 처리 하게 되는데 컨트롤러 서블릿의 코드가 복잡해진다는 단점이 있다.
이런 복잡함을 줄일 수 있는 방법으로 커맨드 패턴을 사용한다.
💡. 커맨드 패턴을 이용한 요청 처리
커맨드 패턴이란 클라이언트의 각 요청을 처리하는 별도 클래스를 제공하는 구현 패턴을 말한다.
하나의 명령어를 하나의 클래스가 처리하게 된다.
명령어를 처리하는 클래스들은 공통의 부모 클래스를 상속 받거나 공통의 인터페이스를 구현하도록 함으로써 동일한 메소드로 실행될 수 있게 된다.

🎈.커맨드 패턴을 이용한 명령어 처리 분리 예제
1. 공통 인터페이스
package mvc.command;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface CommandHandler {
//추상 메소드
public String process(HttpServletRequest request, HttpServletResponse response)
throws Throwable;
}
2. 명령어를 처리하는 핸들러 클래스
(1)
package mvc.command;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloHandler implements CommandHandler {
@Override
public String process(HttpServletRequest request, HttpServletResponse response)
throws Throwable {
//1. 뷰 페이지에서 요청 처리 결과를 보여주기 위해 사용할 정보 저장
request.setAttribute("hello", "안녕하세요!");
//2. 처리 결과를 보여줄 뷰 페이지의 URI 리턴
return "/view/hello.jsp";
}
}
(2)
package mvc.command;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class NullHandler implements CommandHandler {
@Override
public String process(HttpServletRequest request, HttpServletResponse response)
throws Throwable {
return "/view/nullCommand.jsp";
}
}
3. 매핑 정보 설정 파일 작성
(1) 명령어 매핑 정보 properties 파일 ('명렁어=핸들러 클래스의 이름(패키지명 포함)' 의 형태)
hello=mvc.command.HelloHandler
▲ commandHandler.properties
명령어 'hello'를 처리하는 mvc.command.HelloHandler 클래스
(2) web.xml 파일에 서블릿 설정 추가
<servlet>
<servlet-name>ControllerUsingFile</servlet-name>
<servlet-class>mvc.controller.ControllerUsingFile</servlet-class>
<init-param>
<param-name>configFile</param-name>
<param-value>/WEB-INF/commandHandler.properties</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ControllerUsingFile</servlet-name>
<url-pattern>/controllerUsingFile</url-pattern>
</servlet-mapping>
- configFile이란 이름으로 /WEB-INF/commandHandler.properties 파일로부터 설정 정보를 읽어옴
4. 컨트롤러 서블릿
컨트롤러 서블릿에서 설정 파일을 읽어오기 가장 좋은 위치는 init() 메소드인데 init() 메소드는 서블릿을 생성한 후 초기화 할 때 호출되는 메소드이다.
package mvc.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;
import mvc.command.CommandHandler;
import mvc.command.NullHandler;
//커맨드 패턴 구현 - 컨트롤러 서블릿
//process 메소드가 있는 컨트롤러 서블릿
public class ControllerUsingFile extends HttpServlet {
//매핑 정보 저장 <커맨드, 핸들러인스턴스>
private Map<String, Object> commandHandlerMap = new HashMap<String, Object>();
//설정 파일을 읽어오는 init() 메소드
public void init(ServletConfig config) throws ServletException {
//web.xml에 저장한 configFile 초기화 파라미터로부터 설정 파일의 경로 구함
String configFile = config.getInitParameter("configFile");
Properties prop = new Properties();
FileInputStream fis = null;
//설정 파일로부터 매핑 정보를 읽어와 Properties 객체에 저장
try {
//받아온 상대경로를 절대 경로로 바꿔줌
String configFilePath = config.getServletContext().getRealPath(configFile);
fis = new FileInputStream(configFilePath);
prop.load(fis); //프로퍼티스 로딩
} catch (IOException e) {
throw new ServletException(e);
} finally {
if(fis != null)
try {
fis.close();
} catch (IOException e2) {}
}
//Iterator 객체 생성
Iterator keyIter = prop.keySet().iterator(); //키값 받아옴
//반복
while (keyIter.hasNext()) {
String command = (String) keyIter.next();
String handlerClassName = prop.getProperty(command);
try {
//문자열을 클래스로 변환
Class handlerClass = Class.forName(handlerClassName);
Object handlerInstance = handlerClass.newInstance();
commandHandlerMap.put(command, handlerInstance);
} catch (ClassNotFoundException e) {
throw new ServletException(e);
} catch (InstantiationException e) {
throw new ServletException(e);
} catch (IllegalAccessException e) {
throw new ServletException(e);
}
}
}
//메소드 오버라이드1
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
process(request, response);
}
//메소드 오버라이드2
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
process(request, response);
}
//인터페이스의 process 메소드 사용
public void process(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//"cmd" 파라미터를 이용해 클라이언트가 요청한 기능 구함
String command = request.getParameter("cmd");
//요청에 사용될 핸들러 인스턴스를 commandHandlerMap으로부터 구함
CommandHandler handler = (CommandHandler) commandHandlerMap.get(command);
if(handler == null) {
handler = new NullHandler();
}
String viewPage = null;
try {
//구한 핸들러 인스턴스의 process메소드를 호출해 요청을 처리
viewPage = handler.process(request, response);
} catch (Throwable e) {
throw new ServletException(e);
}
//파라미터 정보 유지를 위한 RequestDispatcher
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPage);
dispatcher.forward(request, response);
}
}
5. 뷰 역할의 JSP 작성
(1) /view/hello.jsp
<%@ page language="java" contentType="text/html; charset=EUC-KR" %>
<html>
<head>
<title>Hello</title>
</head>
<body>
<%= request.getAttribute("hello") %>
</body>
</html>
(2) /view/nullCommand.jsp
<%@ page language="java" contentType="text/html; charset=EUC-KR" %>
<html>
<head>
<title>에러</title>
</head>
<body>
잘못된 요청입니다.
</body>
</html>
6. 실행 결과



'Dev > Java' 카테고리의 다른 글
MVC - 커맨드 패턴을 이용한 요청 URI를 명령어로 사용하기 (0) | 2022.10.11 |
---|---|
MVC 게시판 구현 메모 (0) | 2022.10.05 |
MVC 패턴 정의 (0) | 2022.10.04 |
Tiles를 이용한 컴포지트 뷰 구현 (1) | 2022.09.30 |
synchronized 동기화 메소드와 동기화 블록 (1) | 2022.09.29 |
댓글