서블릿 종속성 제거
요청 파라미터 정보는 Map으로 넘기도록 하면 현재 구조에서는 Controller가 서블릿 기술을 몰라도 동작할 수 있다.
request 객체를 Model로 사용하는 대신 별도의 Model 객체를 만들어서 반환하면 된다.
현재는 request객체 내부 저장소를 Model처럼 사용하고 있음.
Controller가 서블릿 기능을 전혀 사용하지 않도록 변경해보자
뷰 이름 중복 제거
Controller 에서 지정하는 뷰 이름에 중복이 있음.
Controller는 뷰의 논리 이름을 반환하고, Front Controller에서 이를 실제 위치로 처리하도록 단순화
Front Controller에서 처리하도록 만들면, 뷰의 폴더 위치가 변해도 Front Controller만 변경하면 되므로 훨씬 코드의 유지보수가 단순화된다.
ModelView
Controller 인터페이스
- Controller는 서블릿 기능을 사용하지 않으므로 서블릿에 종속적이지 않음
회원 폼 컨트롤러
회원 저장 컨트롤러
회원 목록 컨트롤러
논리적 이름을 MovelView에 담아 렌더링하여 뷰를 호출하는 식으로 동작하는데
model을 Map으로 만들어 사용하기 때문에 게터를 통해 model을 가져와 그 안에 저장한 회원이나 회원 목록들을 담아 반환해주는 것이다.
Front Controller
package hello.servlet.web.frontcontroller.v3;
import hello.servlet.web.frontcontroller.ModelView;
import hello.servlet.web.frontcontroller.MyView;
import hello.servlet.web.frontcontroller.v2.ControllerV2;
import hello.servlet.web.frontcontroller.v2.controller.MemberFormControllerV2;
import hello.servlet.web.frontcontroller.v2.controller.MemberListControllerV2;
import hello.servlet.web.frontcontroller.v2.controller.MemberSaveControllerV2;
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 {
String requestURI = request.getRequestURI();
ControllerV3 controller = controllerMap.get(requestURI);
if (controller == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
//paramMap을 넘겨줘야함
Map<String, String> paramMap = createParamMap(request);
ModelView mv = controller.process(paramMap);
MyView view = viewResolver(mv);
view.render(mv.getModel(), request, response);
}
private MyView viewResolver(ModelView mv) {
return new MyView("/WEB-INF/views/" + mv.getViewName() + ".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;
}
}
HttpServletRequest에서 파라미터 정보를 꺼내어 Map으로 변환하는 것을 CreateParamMap메소드에서 처리하고 해당 Map을 컨트롤러에 전달하면서 호출한다.
MyView 수정
ViewResolver 메소드를 통해 논리 이름을 물리적 주소로 변경해주어 렌더링을 해준다.
렌더링을 할때는 모델을 같이 담아 보내야하므로 model에 담겨있는 값을 꺼내 request.setAttribute를 통해 request에 담아 view를 호출한다.
오히려 복잡해진 것처럼 보이지만 컨트롤러가 서블릿에 종속적이지 않게되면서 각 컨트롤러 구현체가 굉장히 가독성이 높아지고 단순해진다.
반응형
'Spring > Spring MVC' 카테고리의 다른 글
유연한 컨트롤러 (0) | 2021.04.28 |
---|---|
단순하고 실용적인 컨트롤러 (0) | 2021.04.21 |
View 분리 (0) | 2021.04.14 |
프론트 컨트롤러 패턴 (0) | 2021.04.13 |
MVC Pattern (0) | 2021.04.10 |