일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 백준
- HttpServletResponse
- 인터페이스
- 추상클래스
- equals()
- 참조변수
- 테스트코드
- DI
- 코드트리
- 오버라이딩
- 스프링
- 다형성
- 의존관계
- 김영한
- fielderror
- 코드트리조별과제
- 코딩테스트
- 싱글톤
- java
- http 메시지 컨버터
- ocp
- objecterror
- JSON
- 서블릿
- 티스토리챌린지
- 오블완
- html form
- 프록시
- @configuration
- 스프링컨테이너
- Today
- Total
minOS
MVC 프레임워크 만들기 - 프론트 컨트롤러 Ver 3 본문
Model 추가 - ver3
서블릿 종속성 제거
컨트롤러 입장에서 HttpServletRequest, HttpServletResponse이 꼭 필요할까?
1) 요청 파라미터 정보를 자바의 Map으로 대신 넘기도록 하면 지금 구조에서는 컨트롤러가 서블릿 기술을 몰라도 동작할 수 있다. 2) request 객체를 Model로 사용하는 대신에 별도의 Model 객체를 만들어서 반환하면 된다. 우리가 구현하는 컨트롤러가 서블릿 기술을 전혀 사용하지 않도록 변경해보자. 이렇게 하면 구현 코드도 매우 단순해지고, 테스트 코드 작성이 쉽다.
뷰 이름 중복 제거
컨트롤러에서 지정하는 뷰 이름에 중복이 있는 것을 확인할 수 있다.
컨트롤러는 뷰의 논리 이름 을 반환하고, 실제 물리 위치의 이름은 프론트 컨트롤러에서 처리하도록 단순화 하자. 이렇게 해두면 향후 뷰의 폴더 위치가 함께 이동해도 프론트 컨트롤러만 고치면 된다.
ex)/WEB-INF/views/new-form.jsp -> new-form`
/WEB-INF/views/save-result.jsp -> save-result
VER 3 구조
ModelView지금까지 컨트롤러에서 서블릿에 종속적인 HttpServletRequest를 사용했다. 그리고 Model도 `request.setAttribute()` 를 통해 데이터를 저장하고 뷰에 전달했다.
서블릿의 종속성을 제거하기 위해 Model을 직접 만들고, 추가로 View 이름까지 전달하는 객체를 만들어보자.
@Getter @Setter public class ModelView { private String viewName; private Map<String,Object> Model = new HashMap<>(); public ModelView(String viewName) { this.viewName = viewName; } }
뷰의 이름과 뷰를 렌더링할 때 필요한 model 객체를 가지고 있다. model 은 map으로 되어 있으므로 컨트롤러에서 뷰에 필요한 데이터를 key ,value로 넣어주면 된다.
Controller Ver3public interface ControllerV3 { ModelView process(Map<String,String> paramMap); //서블릿에 종속적이지 않음 }
이 컨트롤러는 서블릿 기술을 전혀 사용하지 않는다. (ver2 는 사용) 따라서 구현이 매우 단순해지고 , 테스트 코드 작성이 쉽다.
HttpServletRequest가 제공하는 파라미터는 프론트 컨트롤러가 paramMap에 담아서 호출해주면 된다.
응답 결과로 뷰 이름과 뷰에 전달할 Model 데이터를 포함하는 ModelView 객체를 반환한다.MemberFormControllerVer3 - 회원 등록 폼
public class MemberFormControllerV3 implements ControllerV3 { @Override public ModelView process(Map<String, String> paramMap) { return new ModelView("new-form"); } }
ModelView 를 생성할때 "new-form"이라는 viewName을 지정한다.(논리 이름)
실질적인 물리적인 이름은 프론트 컨트롤러에서 처리한다. 모델 뷰 반환MemberSaveControllerV3 - 회원 저장
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; } }
paramMap.get("username");
- 파라미터 정보는 map에 담겨있다. map에서 필요한 요청 파라미터를 조회하면 된다.mv.getModel().put("member", member);
-모델은 단순한 map이므로 모델에 뷰에서 필요한 "member" 객체를 담고 모델 뷰 반환한다.FrontControllerServletV3
@WebServlet(name="frontControllerServletV3",urlPatterns = "/front-controller/v3/*") public class FrontControllerServletV3 extends HttpServlet { //key == url , value = controller 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); String viewName = mv.getViewName();// 논리이름 -> new-form MyView view = viewResolve(viewName); view.render(mv.getModel(),request,response); } private static MyView viewResolve(String viewName) { return new MyView("/WEB-INF/views/" + viewName + ".jsp"); } private static 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; } }
createParamMap()
HttpServletRequest에서 파라미터 정보를 꺼내서 Map으로 변환한다. 그리고 해당 Map( `paramMap` )을 컨트롤러 에 전달하면서 호출한다.
뷰 리졸버
MyView view = viewResolver(viewName)
컨트롤러가 반환한 논리 뷰 이름을 실제 물리 뷰 경로로 변경한다. 그리고 실제 물리 경로가 있는 MyView 객체를 반환 한다.
view.render(mv.getModel(), request, response)`
- 뷰 객체를 통해서 HTML 화면을 렌더링 한다.
- 뷰 객체의 `render()` 는 모델 정보도 함께 받는다.
- JSP는 `request.getAttribute()` 로 데이터를 조회하기 때문에, 모델의 데이터를 꺼내서- request.setAttribute()` 로 담아둔다. JSP로 포워드 해서 JSP를 렌더링 한다.
'TIL > 김영한의 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술' 카테고리의 다른 글
MVC 프레임워크 만들기 - 프론트 컨트롤러 Ver 5 (0) | 2024.07.11 |
---|---|
MVC 프레임워크 만들기 - 프론트 컨트롤러 Ver 4 (0) | 2024.07.11 |
MVC 프레임워크 만들기 - 프론트 컨트롤러 Ver 2 (0) | 2024.06.29 |
MVC 프레임워크 만들기 - 프론트 컨트롤러 Ver 1 (0) | 2024.06.29 |
MVC 프레임워크 만들기 - 프론트 컨트롤러 도입 (0) | 2024.06.29 |