Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- Oracle
- forward
- map
- 그레이들
- set
- 실기
- forTokens
- 1회
- DB
- servlet
- c:out
- JSTL
- param
- IT
- 스프링
- 프레임워크
- el표기법
- jsp
- 웹개발자
- 개발자
- Java
- 리액트
- 정보처리기사
- 2021년
- spring
- 프로젝트
- sql
- List
- sendRedirect
- MVC
Archives
- Today
- Total
룽쓰의 개발도구
MVC 모델을 구현하자 part1 본문
지금 적어두지 않으면 많은 것을 잊어먹을 것 같아서 두서없이 적으려고 한다.
적으면서 기억하자.
[ A. ControllerUsingURI.java ]
package mvc.controller;
import java.io.FileReader;
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.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import mvc.command.CommandHandler;
import mvc.command.NullHandler;
// 클래스 안에서 서블릿의 내용을 사용하기 위해서 상속받았다.
public class ControllerUsingURI extends HttpServlet{
// 1. 가장 많이 사용하는 것이 Map계열이다. Map은 키와 밸류를 설정할 수 있다.
// key는 String으로 두고 value는 인터페이스로 넣었다. 변수는 commandHandlerMap을 설정했다.
private Map<String, CommandHandler> commandHandlerMap = new HashMap<>();
// 이 클래스 안에서만 사용할 수 있는 commandHandlerMap을 사용할 것이다.
// 2. init()이름을 가진 메서드를 구현했다.
public void init() throws ServletException{
// 3. web.xml에 설정해둔 init param인 configFile을 들고온다.
// configFile의 값으로는 /WEB-INF/commandHandler.properties가 있다.
// 즉, 그 안의 값인 키와 밸류 값을 configFile 변수에 다 넣게 됐다.
String configFile = getInitParameter("configFile");
// 새로운 프로퍼티 객체를 만들었다.
Properties prop = new Properties();
// 4. getServletContext()에서 getRealPath를 사용한 것을 볼 수 있는데, 이는 서블릿의 가상 디렉토리 상에서 실제 경로를 읽어오는 것을 말한다.
// 즉, configFile에는 /WEB-INF/commandHandler.properties 주소 값이 저장되어있기 때문에 그것을 불러와서 configFilePath에 집어넣는 것이다.
String configFilePath = getServletContext().getRealPath(configFile);
// 5. 특정 경로에 있는 파일을 읽어올 수 있는 FileReader를 사용해서 configFilePath에 있는 파일을 fis에 담았다.
try(FileReader fis = new FileReader(configFilePath)){
// 6. 프로퍼티스 확장자기 때문에, 위에서 만든 properties의 prop로 load했다.
prop.load(fis);
}catch(IOException e) {
throw new ServletException(e);
}
// 7. prop로 불러온 properties파일 안에 있는 key를 반복자(Iterator) keyIter에 삽입했다.
Iterator keyIter = prop.keySet().iterator();
// 8. 반복문을 출력할 수 있는 while문을 만들었고, keyIter의 다음 값이 있으면 참으로 진행하도록 했다.
while(keyIter.hasNext()) {
// 만약 다음 key값이 있어서 참값이라면, 그 키를 받아서 command에 넣을 것이다.
String command = (String) keyIter.next();
// 그 키를 다시 prop.getProperty("키")에 넣어서 키와 쌍으로 이루는 값을 handlerClassName에 입력했다.
String handlerClassName = prop.getProperty(command);
// 현재 불러온 properties의 내용
// /hello.do = mvc.hello.HelloHandler
// 즉, hello.do는 키값으로 command에 입력됐고, handlerClassName에는 mvc.hello.HelloHandler가 입력됐다.
try {
// 9. mvc.hello.HelloHandler이 위치에 이 클래스가 있으면 handlerClass에 입력한다는 문구를 넣었다.
Class<?> handlerClass = Class.forName(handlerClassName);
// 10. CommandHandler 인터페이스를 이용해서 받아온 handlerClass를 구현했다.
// 여기서 handlerClass는 CommandHandler 인터페이스를 구현시킨 클래스라서 가능하다.
CommandHandler handlerInstance = (CommandHandler)handlerClass.newInstance();
// 11. 1번에서 만들었던 Map계열의 commandHandlerMap<String, CommandHandler>에 key인 command와 class인 handlerInstance를 입력했다.
commandHandlerMap.put(command, handlerInstance);
}catch(ClassNotFoundException | InstantiationException | IllegalAccessException e) {
throw new ServletException(e);
}
}
}
// 즉, 위의 메소드에서 할 수 있는 것은 기존에는 주소 끝에 page=1이런 식으로 하드코딩된 상태를 주소창에 보여줘야 했었지만,
// 위와 같이 설계함으로써 내가 properties파일에 입력해둔 키와 밸류에 따라서 간편하게 사용자들이 들어올 수 있는 것을 알 수 잇다.
위 코드에서 initparam을 불러왔는데 그 내용을 살펴보자
[ B. 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_4_0.xsd" id="WebApp_ID" version="4.0">
<display-name>Ch18_MVC</display-name>
<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>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ControllerUsingFile</servlet-name>
<url-pattern>/controllerUsingFile</url-pattern>
</servlet-mapping>
<!-- <servlet>
<servlet-name>SimpleController</servlet-name>
<servlet-class>mvc.simple.SimpleController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>SimpleController</servlet-name>
<url-pattern>/simple</url-pattern>
</servlet-mapping> -->
<servlet>
<servlet-name>ControllerUsingURI</servlet-name>
<servlet-class>mvc.controller.ControllerUsingURI</servlet-class>
<init-param>
<param-name>configFile</param-name>
<param-value>/WEB-INF/commandHandlerURI.properties</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ControllerUsingURI</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
[ C. A의 추가 부분 ]
// 1. GET, POST방식 둘다 process 메서드를 실행하도록 했다.
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
process(request,response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
process(request,response);
}
private void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// String command = request.getParameter("cmd");
// 원래는 이렇게 파라미터 값을 받아서 사용했는데 이제 그러지 않을 예정이다.
// 1. getRequestURI로 현재 위치한 주소값을 받아서 command 변수에 넣었다.
String command = request.getRequestURI();
// 현재 command의 값을 출력하면 /Ch18_MVC/*.do가 나오게 된다.
// 커맨드라는 String의 index값이 어떻게 되냐?
// request.getContextPath가 의미하는 것은 => /Ch18_MVC를 의미한다.
// 여기서 indexOf란 command에서 getContextPath()가 처음으로 발견되는 위치의 index를 반환하게 된다.
// 즉, command는 /Ch18_MVC/*.do이고, getContextPath()는 /Ch18_MVC이라서 == 0은 참이 된다.
if(command.indexOf(request.getContextPath())== 0) {
// substring은 괄호 안에 들어간 문자열 위치부터 끝까지 문자열을 잘라 내는 것이다.
// 즉, getContextPath()는 /Ch18_MVC인데, 이것의 length를 구했기 때문에 9이고, command에서 9번째의 뒤에서부터 시작이면 /*.do결과 값이 반환되서 command에 입력된다.
command = command.substring(request.getContextPath().length());
}
// 위에서 나온 결과로 /*.do를 가진 command를 map에 입력해서 그 값을 handler 변수에 넣었다.
CommandHandler handler = commandHandlerMap.get(command);
// 만약 그 값이 없으면 Null을 만들고, viewPage도 null로 없다.
if(handler == null) {
handler = new NullHandler();
}
String viewPage = null;
try {
viewPage = handler.process(request, response);
}catch(Throwable e) {
throw new ServletException(e);
}
// 만약 그 값이 null이 아니라는 말은 넘어갈 page가 있다는 것이고,
// 그 페이지로 현재 받은 request, response를 함께 넘겨준다는 것이다.
if(viewPage!= null) {
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPage);
dispatcher.forward(request, response);
}
}
}
이 코드는 책에 기재되어 있는 토대로 작성한 코드이다.
지금 해석해두지 않으면 빨리 까먹을 수 있고, 내 것으로 만들기 힘들 것 같아서 작성했다.
언제나 선택의 연속이라고 한다.
오늘 수업 들었던 것을 다시 보는 것도, 아니 수업을 들을 때 마저 집중을 하냐 안 하냐의 선택까지.
조금 더 노력해서 좋은 결과를 얻어야지