반응형

# MVC04_09 View의 경로를 만들어주는 ViewResolver

  • 기존에 POJO에서 경로를 리턴해 줄때 아래와 같이 리턴 해줬었는데, 경로를 모두 리턴할 경우 추후 폴더가 변경되는 등의 상황 발생 시 경로를 수정해줘야 하는 번거로움이 발생.
return "/WEB-INF/member/memberContent.jsp";
  • 그래서 View의 논리적인 이름만 리턴 될 수 있도록 변경 예정.
return "memberContent";

## ViewResolver

  • prefix와 subfix를 붙여서 하나의 논리적인 경로를 만들어내는 역할을 하는 클래스.

### prefix 와 subfix

  • 아래 경로 에서 논리 경로를 기준으로 앞부분을 prfix, 뒷 부분을 subfix 라고 한다.
return "/WEB-INF/member/memberContent.jsp";

여기서 논리적인 경로 memberContent을 기준으로.

앞 부분을 prefix

뒷 부분을 subfix 

라고 한다.

### ViewResolver 작업 진행_1 : 임시로 FrontController 에서 prefix, subfix 추가하여 논리경로 생성

  • 기존 memberRegister.html 을 jsp로 변경
  • MemberContentController 리턴 값 변경 -> 기존 전체 경로에서 return "memberContent"; 로 변경
  • MemberListController 리턴 값 변경 -> 기존 전체 경로에서 return "memberList"; 로 변경
  • MemberRegisterController 리턴 값 변경 -> 기존 전체 경로에서 return "memberRegister"; 로 변경
  • FrontController 에서 prefix, subfix 추가
package kr.bit.frontController;

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

import javax.servlet.RequestDispatcher;
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 kr.bit.controller.Controller;
import kr.bit.controller.MemberContentController;
import kr.bit.controller.MemberDeleteController;
import kr.bit.controller.MemberInsertController;
import kr.bit.controller.MemberListController;
import kr.bit.controller.MemberRegisterController;
import kr.bit.controller.MemberUpdateController;
import kr.bit.model.MemberDAO;
import kr.bit.model.MemberVO;

@WebServlet("*.do")
public class MemberFrontController extends HttpServlet {
	protected void service(HttpServletRequest request, HttpServletResponse response) 
							throws ServletException, IOException {
		
		// 한글 깨짐 방지
		request.setCharacterEncoding("utf-8");
		// 1. 클라이언트가 어떤 요청을 했는지 파악하기. 
		// (request를 이용하면 클라이언트가 어떤 요청을 했는지 파악 가능)
		String url = request.getRequestURI();
		// System.out.println("url : " + url); 				url 확인
		// /MVC04/memberList.do 이런식으로 출력되는 것 확인 가능.
		
		// 컨택스트 가져오기	
		String ctx = request.getContextPath();
		// System.out.println("ctx : " + ctx);				contextPath 확인
		// /MVC04 이런식으로 출력되는 것 확인 가능.
		
		// 2. 실제로 요청한 명령이 무엇인지 파악(contextPath 제외한 url)
		String command = url.substring(ctx.length());	
		// System.out.println("command : " + command);		클라이언트가 서버에 요청한 실제 command
		// memberList.do 등이 출력된다.
		
		// Controller _ POJO 연결 위함
		Controller controller = null;
		String nextPage = null;
		
		// 3. 요청에 따른 분기 작업. -> HandlerMapping에서 진행
		HandlerMapping mapping = new HandlerMapping();
		controller = mapping.getController(command);
		nextPage = controller.requestHandler(request, response);
		
		// forward, redirect
		if(nextPage != null ) {
			if(nextPage.indexOf("redirect:") != -1) {	// redirect: 라는 글자 존재 시 redirect
				response.sendRedirect(nextPage.split(":")[1]);
			} else {
				// ViewResolver 작업 -> prefix랑 subfix 앞뒤에 붙여 논리적인 경로 완성
				RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/member/" + nextPage + ".jsp");
				rd.forward(request, response);
			}
		}
	}
}

### ViewResolver 작업 진행_2 : ViewResolver 클래스 생성해서 논리경로 생성

  • 프로젝트 > src > kr.bit.frontcontroller > class > ViewResolver 이름의 클래스 생성
  • 아래와 같이 작업 해주면 이후에 경로가 수정되는 상황 발생 시 해당 클래스에서 경로 수정해주면 된다.
