서블릿 종속성 제거

컨트롤러 입장에서 HttpServletRequest, HttpServletResponse가 꼭 필요할까?

요청 파라미터 정보는 자바의 Map으로 넘기도록 하면 컨트롤러가 서블릿 기술을 몰라도 작동할 수 있다.

request 객체를 Model로 사용하는 대신에 별도의 Model 객체를 만들어서 반환하면 된다.

컨트롤러가 서블릿 기술을 전혀 사용하지 않도록 변경해보았다.

이렇게 하면 구현 코드가 단순해지며 테스트 코드 작성에도 용이하다.

 

뷰 이름 중복 제거

컨트롤러에서 지정하는 뷰 이름에 중복이 있는 것을 확인할 수 있다.

컨트롤러는 뷰의 논리 이름을 반환하고, 실제 물리 위치의 이름은 프론트 컨트롤러에서 처리하도록

단순화 하면 향후 뷰의 폴더위치가 함게 이동해도 프론트 컨트롤러만 고치면 된다.

 

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/lecture/71191?volume=1.00&tab=note&speed=0.75&mm=close

ModelView

지금가지 컨트롤러에서 종속적인 HttpServletRequest를 사용했다. 그리고 Model도 request.setAttribute()를 통해

데이터르를 저장하고 뷰에 전달했다.

서블릿의 종속성을 제거하기 위해  Model을 직접 만들고, 추가로 View 이름가지 전달하는 객체를 만들어보았다.

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;
    }
}

뷰의 이름, 뷰를 랜더링할때 필요한 model객체를 가진 클래스를 생성한다.

package hello.servlet.web.frontcontroller.V3;

import hello.servlet.web.frontcontroller.ModelView;

import java.util.Map;

public interface ControllerV3 {

    ModelView process(Map<String, String> paraMap);
}

 

컨트롤러V3 인터페이스를 만들고 이전 버전과는 다르게 서블릿 기술을 전혀 사용하지 않았다.

package hello.servlet.web.frontcontroller.V3.controller;

import hello.servlet.web.frontcontroller.ModelView;
import hello.servlet.web.frontcontroller.V3.ControllerV3;

import java.util.Map;

public class MemberFormControllerV3 implements ControllerV3 {
    @Override
    public ModelView process(Map<String, String> paraMap) {
        return new ModelView("new-form");
    }
}
package hello.servlet.web.frontcontroller.V3.controller;

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;

import java.util.Map;

public class MemberSaveControllerV3 implements ControllerV3 {

    MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    public ModelView process(Map<String, String> paraMap) {
        String username = paraMap.get("username");
        int age = Integer.parseInt(paraMap.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 hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import hello.servlet.web.frontcontroller.ModelView;
import hello.servlet.web.frontcontroller.V3.ControllerV3;

import java.util.List;
import java.util.Map;

public class MemberListControllerV3 implements ControllerV3 {

    MemberRepository memberRepository = MemberRepository.getInstance();

    @Override
    public ModelView process(Map<String, String> paraMap) {
        List<Member> members = memberRepository.findAll();
        ModelView mv = new ModelView("members");
        mv.getModel().put("members",members);

        return mv;
    }
}

각각 컨트롤러들을 만들어주었다. 여기서 반환값은 논리적인 이름이다. 실제 물리적인 이름은 프론트 컨트롤러에서 처리한다.

package hello.servlet.web.frontcontroller.V3;

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 javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@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 {
        System.out.println("FrontControllerServletV1.service");

        String requestURI = request.getRequestURI();

        ControllerV3 controller = controllerMap.get(requestURI);
        if(controller == null){
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        Map<String, String> paraMap = createParamMap(request);
        ModelView mv = controller.process(paraMap);
        String viewName = mv.getViewName();
        MyView view = viewResolver(viewName);
        view.render(mv.getModel(),request,response);
    }

    private MyView viewResolver(String viewName){
        return new MyView("/WEB-INF/views/"+viewName+".jsp");
    }

    private Map<String, String> createParamMap(HttpServletRequest request) {
        Map<String, String> paraMap = new HashMap<>();
        request.getParameterNames().asIterator()
                .forEachRemaining(paramName -> paraMap.put(paramName, request.getParameter(paramName)));
        return paraMap;
    }
}

프론트 컨트롤러 코드는 이전보다 복잡해졌다.

viewResolver()가 컨트롤러가 반환한 논리이름을 실제 물리 이름으로 치환해준다. 그리고 실제 물리 경로가 있는

Myview객체를 반환하고 Myview 객체의 render()를 통해 화면을 그리게 된다.

+ Recent posts