ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • MVC 만들어보기
    스프링 2022. 12. 25. 22:45

    서블릿 종속성 제거

    controller에서는 HttpservletRequest, HttpservletResponse가 필요 하지 않고, 단지 request, 와 response가 필요한 것이다.

    요청 파라미터 정보는 Map으로 대신 넘기도록 한다. 또한 request객체를 model로 사용하는 대신 별도의 Model객체를 만들어서 반환한다.

     

    뷰 이름 중복 제거 

    viewPath를 적을 때 물리 이름을 전부 적는게 아니라, 논리적인 이름을 반환하도록 한다.

    따라서 프론트컨트롤러에서 물리 이름을 처리하도록 한다.

    경로가 변경되면 각 뷰의 경로를 모두 고칠 필쇼 없이, 프론트 컨트롤러에 적혀진 경로만 바꿔주면 된다.
    즉, 변경의 지점을 한개로 할 수 있다.
    프론트 컨트롤러

    • 프론트 컨트롤러 서블릿 하나로 클라이언트의 요청을 받음
    • 프론트 컨트롤러가 요청에 맞는 컨트롤러를 찾아서 호출

     

    frontcontroller

    @WebServlet(name = "frontControllerV3", 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;
            }
    
            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);
        }
    
        private static MyView viewResolver(String viewName) {
            return new MyView("/WEB-INF/views" + viewName + ".jsp");
        }
    
        private 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;
        }
    
    }

    요청된 URL을 가져와서 해당 컨트롤러에 맞는 컨트롤러가 호출이 되면서 process가 실해된다.

     

    각각의 컨트롤러는 controllerV3을 implements하여 구현이 되어있다.

    각 컨트롤러에서 복잡한 절차를 걸친 후에 데이터를 담은 model과 view이름을 담는 ModelView를 return한다.

    논리적 이름을 MyView로 물리적인 이름으로 변환시켜주고 가진 모델을 포함하여 동적으로 rendering을 실시하도록 한다.

     

    정리하면 해당 URI를 얻으면 매핑해서 해당 컨트롤러를 가져온다. createParaMap으로 form으로 보내야할 정보가 있다면 이를 map에 담아서 process에 넘긴다.

    해당 파라미터를 ModelView에서 처리하게 되고, viewResolver가 해당하는 JSP를 불러오게 된다. 이에따라 만약 경로가 바뀌었다 해도 손쉽게 코드를 손대지 않고 변경이 가능하게 된다.

     

    개선방향

    실제 컨트톨러 인터페이스를 구현하는 개발자 입장에서 보면, 항상 ModelView 객체를 생성하고 반환해야 하는 부분이 조금은 번거롭다.

     

    따라서 컨트롤러에서 MyView를 return하지 않고, ViewName만을 return하도록 변경하도록 개선한다.

     

     

    public class MemberSaveControllerV4 implements ControllerV4 {
        private MemberRepository memberRepository = MemberRepository.getInstance();
    
        @Override
        public String process(Map<String, String> paramMap, Map<String, Object> model) {
            String username = paramMap.get("username");
            int age = Integer.parseInt(paramMap.get("age"));
    
            Member member = new Member(username, age);
            memberRepository.save(member);
    
            model.put("member", member);
            return "save";
        }
    }

    이제 ModelView객체를 생성하지 않는다. V3의 코드와 비교해 보았을때 번거로움이 사라졌다.

    Model이 파라미터로 넘어오고, ViewName만을 반환한다.

     

    frontController

    @Override
        protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            System.out.println("FrontControllerServletV4.service");
    
            String requestURI = request.getRequestURI();
    
            ControllerV4 controller = controllerMap.get(requestURI);
            if (controller == null) {
                response.setStatus(HttpServletResponse.SC_NOT_FOUND);
                return;
            }
    
            Map<String, String> paramMap = createParaMap(request);
            Map<String, Object> model = new HashMap<>();
            String viewName = controller.process(paramMap, model);
    
            MyView view = ViewResolver(viewName);
    
            view.render(model, request, response);
        }

    프론트컨트롤러에서 Map으로 model을 생성하고, 해당 컨트롤러에 파라미터로 넘겨준다. 컨트롤러에서는 model에 정보들을 담아두게 된다. 이후 ViewResolver로 해당 VeiwName을 가져오고, MyView가 render로 해당 JSP를 랜더링 해준다.

     

    모델 객체를 프론트 컨트롤러에서 생성해서 넘겨준다. 컨트롤러에서 모델 객체에 값을 담으면 여기에 그대로 담겨있게 된다.

    728x90

    '스프링' 카테고리의 다른 글

    핸들러 매핑, 핸들러 어댑터, 뷰 리졸버  (0) 2022.12.26
    스프링 MVC  (0) 2022.12.26
    MVC 이해해보자  (0) 2022.12.24
    로깅  (0) 2022.12.23
    빈스코프  (0) 2022.12.22

    댓글

Designed by Tistory.