package kr.bit.frontController;

public class ViewResolver {
	public static String makeView(String nextPage) {
		return "/WEB-INF/member/" + nextPage + ".jsp";
	}
}
  • FrontController  수정 (ViewResolver 로 작업 될 수 있도록 변경)
package kr.bit.frontController;

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

import javax.servlet.RequestDispatcher;
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 kr.bit.controller.Controller;
import kr.bit.controller.MemberContentController;
import kr.bit.controller.MemberDeleteController;
import kr.bit.controller.MemberInsertController;
import kr.bit.controller.MemberListController;
import kr.bit.controller.MemberRegisterController;
import kr.bit.controller.MemberUpdateController;
import kr.bit.model.MemberDAO;
import kr.bit.model.MemberVO;

@WebServlet("*.do")
public class MemberFrontController extends HttpServlet {
	protected void service(HttpServletRequest request, HttpServletResponse response) 
							throws ServletException, IOException {
		
		// 한글 깨짐 방지
		request.setCharacterEncoding("utf-8");
		// 1. 클라이언트가 어떤 요청을 했는지 파악하기. 
		// (request를 이용하면 클라이언트가 어떤 요청을 했는지 파악 가능)
		String url = request.getRequestURI();
		// System.out.println("url : " + url); 				url 확인
		// /MVC04/memberList.do 이런식으로 출력되는 것 확인 가능.
		
		// 컨택스트 가져오기	
		String ctx = request.getContextPath();
		// System.out.println("ctx : " + ctx);				contextPath 확인
		// /MVC04 이런식으로 출력되는 것 확인 가능.
		
		// 2. 실제로 요청한 명령이 무엇인지 파악(contextPath 제외한 url)
		String command = url.substring(ctx.length());	
		// System.out.println("command : " + command);		클라이언트가 서버에 요청한 실제 command
		// memberList.do 등이 출력된다.
		
		// Controller _ POJO 연결 위함
		Controller controller = null;
		String nextPage = null;
		
		// 3. 요청에 따른 분기 작업. -> HandlerMapping에서 진행
		HandlerMapping mapping = new HandlerMapping();
		controller = mapping.getController(command);
		nextPage = controller.requestHandler(request, response);
		
		// forward, redirect
		if(nextPage != null ) {
			if(nextPage.indexOf("redirect:") != -1) {	// redirect: 라는 글자 존재 시 redirect
				response.sendRedirect(nextPage.split(":")[1]);
			} else {
				// ViewResolver 작업
				// ViewResolver 클래스에서 경로 가져올수 있도록 변경
				RequestDispatcher rd = request.getRequestDispatcher(ViewResolver.makeView(nextPage));
				rd.forward(request, response);
			}
		}
	}
}

 

# MVC04_10 Context Path가 변경되어도 동일한 경로 유지하기

  • Servers > server.xml
  • 만약 기존 MVC04 가 MVC로 바뀌게 되면 memberContent.jsp 등에 /MVC04/memberUpdate.do 로 되어있는 부분을 일일이 확인해서 수정해 줘야 한다. (수정은 어렵지 않지만 번거로움)
server.xml 에서..

<Context docBase="MVC04" path="/MVC04" reloadable="true" source="org.eclipse.jst.jee.server:MVC04"/></Host>

여기서 path 가 Context Path.
  • 현재 프로젝트의 Context Path를 자동으로 가져와서 Context Path 자리에 출력해주면 될 것.

## Context Path 가져오기

  • 아래 코드 이용해서 Context Path 가져오기
String ctx = request.getContextPath();

## Context Path 가져오는 활용한 변경 작업

  • 우선 Controller 변경 작업 진행

1. MemberDeleteController

package kr.bit.controller;

import java.io.IOException;

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

import kr.bit.model.MemberDAO;

public class MemberDeleteController implements Controller {

