김영한님의 스프링 MVC 1편 강의를 듣고 복습 겸 정리하는 포스팅입니다!!
아직 공부하는 중인 학생이라 부족한 부분이 있을 수 있습니다.
혹시라도 틀린 부분이 있다면 언제든지 댓글로 남겨주세요. 감사합니다 🙇♂️
섹션 5. 단순하고 실용적인 컨트롤러 -V4
[이전 버전]
https://lyjduswls.tistory.com/56
[스프링 MVC] #6
김영한님의 스프링 MVC 1편 강의를 듣고 복습 겸 정리하는 포스팅입니다!!아직 공부하는 중인 학생이라 부족한 부분이 있을 수 있습니다. 혹시라도 틀린 부분이 있다면 언제든지 댓글로 남겨주세
lyjduswls.tistory.com
이전 단계 V3는 서블릿 종속성과 뷰 경로 중복을 제거한 구조적으로 잘 설계된 컨트롤러이다.
그러나 개발자 입장자 입장에서 매번 ModelView 객체를 생성하고 반환하는 부분이 다소 번거롭다.
좋은 프레임워크는 아키텍처도 중요하지만, 개발자가 실제로 사용하기에 단순하고 편리해야하며, 실용성 또한 갖추어야 한다.
이번 단계에서는 V3를 조금 변경해서 개발자들이 더욱 편리하게 컨트롤러를 구현할 수 있는 V4버전을 구현해보자.
V4 구조
- 클라이언트가 HTTP 요청을 전송한다.
- 프론트 컨트롤러가 매핑정보에 맞는 컨트롤러를 조회한다.
- 프론트 컨트롤러가 컨트롤러를 호출하면서 paramMap, model을 전달한다.
- 컨트롤러는 모델에 필요한 데이터를 담고, 논리 뷰 이름(viewName)만 반환한다.(기존에는 ModelView 객체를 반환했다.)
- 프론트 컨트롤러가 뷰 리졸버(viewResolver)를 호출해 논리 뷰 이름을 물리 경로로 변환한다.
- 뷰 리졸버는 실제 경로를 담은 MyView 객체를 반환한다.
- 프론트 컨트롤러가 MyView.render(model)을 호출한다.
- MyView 내부에서 JSP로 forward하여 HTML 응답을 생성하고 클라이언트에게 전달한다.
ControllerV4
package hello.servlet.web.frontcontroller.v4;
import java.util.Map;
public interface ControllerV4 {
/**
* @param paramMap
* @param model
* @return viewName
*/
String process(Map<String, String> paramMap, Map<String, Object> model);
}
위의 사진이 이전 단계인 ControllerV3이다.
이전 단계는 paramMap만 전달하고, ModelView 객체를 직접 생성해 반환해야 했다. 이번 버전은 인터페이스에 ModelView가 없다.
String process(Map<String, String> paramMap, Map<String, Object> model);
이제 model 객체도 파라미터로 함께 전달되며, 컨트롤러는 뷰 이름(String)만 반환하면 된다.
model은 프론트 컨트롤러가 생성해서 넘겨주는 비어 있는 Map 이며, 개발자가 model에 필요한 값을 put()으로 추가해 사용하면 된다.
MemberFormControllerV4- 회원 등록 폼 컨트롤러
package hello.servlet.web.frontcontroller.v4.controller;
import hello.servlet.web.frontcontroller.v4.ControllerV4;
import java.util.Map;
public class MemberFormControllerV4 implements ControllerV4 {
@Override
public String process(Map<String, String> paramMap, Map<String, Object> model) {
return "new-form";
}
}
위의 사진은 이전 단계인 V3 버전이다.
return new ModelView("new-form");
V3의 코드를 보면 ModelView 객체를 생성해 반환하고 있다. 그러나 V4에서는 객체를 만들 필요 없이 뷰의 논리 이름만 반환하면 된다.
또한 모델 객체도 프론트 컨트롤러에서 생성해 넘겨줄 것이기 때문에, 컨트롤러 내부에서 별도로 모델을 생성할 필요가 없다.
MemberSaveControllerV4- 회원 정보 저장 컨트롤러
package hello.servlet.web.frontcontroller.v4.controller;
import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
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";
}
}
위의 사진은 이전 단계인 V3 버전이다.
이전 단계에서는 ModelView 객체를 생성하고, 모델과 뷰의 이름을 설정해야 했다.
V4버전에서는 파라미터에서 값만 꺼내고, 비지니스 로직 처리한 뒤 모델에 put으로 데이터를 담고 논리 뷰 이름만 반환하면 된다.
이전 단계에 비해 코드가 훨씬 간단해졌다.
MembeListControllerV4- 회원 목록 조회 컨트롤러
package hello.servlet.web.frontcontroller.v4.controller;
import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import hello.servlet.web.frontcontroller.v4.ControllerV4;
import java.util.List;
import java.util.Map;
public class MemberListControllerV4 implements ControllerV4 {
private MemberRepository memberRepository = MemberRepository.getInstance();
@Override
public String process(Map<String, String> paramMap, Map<String, Object> model) {
List<Member> members = memberRepository.findAll();
model.put("members", members);
return "members";
}
}
FrontControllerServletV4
package hello.servlet.web.frontcontroller.v4;
import hello.servlet.web.frontcontroller.MyView;
import hello.servlet.web.frontcontroller.v4.controller.MemberFormControllerV4;
import hello.servlet.web.frontcontroller.v4.controller.MemberListControllerV4;
import hello.servlet.web.frontcontroller.v4.controller.MemberSaveControllerV4;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@WebServlet(name = "frontControllerServletV4", urlPatterns = "/front-controller/v4/*")
public class FrontControllerServletV4 extends HttpServlet {
private Map<String, ControllerV4> controllerMap = new HashMap<>();
public FrontControllerServletV4() {
controllerMap.put("/front-controller/v4/members/new-form", new MemberFormControllerV4());
controllerMap.put("/front-controller/v4/members/save", new MemberSaveControllerV4());
controllerMap.put("/front-controller/v4/members", new MemberListControllerV4());
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String requestURI = request.getRequestURI();
ControllerV4 controller = controllerMap.get(requestURI);
if(controller == null){
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
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 static MyView viewResolver(String viewName) {
MyView view = new MyView("/WEB-INF/views/" + viewName + ".jsp");
return view;
}
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;
}
}
프레임워크 입장에서는 거의 고친 것이 없는데 개발자 입장에서는 매우 편해졌다 !!
'Spring Study' 카테고리의 다른 글
[스프링 MVC] #9 (0) | 2025.05.14 |
---|---|
[스프링 MVC] #8 (0) | 2025.05.10 |
[스프링 MVC] #6 (1) | 2025.05.04 |
[스프링 MVC] #5 (1) | 2025.05.03 |
[스프링 MVC] #4 (0) | 2025.05.03 |