Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- JPQL
- Thymeleaf
- 알고리즘
- SpringBoot
- 스프링
- transaction
- AOP
- Exception
- db
- kotlin
- 스프링 핵심 원리
- 그리디
- QueryDSL
- Android
- Greedy
- spring
- Proxy
- Spring Boot
- Servlet
- http
- java
- jpa
- 자바
- JDBC
- 백준
- springdatajpa
- 스프링 핵심 기능
- 김영한
- pointcut
- 인프런
Archives
- Today
- Total
개발자되기 프로젝트
Model 추가 : v3 본문
1. Servlet 종속성 제거
- Controller입장에서 HttpServletRequest, HttpServletReponse가 필요할까..?
- Controller는 파라미터 정보만 필요하다.
- Request객체를 model 객체로 대체해보자.
- 그러면 Controller는 Servlet 기술에 대한 의존성이 없다. ㄱㅇㄷ
2. 뷰 이름 중복 제거
컨트롤러는 뷰의 논리 이름을 반환하고,
실제 물리 위치의 이름은 프론트 컨트롤러에서 처리하도록 단순화
이렇게 하면 나중에 폴더 위치가 이동해서 frontcontroller만 고치면됨 ㄱㅇㄷ~
- /WEB-INF/views/new-form.jsp --> new-form
- /WEB-INF/views/save-result.jsp --> save-result
- /WEB-INF/views/members.jsp --> members
3. v3 구조
4. ModelView
- 이전에는 컨트롤러에서 서블릿에 종속적인 HttpServletRequest를 사용함.
- 그리고 Model은 request.setAttribute() 를 통해 데이터를 저장하고 뷰에 전달했음
- 서블릿의 종속성을 제거하기 위해 Model을 직접 만들고,
- 추가로 View 이름까지 전달하는 객체를 만들자.
- 뷰의 이름과 뷰를 렌더링할 때 필요한 model 객체를 가지고 있다.
- model은 단순히 map으로 되어 있으므로 컨트롤러에서 뷰에 필요한 데이터를 key, value로 넣어주면 된다.
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;
}
}
5. ControllerV3 Interface
- paramMap을 받음
- ModelView객체를 반환
- 이 컨트롤러는 서블릿 기술을 전혀 사용하지 않는다.
- 따라서 구현이 매우 단순해지고, 테스트 코드 작성시 테스트 하기 쉽다.
- HttpServletRequest가 제공하는 파라미터는 프론트 컨트롤러가 paramMap에 담아서 호출해주면 된다.
- 응답 결과로 뷰 이름과 뷰에 전달할 Model 데이터를 포함하는 ModelView 객체를 반환하면 된다.
public interface ControllerV3 {
ModelView process(Map<String, String> paramMap);
}
6. FrontController
- HttpServletRequest로 넘어온 request정보를 가지고 pramMap<String,String>을 만듦.
- ex -> "username" : "kim"
- 각 Controller에서 return한 ModelView객체의 viewName(논리이름) 꺼냄.
- 논리 이름을 가지고 물리 이름으로 변경한 MyView 생성.
- MyView의 render() 에 model, request, reponse객체 넘겨줌.
- view에서 jsp로 이동함.
@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;
}
Map<String, String> paramMap = createParamMap(request);
ModelView mv = controller.process(paramMap);
//논리 이름을 물리 이름으로 바꾸기
String viewName = mv.getViewName();
MyView view = viewResolver(viewName);
//모델은 render에 넘겨줘야함.
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) {
//paramMap
Map<String, String> paramMap = new HashMap<>();
request.getParameterNames().asIterator()
.forEachRemaining(paramName -> paramMap.put(paramName, request.getParameter(paramName)));
return paramMap;
}
}
- 뷰 리졸버
- MyView view = viewResolver(viewName)
- 컨트롤러가 반환한 논리 뷰 이름을 실제 물리 뷰 경로로 변경한다.
- 그리고 실제 물리 경로가 있는 MyView 객체를 반환한다.
- 논리 뷰 이름: members
- 물리 뷰 경로: /WEB-INF/views/members.jsp
- view.render(mv.getModel(), request, response)
- 뷰 객체를 통해서 HTML 화면을 렌더링 한다. 뷰 객체의 render() 는 모델 정보도 함께 받는다.
- JSP는 request.getAttribute() 로 데이터를 조회하기 때문에,
- 모델의 데이터를 꺼내서 request.setAttribute() 로 담아둔다.
- JSP로 포워드 해서 JSP를 렌더링 한다.
- render()에 model을 넘겨주면 request에 담아줘야함.
- JSP는 request객체에 setAttribute를 해줘야 사용할 수 있음.
public void render(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
modelToRequestAttribute(model, request);
RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath);
dispatcher.forward(request,response);
}
private void modelToRequestAttribute(Map<String, Object> model, HttpServletRequest request) {
model.forEach((key, value) -> request.setAttribute(key, value));
}
7. MemberFormControllerv3
- ModelView 객체에 jsp 논리이름 넣어서 return
- ModelView 를 생성할 때 new-form 이라는 view의 논리적인 이름을 지정한다.
- 실제 물리적인 이름은 프론트 컨트롤러에서 처리한다.
public class MemberFormControllerV3 implements ControllerV3 {
@Override
public ModelView process(Map<String, String> paramMap) {
return new ModelView("new-form");
}
}
8. MemberSaveControllerV3
- 넘어온 paramMap을 사용하여 Member 객체 생성 및 save.
- jsp 논리 이름을 사용하여 ModelView 객체 생성
- ModelView객체의 model에 member 넣기.
- ModelView 객체 return.
- paramMap.get("username");
- 파라미터 정보는 map에 담겨있다. map에서 필요한 요청 파라미터를 조회하면 된다.
- mv.getModel().put("member", member);
- 모델은 단순한 map이므로 모델에 뷰에서 필요한 member 객체를 담고 반환한다.
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;
}
}
9. ModelListControllerV3
- paramMap으로 넘어온 정보를 가지고 findAll실행.
- jsp의 논리 이름을 가지고 ModelView객체 생성.
- ModelView 객체의 model에 members 넣기.
- ModelView 객체 return
public class MemberListControllerV3 implements ControllerV3 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public ModelView process(Map<String, String> paramMap) {
List<Member> members = memberRepository.findAll();
ModelView mv = new ModelView("members");
mv.getModel().put("members", members);
return mv;
}
}
10. 실행
- localhost:8080/front-controller/v3/members/new-form 접속
- frontCtonroller에서 controllerMap을 통해 uri에 해당하는 Controller 확인.
- -->MemverFormControllerV3
- HttpServletRequest에 담긴 request정보를 가지고 paramMap을 생성.
- controller.process()에 pramMap 넘겨줌.
- controller는 model과 view의 논리이름이 담긴 ModelView객체 반환.
- FrontController는 넘어온 논리이름을 가지고 물리이름이 담긴 MyView객체 생성.
- FrontController는 MyView객체의 render실행을 위해
- ModelView객체의 model, HttpServlerRequest 객체, HttpServletResponse객체를 넘김.
- MyView객체는 넘어온 model정보를 request.setAttribute를 통해 request에 정보를 담음.
- MyView객체는 가지고있는 jsp 물리이름, request, response 객체를 가지고 JSP로 이동 -> HTML응답.
11. GitHub : 210911 FrontController V3
'인프런 > [인프런] 스프링 MVC 1' 카테고리의 다른 글
Controller V5 -1 (0) | 2021.09.11 |
---|---|
Controller V4 (0) | 2021.09.11 |
Controller->view이동 분리 : V2 (0) | 2021.09.11 |
FrontController 도입 : v1 (0) | 2021.09.10 |
Front Controller 패턴 (0) | 2021.09.10 |
Comments