	@Override
	public String requestHandler(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		// Context Path 가져오기
		String ctx = request.getContextPath();	// MVC04가 옴
		
		int num = Integer.parseInt(request.getParameter("num"));
		
		MemberDAO dao = new MemberDAO();
		
		int cnt = dao.memberDelete(num);
		
		String nextPage = null;
		
		if (cnt > 0) {
			nextPage = "redirect:" + ctx + "/memberList.do";	// Context Path 추가
		} else {
			throw new ServletException("not delete");
		}
		
		return nextPage;
	}

}

2. MemberInsertController

package kr.bit.controller;

import java.io.IOException;
import java.io.PrintWriter;

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

import kr.bit.model.MemberDAO;
import kr.bit.model.MemberVO;

public class MemberInsertController implements Controller {

	@Override
	public String requestHandler(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		// Context Path 가져오기
		String ctx = request.getContextPath();	// MVC04가 옴
				
		// 1. 파라미터 수집(VO)
		String id = request.getParameter("id");
		String pass = request.getParameter("pass");
		String name = request.getParameter("name");
		int age = Integer.parseInt(request.getParameter("age"));
		String email = request.getParameter("email");
		String phone = request.getParameter("phone");
		
		// 파라미터 수집(VO)
		// MemberVO vo = new MemberVO(id, pass, name, age, email, phone);
		MemberVO vo = new MemberVO();		
		vo.setId(id);
		vo.setPass(pass);
		vo.setName(name);
		vo.setAge(age);
		vo.setEmail(email);
		vo.setPhone(phone);
		
		//System.out.println("vo : " + vo);	// vo.toString() 이 생략되어있는 것.
		// Model과 연동하는 부분
		MemberDAO dao = new MemberDAO();
		int cnt = dao.memberInsert(vo);
		
		// PrintWriter out = response.getWriter();
		String nextPage = null;
		// 가입 성공
		if ( cnt > 0 ) {
			//out.println("insert success");	
			// 다시 회원 리스트 보기로 가야함.
			// response.sendRedirect("/MVC04/memberList.do");
			nextPage = "redirect:" + ctx + "/memberList.do";	// Context Path 추가
		// 가입 실패 -> 예외 객체를 만들어서 WAS에게 던지자.
		} else {
			throw new ServletException("not insert");	
		}
		return nextPage;
	}

}

3. MemberUpdateController

package kr.bit.controller;

import java.io.IOException;

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

import kr.bit.model.MemberDAO;
import kr.bit.model.MemberVO;

public class MemberUpdateController implements Controller {

	@Override
	public String requestHandler(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		// Context Path 가져오기
		String ctx = request.getContextPath();	// MVC04가 옴
				
		request.setCharacterEncoding("utf-8");
		// 1. 파라미터 수집(VO)
		int num = Integer.parseInt(request.getParameter("num"));
		int age = Integer.parseInt(request.getParameter("age"));
		String email = request.getParameter("email");
		String phone = request.getParameter("phone");
	
		MemberVO vo = new MemberVO();
		vo.setNum(num);
		vo.setAge(age);
		vo.setEmail(email);
		vo.setPhone(phone);
	
		MemberDAO dao = new MemberDAO();
		
		int cnt = dao.memberUpdate(vo);
		
		String nextPage = null;
		
		if (cnt > 0) {
			nextPage = "redirect:" + ctx + "/memberList.do";	// Context Path 추가
		} else {
			throw new ServletException("not update");
		}
		
		return nextPage;
	}

}
  • jsp 변경작업 진행
  • jsp에서는 아래와 같이 Context Path 가져오기
<!-- Context Path 가져오기 -->
<c:set var="ctx" value="${pageContext.request.contextPath}"/>

<!-- 가져온 Context Path 사용 -->
${ctx}

1. memberContent.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="kr.bit.model.*" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
	// JSTL 사용 전
	// MemberVO vo = (MemberVO)request.getAttribute("vo");
