Jan 27, 2023
7 mins read
서블릿 종속성 제거 : 요청 파라메터는 Map으로 받아서 처리하고 request 객체 대신 Model 객체를 구현한다.
-> 코드가 단순해지고 테스트, 수정이 쉬워진다.
뷰 이름 중복 제거 : 물리 위치 이름 대신 논리 이름을 받아서 처리한다. 물리 위치는 프론트컨트롤러에서만 처리한다.
/WEB-INF/views/new-form.jsp -> new-form
(인프런 수업 듣는중)
hello.servlet.web.frontcontroller에 ModelView 객체를 만든다. 뷰이름과 뷰렌더링에 필요한 모델을 Map형태로 가져간다.
package hello.servlet.web.frontcontroller;
import java.util.HashMap;
import java.util.Map;
public class ModelView {
private String viewName;
private Map<String, Object> model = new HashMap<>();
public ModelView(String viewName) {
this.viewName = viewName;
}
public String getViewName() {
return viewName;
}
public void setViewName(String viewName) {
this.viewName = viewName;
}
public Map<String, Object> getModel() {
return model;
}
public void setModel(Map<String, Object> model) {
this.model = model;
}
}
package hello.servlet.web.frontcontroller.v3;
import java.util.Map;
import hello.servlet.web.frontcontroller.ModelView;
public interface ControllerV3 {
ModelView process(Map<String, String> paramMap);
}
package hello.servlet.web.frontcontroller.v3.controller;
import java.util.Map;
import hello.servlet.web.frontcontroller.ModelView;
import hello.servlet.web.frontcontroller.v3.ControllerV3;
public class MemberFormControllerV3 implements ControllerV3{
@Override
public ModelView process(Map<String, String> paramMap) {
return new ModelView("new-form");
}
}
package hello.servlet.web.frontcontroller.v3.controller;
import java.util.Map;
import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import hello.servlet.web.frontcontroller.ModelView;
import hello.servlet.web.frontcontroller.v3.ControllerV3;
public class MemberSaveControllerV3 implements ControllerV3{
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public ModelView process(Map<String, String> paramMap) {
String username = paramMap.get("username");
int age = Integer.parseInt(paramMap.get("age"));
Member member = new Member(username, age);
memberRepository.save(member);
ModelView mv = new ModelView("save-result");
mv.getModel().put("member", member);
return mv;
}
}
package hello.servlet.web.frontcontroller.v3.controller;
import java.util.List;
import java.util.Map;
import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import hello.servlet.web.frontcontroller.ModelView;
import hello.servlet.web.frontcontroller.v3.ControllerV3;
public class MemberListControllerV3 implements ControllerV3{
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public ModelView process(Map<String, String> paramMap) {
List<Member> members = memberRepository.findAll();
ModelView mv = new ModelView("members");
mv.getModel().put("members", members);
return mv;
}
}
package hello.servlet.web.frontcontroller.v3;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import hello.servlet.web.frontcontroller.ModelView;
import hello.servlet.web.frontcontroller.MyView;
import hello.servlet.web.frontcontroller.v3.controller.MemberFormControllerV3;
import hello.servlet.web.frontcontroller.v3.controller.MemberListControllerV3;
import hello.servlet.web.frontcontroller.v3.controller.MemberSaveControllerV3;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
//front-controller/v3/으로 들어오는 모든 요청을 컨트롤 한다.
@WebServlet(name = "frontControllerServletV3", urlPatterns = "/front-controller/v3/*")
public class FrontControllerServletV3 extends HttpServlet {
private Map<String, ControllerV3> controllerMap = new HashMap<>();
public FrontControllerServletV3(){
controllerMap.put("/front-controller/v3/members/new-form", new MemberFormControllerV3());
controllerMap.put("/front-controller/v3/members/save", new MemberSaveControllerV3());
controllerMap.put("/front-controller/v3/members", new MemberListControllerV3());
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String requestURI = request.getRequestURI();
//다형성 사용
ControllerV3 controller = controllerMap.get(requestURI);
if (controller == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
//pramMap
Map<String, String> paramMap = createParamMap(request);
ModelView mv = controller.process(paramMap);
String viewName = mv.getViewName(); //논리이름
MyView view = viewResolver(viewName);
view.render(mv.getModel(), request, response); //v2 버전의 MyView객체 뷰에 모델을 추가한 메서드 render를 추가해야한다.
}
public Map<String, String> createParamMap(HttpServletRequest request){
Map<String, String> paramMap = new HashMap<>();
request.getParameterNames().asIterator().forEachRemaining(paramName->paramMap.put(paramName, request.getParameter(paramName)));
return paramMap;
}
public MyView viewResolver(String viewName) {
return new MyView("/WEB-INF/views/" +viewName+ ".jsp");
}
}
package hello.servlet.web.frontcontroller;
import java.io.IOException;
import java.util.Map;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
public class MyView {
private String viewPath;
public MyView(String viewPath){
this.viewPath = viewPath;
}
//각 컨트롤러가 뷰로 이동시켰던 로직을 따로 분리하여 만든것이다.
public void render(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
}
//모델을 전달받아 뷰로 이동시키는 함수 추가
public void render(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
modelToRequestAttribute(model, request);
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request, response);
}
//jsp에 모델에 있는 값을 전달하기 위해 request에 담아주는 작업을 해준다. (jsp는 request에서 값을 받기 때문에)
private void modelToRequestAttribute(Map<String, Object> model, HttpServletRequest request) {
model.forEach((key,value)->request.setAttribute(key, value)); //변수로 루프돌려서 request에 다 담음
}
}
뷰와 모델이 다 추가되어 프론트컨트롤러에 많은 변화가 생겼다. 그 대신 각 비지니스 로직을 수행하는 컨트롤러는 훨씬 단순해졌다.
개념적으로나 코드 보면서 따라가면 알것같은데 막상 0부터 다시 만들어 보라고하면 못할것같다. 계속 보면서 익숙해져야할듯.
http://localhost:8080/front-controller/v3/members
http://localhost:8080/front-controller/v3/members/new-form
접속해보면 잘 동작을 하는걸 확인할 수 있다.