반응형
# 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>
반응형