%>    
<!-- Context Path 가져오기 -->
<c:set var="ctx" value="${pageContext.request.contextPath}"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css'>
<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script>
<script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js'></script>
</head>
<body>
<form action="${ctx}/memberUpdate.do" method="post">
<input type="hidden" name="num" value="${vo.getNum()}"/>
	<table border="1" class="table table-bordered">
	<c:if test="${vo != null}">
		<tr>
			<td colspan="2">${vo.getName()} 회원의 상세보기</td>
		</tr>
		<tr>
			<td>번호</td>
			<td>${vo.getNum()}</td>
		</tr>
		<tr>
			<td>아이디</td>
			<td>${vo.getId()}</td>
		</tr>
		<tr>
			<td>비밀번호</td>
			<td>${vo.getPass()}</td>
		</tr>
		<tr>
			<td>이름</td>
			<td>${vo.getName()}</td>
		</tr>
		<tr>
			<td>나이</td>
			<td><input type="text" name="age" value="${vo.getAge()}" /></td>
		</tr>
		<tr>
			<td>이메일</td>
			<td><input type="text" name="email" value="${vo.getEmail()}" /></td>
		</tr>
		<tr>
			<td>전화번호</td>
			<td><input type="text" name="phone" value="${vo.getPhone()}" /></td>
		</tr>
	</c:if>
		<tr>
			<td colspan="2" align="center">
				<input type="submit" value="수정하기" class="btn btn-primary" />
				<input type="reset" value="취소" class="btn btn-warning" />
				<input type="button" value="리스트" onclick="location.href='${ctx}/memberList.do'" class="btn" />
			</td>
		</tr>
	</table>
</form>
</body>
</html>

2. memberList.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="kr.bit.model.*" %>
<%@ page import="java.util.*" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
	// JSTL 사용 전.
	// ArrayList<MemberVO> list = (ArrayList<MemberVO>) request.getAttribute("list");
%>
<!-- Context Path 가져오기 -->
<c:set var="ctx" value="${pageContext.request.contextPath}"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
<link rel='stylesheet' href='https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css'>
<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script>
<script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js'></script>
<script>
	function deleteFn(num) {
		location.href="${ctx}/memberDelete.do?num=" + num;
	}
</script>
</head>
<body>
[MVC04 예제 - FrontController + POJO]
<table class="table table-bordered">
	<tr>
		<td>번호</td>
		<td>아이디</td>
		<td>비밀번호</td>
		<td>이름</td>
		<td>나이</td>
		<td>이메일</td>
		<td>전화번호</td>
		<td>삭제</td>
	</tr>
	<c:forEach var="vo" items="${list}">		
		<tr>
			<td>${vo.getNum()}</td>
			<td><a href="${ctx}/memberContent.do?num=${vo.getNum()}">${vo.getId()}</a></td>
			<td>${vo.getPass()}</td>
			<td>${vo.getName()}</td>
			<td>${vo.getAge()}</td>
			<td>${vo.getEmail()}</td>
			<td>${vo.getPhone()}</td>
			<td><input type="button" value="삭제" class="btn btn-warning" onclick="deleteFn(${vo.getNum()})" /></td>
		</tr>
	</c:forEach>
	<tr>
		<td colspan="8" align="right"><input type="button" value="회원가입" class="btn btn-primary" onclick="location.href='${ctx}/memberRegister.do'"/></td>
	</tr>
</table>
</body>
</html>

3. memberRegister.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!-- Context Path 가져오기 -->
<c:set var="ctx" value="${pageContext.request.contextPath}"/>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>신규 회원 가입</title>
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
	<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
	<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<h1>회원가입화면</h1>
<form action="${ctx}/memberInsert.do" method="POST" >
	<table class="table table-bordered">
	  <tr>
	    <td>아이디</td>
	    <th><input type="text" name="id" /></th>
	  </tr>
	  <tr>
	    <td>패스워드</td>
	    <th><input type="password" name="pass" /></th>
	  </tr>
	  <tr>
	    <td>이름</td>
	    <th><input type="text" name="name" /></th>
	  </tr>
	  <tr>
	    <td>나이</td>
	    <th><input type="text" name="age" /></th>
	  </tr>
	  <tr>
	    <td>이메일</td>
	    <th><input type="text" name="email" /></th>
	  </tr>
	  <tr>
	    <td>전화번호</td>
	    <th><input type="text" name="phone" /></th>
	  </tr>
	  <tr>
	    <td colspan="2" align="center">
	    	<input type="submit" value="가입" class="btn btn-primary"/>
			<input type="reset" value="취소" class="btn btn-warning"/>
	    </td>
	  </tr>
	</table>
</form>
</body>
</html>
반응형

+ Recent posts