2022.10.11 [TUE]
- Day 47-
수업 주요 목차
- Front Controller Design Pattern
- Git
🤖Review
Front Controller Design Pattern : 모든 클라이언트의 요청을 하나의 진입점으로 통합하여 처리하는 설계 패턴
- 웹 어플리케이션 서비스의 공통 정책을 일관성 있고 효과적으로 처리할 수 있다.(예: 인코딩 , 인증, 예외처리, 데이터수집 등)
👾 FrontController 적용 전 Web MVC 구조 👾
client 1 -- FindMemberByIdServlet -- Model
client 3 -- FindMemberByIdServlet -- Model
client 2 -- RegisterMemberServlet -- Model
client 4 -- RegisterMemberServlet -- Model
👾 FrontController 적용 후 Web MVC 구조 Ver 1 👾
client 1 -- FrontControllerServlet -- Model
client 2 -- FrontControllerServlet -- Model
client 3 -- FrontControllerServlet -- Model
client 4 -- FrontControllerServlet -- Model
client 5 -- FrontControllerServlet -- Model
FrontControllerServlet : command 정보를 이용해 요청을 구분한다.
String command=request.getParameter("command");
if(command.equals("~~~"){
} else if(command.equals("~~~~")){
}
package org.kosta.myproject.controller;
import java.io.IOException;
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 org.kosta.myproject.model.CustomerVO;
import org.kosta.myproject.model.MockDAO;
@WebServlet("/FrontControllerServlet")
public class FrontControllerServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//client의 요청을 분석한다.
//request.setCharacterEncoding("utf-8"); 애초에 받아서 실행되기 전에 setting을 해줘야 함 여기 써도 되지만 그냥 post방식에 다 사용하는 거니까 doPost에 써주는게 제일 깔끔
String command=request.getParameter("command");
//System.out.println(command);
if(command.equals("findCustomerById")) {
String id=request.getParameter("customerId");
CustomerVO cvo=MockDAO.getInstance().findCustomerById(id);
if(cvo!=null) {
request.setAttribute("cvo", cvo);
request.getRequestDispatcher("findbyid-ok.jsp").forward(request, response);
} else {
request.getRequestDispatcher("findbyid-fail.jsp").forward(request, response);
}
} else if(command.equals("registerCustomer")) {
CustomerVO cvo=new CustomerVO(request.getParameter("customerId"), request.getParameter("customerName"), request.getParameter("customerAddress"));
MockDAO.getInstance().registerCustomer(cvo);
response.sendRedirect("register.jsp");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doDispatch(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
doDispatch(request, response);
}
}
doGet()과 doPost()에서는 doDispatch()를 호출하고 하나의 front controller servlet이 여러 요청을 구분하기 위해 hidden 방식을 이용한다.
클라이언트(index.jsp)
<input type="hidden" name="command" value="~~">
하나의 FrontControllerServlet으로 여러 폼에서 요청이 전달될 경우 이를 구분하기 위한 방법 중 하나는 hidden tag를 이용한 방법이 있다. <input type="hidden" name="command" value="findMemberById"> or <input type="hidden" name="command" value="registerMember"> |
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WEB MVC + Front Controller Design Pattern ver 1</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container pt-3">
<h4>WEB MVC + Front Controller Design Pattern</h4>
<form action="FrontControllerServletVer3" method="get">
<input type="hidden" name="command" value="findCustomerById">
<input type="text" name="customerId" placeholder="고객아이디" required="required">
<button type="submit">검색</button>
</form>
<br><br>
<form action="FrontControllerServletVer3" method="post">
<input type="hidden" name="command" value="registerCustomer"> <%-- 2011~12년도까지 사용하던 방식 --%>
<input type="text" name="customerId" placeholder="고객아이디" required="required"><br>
<input type="text" name="customerName" placeholder="고객이름" required="required"><br>
<input type="text" name="customerAddress" placeholder="고객주소" required="required"><br>
<button type="submit">검색</button>
</form>
</div>
</body>
</html>
위와 같은 구조로 여러 클라이언트의 요청을 하나의 진입점으로 모아보았다. 이 경우 FrontControllerServlet의 doDispatch method의 코드량이 요청이 늘어날 수록 비대해질 수 밖에 없는 구조로 refactoring(내부적 구조개선)이 필요하다.
🧚♂️ refactoring : 입,출력은 동일하나 시스템의 내부 구조를 개선하는 활동 (가독성, 재사용성,, 유지보수성 향상이 목적)
- refactoring 1 안 : 요청에 대한 처리를 메서드 별로 분화
- refactoring 2 안 : 메서드 별로 분화해서 FrontControllerServlet class자체가 커지는 것은 피할 수 없으므로 요청 처리를 전담할 Controller class를 별도로 생성&관리
👾 FrontController 적용 후 Web MVC 구조 Ver 2 👾
1안 : 메서드별로 분화 FrontControllerServletVer2
package org.kosta.myproject.controller;
import java.io.IOException;
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 org.kosta.myproject.model.CustomerVO;
import org.kosta.myproject.model.MockDAO;
/**
*
* Front Controller Design Pattern Version 2
* 모든 클라이언트의 요청을 FrontControllerServlet에서 처리해본다.
* doDispatch method의 코드량이 비대 -> refactoring -> method별로 분화
*
* @author hasense
*
*/
@WebServlet("/FrontControllerServletVer2")
public class FrontControllerServletVer2 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void findCustomerById(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
String id=request.getParameter("customerId");
CustomerVO cvo=MockDAO.getInstance().findCustomerById(id);
if(cvo!=null) {
request.setAttribute("cvo", cvo);
request.getRequestDispatcher("findbyid-ok.jsp").forward(request, response);
} else {
request.getRequestDispatcher("findbyid-fail.jsp").forward(request, response);
}
}
protected void registerCustomer(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
CustomerVO cvo=new CustomerVO(request.getParameter("customerId"), request.getParameter("customerName"), request.getParameter("customerAddress"));
MockDAO.getInstance().registerCustomer(cvo);
response.sendRedirect("register.jsp");
}
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//client의 요청을 분석한다.
String command=request.getParameter("command");
System.out.println(getServletName()+" "+command);
if(command.equals("findCustomerById")) {
findCustomerById(request, response);
} else if(command.equals("registerCustomer")) {
registerCustomer(request, response);
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doDispatch(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
doDispatch(request, response);
}
}
👾 Front Controller Design Pattern Version 3 👾
2안 : 클래스별로 분화 FrontControllerServletVer3
package org.kosta.myproject.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
* Front Controller Design Pattern Version 3
* 모든 클라이언트의 요청을 하나의 진입점으로 모은다. 공통 적책 수행(인코딩, 인증, 예외처리, ....)
* 클라이언트 요청을 처리할 별도의 Controller 클래스로 분화하여 서비스한다.
*
*
* 토론점 : doDispatch 내부에서 개별 컨트롤러 객체 생성 후 실행시 각 컨트롤러 객체의 내부 구현부를 확인해서 각각 다르게 실행해야 하는 단점이 존재함
* -> 인터페이스를 통한 표준화, 다형성 적용 환경을 마련하면 됨
* Controller interface의 handleRequest(request,response) : String
*
* @author hasense
*
*/
@WebServlet("/FrontControllerServletVer3")
public class FrontControllerServletVer3 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//client의 요청을 분석한다.
String command=request.getParameter("command");
System.out.println(getServletName()+" "+command);
if(command.equals("findCustomerById")) {
FindCustomerByIdController controller=new FindCustomerByIdController();
controller.findCustomerById(request, response);
} else if(command.equals("registerCustomer")) {
RegisterCustomerContrrollerr controller=new RegisterCustomerContrrollerr();
controller.registerCustomer(request, response);
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doDispatch(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
doDispatch(request, response);
}
}
- FindCustomerByIdController
package org.kosta.myproject.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.kosta.myproject.model.CustomerVO;
import org.kosta.myproject.model.MockDAO;
public class FindCustomerByIdController {
protected void findCustomerById(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
String id=request.getParameter("customerId");
CustomerVO cvo=MockDAO.getInstance().findCustomerById(id);
if(cvo!=null) {
request.setAttribute("cvo", cvo);
request.getRequestDispatcher("findbyid-ok.jsp").forward(request, response);
} else {
request.getRequestDispatcher("findbyid-fail.jsp").forward(request, response);
}
}
}
- RegisterCustomerContrroller
package org.kosta.myproject.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.kosta.myproject.model.CustomerVO;
import org.kosta.myproject.model.MockDAO;
public class RegisterCustomerContrroller {
protected void registerCustomer(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
CustomerVO cvo=new CustomerVO(request.getParameter("customerId"), request.getParameter("customerName"), request.getParameter("customerAddress"));
MockDAO.getInstance().registerCustomer(cvo);
response.sendRedirect("register.jsp");
}
}
모든 클라이언트의 요청을 하나의 진입점으로 모은다. 공통 적책 수행(인코딩, 인증, 예외처리, ....)
클라이언트 요청을 처리할 별도의 Controller 클래스로 분화하여 서비스한다.
토론점 : doDispatch 내부에서 개별 컨트롤러 객체 생성 후 실행시 각 컨트롤러 객체의 내부 구현부를 확인해서 각각 다르게 실행해야 하는 단점이 존재함
-> 인터페이스를 통한 표준화, 다형성 적용 환경을 마련하면 됨
Controller interface의 handleRequest(request,response) : String
👾 Front Controller Design Pattern Version 4 👾
-Controller (Interface)
클라이언트 요청을 처리하는 개별 컨트롤러의 상위 인터페이스 -> 표준화, 캡슐화
컨트롤러를 사용하는 측은 인터페이스의 추상 method handleRequest만 파악해서 사용하면 된다.
-> 단일한 메세지 방식으로 표준화
package org.kosta.myproject.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface Controller {
public String handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
- Front Controller Servlet
package org.kosta.myproject.controller;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/FrontControllerServletVer4")
public class FrontControllerServletVer4 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doDispatch(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
doDispatch(request, response);
}
protected void doDispatch(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
String command = request.getParameter("command");
Controller controller = null;
if (command.equals("findCustomerById")) {
controller=new FindCustomerByIdController();
} else if (command.equals("registerCustomer")) {
controller=new RegisterCustomerController();
}
String path=controller.handleRequest(request, response);
if(path.startsWith("redirect:")) {
response.sendRedirect(path.substring(9));
} else {
request.getRequestDispatcher(path).forward(request, response);
}
} catch (Exception e) {
e.printStackTrace();
}
} // doDispatch
}
post방식에서 redirect를 이용할 경우 path 앞에 redirect:를 붙여주고 조건에 startsWith() method사용
path에서 redirect:를 뺀 뒷부분만 사용하고 싶다면 subString을 사용(몇번째부터인지 모르겠으면 test case하나 만들어서
"redirect:".trim().length()로 redirect:의 길이를 파악해주면 된다.)
- Find
package org.kosta.myproject.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.kosta.myproject.model.CustomerVO;
import org.kosta.myproject.model.MockDAO;
public class FindCustomerByIdController implements Controller {
@Override
public String handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
String path=null;
String id=request.getParameter("customerId");
CustomerVO cvo=MockDAO.getInstance().findCustomerById(id);
if(cvo!=null) {
request.setAttribute("cvo", cvo);
path="findbyid-ok.jsp";
} else {
path="findbyid-fail.jsp";
}
return path;
}
}
- Register
package org.kosta.myproject.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.kosta.myproject.model.CustomerVO;
import org.kosta.myproject.model.MockDAO;
public class RegisterCustomerController implements Controller {
@Override
public String handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
CustomerVO cvo=new CustomerVO(request.getParameter("customerId"), request.getParameter("customerName"), request.getParameter("customerAddress"));
MockDAO.getInstance().registerCustomer(cvo);
System.out.println("고객 등록 컨트롤러 : "+request.getParameter("customerName"));
String path="redirect:register.jsp";
return path;
}
}
↓
1. Find By Id
2. Register
🔎 Git 실습 내용
1.Create a new repository
- Add a README file
- Add .gitignore
↓
2. Edit .gitignore
▼참고 사이트▼
사용하는 프로그램에 맞춰서 .gitignore 파일을 만들어주는 사이트
https://www.toptal.com/developers/gitignore
gitignore.io
Create useful .gitignore files for your project
www.toptal.com
3. Clone Git repository in Eclipse
STEP 1. copy the url
STEP 2. Clone a Git Repository
GitHub에서 url copy하면 자동적으로 정보가 채워진다. 주의할 점은 Authentication User이름과 Password(발급받은 토큰)를 잘 넣어줘야 한다. next누르고 Finish누르면 clone 끝!
4. Share Project
5. Commit & Push
파일 수정 후 저장하면 Unstaged Changes에 올라가고 옆에 있는 + 표시를 눌러주거나 마우스로 드래그해서 Staged Changes로 내려준다.
Commit 전 message에 변경사항을 적어주고 아래 Commit을 먼저 눌러준다.
이렇게 Push해야 할 내용이 1개 있다고 뜨면 아래 Push Head...를 눌러준다.
Preview -> Push해주면 끝!
//오늘의 숙제
오늘은 블로그 정리만 하고 쉬어야 하는 날...🧟♀️