-
[스프링MVC - 1편] MVC 프레임워크 만들기 (1)스프링&스프링부트 2025. 1. 12. 13:27
프론트 컨트롤러 패턴 소개
프론트 컨트롤러 도입 전
프론트 컨트롤러 도입 후
FrontController 패턴 특징
- 프론트 컨트롤러 서블릿 하나로 클라이언트의 요청을 받음
- 프론트 컨트롤러가 요청에 맞는 컨트롤러를 찾아서 호출
- 입구를 하나로
- 공통 처리 가능
- 프론트 컨트롤러를 제외한 나머지 컨트롤러는 서블릿을 사용하지 않아도 됨
스프링 웹 MVC와 프론트 컨트롤러
스프링 웹 MVC의 핵심도 바로 FrontController이다
스프링 웹 MVC의 DispatcherServlet이 FrontController 패턴으로 구현되어 있다
프론트 컨트롤러 도입 - v1
[V1 구조 ]
1. ControllerV1
public interface ControllerV1 { void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException; }
서블릿과 비슷한 모양의 컨트롤러 인터페이스를 도입한다 (각 컨트롤러들은 이 인터페이스를 구현)
프론트 컨트롤러는 이 인터페이스를 호출해서 구현과 관계없이 로직의 일관성을 가져갈 수 있다
2. MemberFormControllerV1 - 회원 등록 컨트롤러
public class MemberFormControllerV1 implements ControllerV1 { @Override public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String viewPath = "/WEB-INF/views/new-form.jsp"; RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath); dispatcher.forward(request, response); } }
3. MemberSaveControllerV1 - 회원 저장 컨트롤러
public class MemberSaveControllerV1 implements ControllerV1 { private MemberRepository memberRepository = MemberRepository.getInstance(); @Override public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); int age = Integer.parseInt(request.getParameter("age")); Member member = new Member(username, age); memberRepository.save(member); // Model 데이터 보관 request.setAttribute("member", member); String viewPath = "/WEB-INF/views/save-result.jsp"; RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath); dispatcher.forward(request, response); } }
4. MemberListControllerV1 - 회원 목록 컨트롤러
public class MemberListControllerV1 implements ControllerV1 { private MemberRepository memberRepository = MemberRepository.getInstance(); @Override public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { List<Member> members = memberRepository.findAll(); request.setAttribute("members", members); String viewPath = "/WEB-INF/views/members.jsp"; RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath); dispatcher.forward(request, response); } }
5. FrontControllerServletV1 - 프론트 컨트롤러
@WebServlet(name="frontControllerServletV1", urlPatterns="/front-controller/v1/*") public class FrontControllerServletV1 extends HttpServlet { private Map<String, ControllerV1> controllerMap = new HashMap<>(); public FrontControllerServletV1() { controllerMap.put("/front-controller/v1/members/new-form", new MemberFormControllerV1()); controllerMap.put("/front-controller/v1/members/save", new MemberSaveControllerV1()); controllerMap.put("/front-controller/v1/members", new MemberListControllerV1()); } @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // System.out.println("FrontControllerServletV1.service"); String requestURI = request.getRequestURI(); ControllerV1 controller = controllerMap.get(requestURI); if (controller == null) { response.setStatus(HttpServletResponse.SC_NOT_FOUND); return; } controller.process(request, response); } }
프론트 컨트롤러 분석
- urlPatterns
- urlPatterns = "/front-controller/v1/* : /front-controller/v1를 포함한 하위 모든 요청은 이 서블릿에서 받아들인다
- controllerMap
- key : 매핑 URL
- value : 호출될 컨트롤러
- service()
- requestURI를 조회해서 실제 호출할 컨트롤러를 controllerMap에서 찾는다
- 컨트롤러를 찾고 controller.process(request, response);을 호출해서 해당 컨트롤러를 실행한다
- JSP - 동일
View 분리 - v2
String viewPath = "/WEB-INF/views/new-form.jsp"; RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath); dispatcher.forward(request, response);
모든 컨트롤러에서 뷰로 이동하는 부분에 중복이 있고, 깔끔하지 않다
이 부분을 깔끔하게 분리하기 위해 별도로 뷰를 처리하는 객체를 만든다
V2 구조
1. MyView
public class MyView { private String viewPath; public MyView(String viewPath) { this.viewPath = viewPath; } public void render(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { RequestDispatcher dispatcher = request.getRequestDispatcher(viewPath); dispatcher.forward(request, response); } }
2. ControllerV2
public interface ControllerV2 { MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException; }
3. MemberFormControllerV2 - 회원 등록 폼
public class MemberFormControllerV2 implements ControllerV2 { @Override public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { return new MyView("/WEB-INF/views/new-form.jsp"); } }
4. MemberSaveControllerV2 - 회원 저장
public class MemberSaveControllerV2 implements ControllerV2 { private MemberRepository memberRepository = MemberRepository.getInstance(); @Override public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); int age = Integer.parseInt(request.getParameter("age")); Member member = new Member(username, age); memberRepository.save(member); // Model 데이터 보관 request.setAttribute("member", member); return new MyView("/WEB-INF/views/save-result.jsp"); } }
5. MemberListControllerV2 - 회원 목록
public class MemberListControllerV2 implements ControllerV2 { private MemberRepository memberRepository = MemberRepository.getInstance(); @Override public MyView process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { List<Member> members = memberRepository.findAll(); request.setAttribute("members", members); return new MyView("/WEB-INF/views/members.jsp"); } }
6. 프론트 컨트롤러 V2
@WebServlet(name="frontControllerServletV2", urlPatterns="/front-controller/v2/*") public class FrontControllerServletV2 extends HttpServlet { private Map<String, ControllerV2> controllerMap = new HashMap<>(); public FrontControllerServletV2() { controllerMap.put("/front-controller/v2/members/new-form", new MemberFormControllerV2()); controllerMap.put("/front-controller/v2/members/save", new MemberSaveControllerV2()); controllerMap.put("/front-controller/v2/members", new MemberListControllerV2()); } @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String requestURI = request.getRequestURI(); ControllerV2 controller = controllerMap.get(requestURI); if (controller == null) { response.setStatus(HttpServletResponse.SC_NOT_FOUND); return; } MyView view = controller.process(request, response); view.render(request, response); } }
728x90'스프링&스프링부트' 카테고리의 다른 글
[스프링MVC - 1편] MVC 프레임워크 만들기 (3) (0) 2025.01.12 [스프링MVC - 1편] MVC 프레임워크 만들기 (2) (0) 2025.01.12 [스프링MVC - 1편] MVC 패턴 적용, 한계 (0) 2025.01.12 [스프링MVC - 1편] MVC 패턴 개요 (0) 2025.01.11 [스프링MVC - 1편] JSP 회원관리 웹 애플리케이션 만들기 (0) 2025.01.11