본문으로 바로가기
반응형

 

 

 

 

이전 포스팅에선 컨트롤러에서 ModelView를 반환하는 것을 다뤘다.

 

 

https://healthdevelop.tistory.com/entry/spring51

 

[Spring MVC] 프론트 컨트롤러 패턴 도입 | 프론트 컨트롤러 패턴 적용하기 - 회원 관리 예제(FrontContr

● 프론트 컨트롤러(Front Controller)  Spring MVC 에서 프론트 컨트롤러가 도입되고 나서 컨트롤러의 호출 이전에 공통 처리 기능이 가능해졌다. 프론트 컨트롤러 서블릿 하나로 클라이언트의 요청

healthdevelop.tistory.com

 

프론트 컨트롤러에서 매핑 정보에 맞는 컨트롤러를 호출하고 

컨트롤러에서는 로직을 수행한 후 forwarding 할 view 이름과 model을 반환했다.

 

하지만 이런 식으로 코드를 작성하면 컨트롤러에서 항상 ModelView를 생성하고

그것을 반환해주는 형식으로 동작한다.

 

 

@Override
public ModelView process(Map<String, String> paraMap) {
    return new ModelView("new-form"); // ModelView를 항상 생성하고 반환
}

 

 

더욱 간단하게 코드 구조를 작성하기 위한 방법이 필요하다.

 

그 방법은 controller가 호출될 때 paramMap과 model을 매개변수로 넘겨주는 것이다.

이때 반환 타입은 단순히 논리 뷰 이름으로 반환하면 된다.

 

참고로 앞서 설명한 구조는 현재 Spring MVC 구조와 거의 동일한 구조이다.

 

 

 

 

 


● 구조  

 

 

출처: 스프링 MVC 1편(김영한)

 

 

이전 포스팅과의 차이점은 거의 없다.

 

단지 FrontController에서 매핑된 정보를 바탕으로 컨트롤러를 호출할 때,

paramMap과 model을 넘겨준다.

 

이에 Controller는 로직을 수행하고 논리 view 이름만 반환한다.

 

 

직접 설명보단 구현이 이해가 빠르다.

 

 

 

 


● ModelView 생성

 

 

 

 

 

Controller(인터페이스)

package hello.servlet.web.frontcontroller.v4;

import java.util.Map;

public interface ControllerV4 {

    /**
     *
     * @param paramMap
     * @param model
     * @return
     */
    String process(Map<String, String> paramMap, Map<String, Object> model);
}

 

이전 Controller 인터페이스에선 ModelView를 반환했지만

이번엔 단순히 String(논리 view 이름)을 반환한다.

 

 

 

 

 

 

 

Controller(구현체)

package hello.servlet.web.frontcontroller.v4.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 hello.servlet.web.frontcontroller.v4.ControllerV4;

import java.util.Map;

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

 

실제 구현체는 FrontController로부터 받은 paramMap(request attribute)과  model을 활용한다.

paramMap에서 받은 정보를 토대로 로직을 수행한 후,

그 결과를 model에 담아주고 forwarding 할 view 이름을 반환한다.

 

 

 

 

 

 

FrontController

package hello.servlet.web.frontcontroller.v4;

import +;


@WebServlet(name = "frontControllerServletV4", urlPatterns = "/front-controller/v4/*")
public class FrontControllerServletV4 extends HttpServlet {

    private Map<String, ControllerV4> controllerV4Map = new HashMap<>();

    public FrontControllerServletV4() {
        controllerV4Map.put("/front-controller/v4/members/new-form", new MemberFormControllerV4());
        controllerV4Map.put("/front-controller/v4/members/save", new MemberSaveControllerV4());
        controllerV4Map.put("/front-controller/v4/members", new MemberListControllerV4());
    }

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        String requestURI = request.getRequestURI();// 들어온 URL을 얻을 수 있다.

        ControllerV4 controller = controllerV4Map.get(requestURI); // 요청 온 URI에 의해 Controller 객체가 다르게 호출
        if(controller == null){ // 읽어온 URI에 매치되는 Controller 객체가 없다면
            response.setStatus(HttpServletResponse.SC_NOT_FOUND); // 404 Not Found
            return;
        }

        // paramMap 넘겨주기 ( request 파라미터 다 읽어와 map에 저장)
        Map<String, String> paramMap = createParamMap(request);
        Map<String, Object> model = new HashMap<>(); // 추가
        String viewName = controller.process(paramMap, model);

        MyView view = viewResolver(viewName);

        view.render(model, 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> paramMap = new HashMap<>();
        request.getParameterNames().asIterator()
                .forEachRemaining(paramName -> paramMap.put(paramName, request.getParameter(paramName)));
        return paramMap;
    }
}

 

이전에 작성된 코드와 크게 다를 건 없다. 30번 라인에 아래 코드만 추가 되었다.

Map<String, Object> model = new HashMap<>() 

 

Controller에서 로직을 수행하고 그 결과를 담을 model을 FrontController에서 미리 생성하고

그것을 매개변수로 넘어주기만 할 뿐이다.

컨트롤러에서 모델 객체에 값을 담으면 여기에 그대로 담겨있게 된다

 

 

 

 


 

 

이번 버전의 컨트롤러는 매우 단순하고 실용적이다.

기존 구조에서 모델을 파라미터로 넘기고, 뷰의 논리 이름을 반환한다는 아이디어 일뿐이다.

 

 

구조는 어느 정도 완성이 되어가고 있다. 하지만 사소한 문제점이 하나 더 남아있다.

만약 동료 개발자와 협업을 할 경우, 각자 입맛에 맞는 controller들을 사용하고자 할 때는 어떻게 해결할까?

 

 

다음 포스팅에선 위 문제점을 해결하고자 어댑터 패턴을 적용해보도록 하자.

 

반응형