김영한님의 스프링 MVC 1편 강의를 듣고 복습 겸 정리하는 포스팅입니다!!
아직 공부하는 중인 학생이라 부족한 부분이 있을 수 있습니다.
혹시라도 틀린 부분이 있다면 언제든지 댓글로 남겨주세요. 감사합니다 🙇♂️
섹션 5. 프론트 컨트롤러 도입 - V1
프론트 컨트롤러 도입 전
- 공통 로직을 각각의 컨트롤러에 직접 삽입해야 한다.
- 공통으로 처리해야 하는 작업이 많아질수록 중복 코드가 증가한다.
- 유지보수가 어렵다.
프론트 컨트롤러 도입 후
프론트 컨트롤러 (FrontController)
- 프론트 컨트롤러도 하나의 서블릿이다. 이 서블릿이 클라이언트의 모든 요청을 받아 처리한다.
- 요청에 맞는 컨트롤러를 찾아 호출하는 역할이다.
- 프론트 컨트롤러를 제외한 나머지 컨트롤러는 서블릿을 사용하지 않아도 된다.
프론트 컨트롤러 도입 효과
- 공통 로직을 중앙에서 관리해 코드 중복이 사라진다.
- 나머지 컨트롤러는 비즈니스의 흐름만 신경쓰면 된다.
스프링 웹 MVC와 프론트 컨트롤러
- 스프링 웹 MVC의 핵심도 "FrontController"이다.
- 스프링 웹 MVC의 DispatcherServlet이 FrontController 패턴으로 구현되어 있다.
프론트 컨트롤러 도입 - v1
기존의 코드를 최대한 유지하면서, 프론트 컨트롤러를 도입
- 클라이언트가 HTTP 요청을 전송한다.
- FrontController(Servlet)가 요청을 받는다.
- 요청 URL 매핑 정보에서 해당 컨트롤러를 조회한다.
- 프론트 컨트롤러가 조회된 컨트롤러를 호출한다.
- 컨트롤러는 자신의 로직을 수행 후, JSP 경로를 반환한다.
- 프론트 컨트롤러는 jsp에 forword해서 HTML로 응답이 가게된다.
ControllerV1
package hello.servlet.web.frontcontroller.v1;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
public interface ControllerV1 {
void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
}
서블릿과 비슷한 모양의 컨트롤러 인터페이스를 도입한다. 각 컨트롤러들은 이 인터페이스를 구현한다.
일단 지금 단계에서는 기존 로직을 최대한 유지하는 것이 핵심이다.
MemberFormControllerV1 - 회원 등록 폼 컨트롤러
package hello.servlet.web.frontcontroller.v1.controller;
import hello.servlet.web.frontcontroller.v1.ControllerV1;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
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);
}
}
MemberSaveControllerV1 - 회원 정보 저장 컨트롤러
package hello.servlet.web.frontcontroller.v1.controller;
import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import hello.servlet.web.frontcontroller.v1.ControllerV1;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
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);
System.out.println("member = " + member);
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);
}
}
MemberListControllerV1 - 회원 목록 조회 컨트롤러
package hello.servlet.web.frontcontroller.v1.controller;
import hello.servlet.domain.member.Member;
import hello.servlet.domain.member.MemberRepository;
import hello.servlet.web.frontcontroller.v1.ControllerV1;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
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);
}
}
FrontControllerServletV1
package hello.servlet.web.frontcontroller.v1;
import hello.servlet.web.frontcontroller.v1.controller.MemberFormControllerV1;
import hello.servlet.web.frontcontroller.v1.controller.MemberListControllerV1;
import hello.servlet.web.frontcontroller.v1.controller.MemberSaveControllerV1;
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 = "frontControllerServletV1", urlPatterns = "/front-controller/v1/*") // 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
@WebServlet(name = "frontControllerServletV1", urlPatterns = "/front-controller/v1/*")
urlPatterns = "/front-controller/v1/*"로 설정하면, /front-controller/v1를 포함한 하위 모든 요청은 이 서블릿에서 받아들인다.
controllerMap
private Map<String, ControllerV1> controllerMap = new HashMap<>();
- key : 요청 URL
- value : 실행할 컨트롤러 인스턴스
매핑정보
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());
}
- /front-controller/v1/members/new-form → MemberFormControllerV1
- /front-controller/v1/members/save → MemberSaveControllerV1
- /front-controller/v1/members → MemberListControllerV1
실행한 후 회원가입 창에 들어간 모습이다.
1. 요청 URI 추출
String requestURI = request.getRequestURI();
Service의 requestURI를 통해 사진에 있는 상단의 url 주소 "/front-controller/v1/members/new-form"를 그대로 받을 수 있다.
2. 매핑 정보에서 컨트롤러 조회
ControllerV1 controller = controllerMap.get(requestURI);
controller.Map.get(requestURI)를 통해 상단의 주소를 찾을 수 있다.
"/front-controller/v1/members/new-form" -> MemberFormControllerV1() 반환
3. 컨트롤러가 없으면 404 응답
if(controller == null){
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
페이지가 없거나 못찾는 경우에는 404 에러를 띄우게 된다.
4. 컨트롤러 로직 실행
controller.process(request, response);
조회에 성공했다면 ControllerV1의 controller.process()를 호출하게 된다.
'Spring Study' 카테고리의 다른 글
[스프링 MVC] #6 (1) | 2025.05.04 |
---|---|
[스프링 MVC] #5 (1) | 2025.05.03 |
[스프링 MVC] #3 (2) | 2025.04.27 |
[스프링 MVC] #2 (0) | 2025.04.13 |
[스프링 MVC] #1 (0) | 2025.04.10 |