[Spring] 프론트 컨트롤러(Front Controller) 패턴

2023. 5. 24. 15:02·Spring/개념

프론트 컨트롤러란?


  • 서블릿 하나로 클라이언트의 요청을 다 받아서 공통 처리를 중복없이 하기 위해 사용된다.
  • 이후 나머지 컨트롤러들은 서블릿이 사용하지 않는다.
    프론트 컨트롤러가 요청을 받고 응답하기 때문이다. 즉, 프론트 컨트롤러가 받아서 다른 컨트롤러를 사용하기 때문이다.
  • 스프링도 DispatcherServlet이 FrontController이다.

 

기존의 패턴을 설명하자면 아래 그림과 같다

각 클라이언트들은 Controller A, B, C에 대해 각각 호출한다.

공통 코드들은 별도로 처리되어 있지 않고 각 Controller에 포함되어 있다.

 

하지만 프론트 컨트롤러 패턴을 도입한다면?

각 클라이언트들은 Front Controller에 요청을 보내고, Front Controller은 각 요청에 맞는 컨트롤러를 찾아서 호출시킨다.

공통 코드에 대해서는 Front Controller에서 처리하고, 서로 다른 코드들만 각 Controller에서 처리할 수 있도록 한다.

 

장점을 정리해보자면,

  • 공통 코드 처리가 가능 
  • Front Controller 외 다른 Controller에서 Servlet 사용하지 않아도 됨

 

스프링 웹 MVC의 핵심도 위 같은 FrontController이다.

(스프링 웹 MVC의 DispatcherServlet이 FrontController 패턴으로 구현되어 있음)

 

 

구조 살펴 보기

구조를 살펴보면 아래와 같다.

  1. 프론트 컨트롤러에 요청이 온다.
    → 프론트 컨트롤러는 HttpServlet을 상속 받는다.
  2. 프론트 컨트롤러는 컨트롤러들의 URL 관련 정보들을 갖고 있는데 여기서 조회를 한다.
    → Interface에 컨트롤러들을 Map으로 갖고 있다.
  3. 매핑된 컨트롤러를 호출한다.
  4. 매핑된 컨트롤러는 공통 로직 이외의 본인의 역할을 수행한다.

 

 

이제 간단한 예제를 통해 Front Controller에 대해 파악해보자.

 

 

ControllerV1

public interface ControllerV1 {
	void process(HttpServletRequest req, HttpServletResponse res) throws ServletException,IOException;
}

 

MemberFormControllerV1

public class MemberFormControllerV1 implements ControllerV1{
	@Override
	public void process(HttpServletRequest req, HttpServletResponse res) throws ServletException,IOException {
		String viewPath = "/WEB-INF/views/new-form.jsp";	 
		RequestDispatcher dispatcher = req.getRequestDispatcher(viewPath); 
		dispatcher.forward(req, res);
	}
}

 

MemberSaveControllerV1

public class MemberSaveControllerV1 implements ControllerV1{
	MemberRepository memberRepository = MemberRepository.getInstance();
	
	@Override
	public void process(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		String username = req.getParameter("username");
		int age = Integer.parseInt(req.getParameter("age"));
		
		Member member = new Member(username, age);
		memberRepository.save(member);
		req.setAttribute("member", member);
		
		String viewPath = "/WEB-INF/views/save-result.jsp";	
		RequestDispatcher dispatcher = req.getRequestDispatcher(viewPath); 
		dispatcher.forward(req, res);
	}
}

 

MemberListControllerV1

public class MemberListControllerV1 implements ControllerV1{
	MemberRepository memberRepository = MemberRepository.getInstance();
	
	@Override
	public void process(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		List<Member> members = memberRepository.findAll();
		req.setAttribute("members", members);
		
		String viewPath = "/WEB-INF/views/members.jsp";	
		RequestDispatcher dispatcher = req.getRequestDispatcher(viewPath); 
		dispatcher.forward(req, res);	
	}
}

 

MemberFormControllerV1, MemberSaveControllerV1, MemberListControllerV1는 ControllerV1 인터페이스를 구현한 구체 컨트롤러다.

 

이제 가장 중요한 Front Controller를 생성해보자.

 

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 req, HttpServletResponse res) throws ServletException, IOException {
		System.out.println("FrontControllerServletV1.service");
		
		String reqURI = req.getRequestURI();
		ControllerV1 controller = controllerMap.get(reqURI);
		
		if(controller == null) {
			res.setStatus(HttpServletResponse.SC_NOT_FOUND);
			return;
		}
		
		controller.process(req, res);
	}
}
  • urlPatterns = "/front-controller/v1/*": front-controller/v1 하위의 모든 항목에 대해 해당 서블릿 실행
  • 생성자: 각 url에 대해 Controller를 매핑하기 위해 Map에 데이터를 put
  • request에 대한 URI 값을 가져와서 controllerMap에서 어떤 컨트롤러에 매핑 되었는지 찾는다
  • 만약 controller가 존재하지 않는다면 404 에러 처리

 

이제 위에서 살펴봤던 그림을 예제 코드를 짚어가며 다시 보자

각 클라이언트들은 /front-controller/v1 하위의 어떤 경로를 접속하던간에 Front Controller으로 이동한다.

 

예를 들어, localhost:8080/front-controller/v1/members에 접속했다고 가정하자.

  1. @WebServlet의 urlPatterns에 의해 FrontControllerServletV1으로 이동
  2. 접속한 URI를 받고, ControllerV1 controller 변수에 MemberListControllerV1 저장 (Map에서 꺼내옴)
  3. MemberListControllerV1의 process 실행

 

위 예제는 아직 모든 Controller에서 RequestDispatcher을 이용해 view로 이동한다는 코드가 계속 반복되고 있다.

하지만 모든 요청이 Front Contoller를 통해 구체적인 컨트롤러들이 실행된다는 것은 파악할 수 있을 것이다.

 

 

스프링는 프론트 컨트롤러 패턴을 따르고 이를 DispatcherServlet이 담당한다.
DispatcherServlet은 클라이언트의 요청을 먼저 받아 필요한 처리를 한 뒤, 개발자가 구현한 요청에 맞는 핸들러에게 요청을 Dispatch하고 해당 핸들러의 실행 결과를 Response형태로 만드는 역할을 한다.

 

 

 


참고

  • https://www.youtube.com/watch?v=2pBsXI01J6M&t=185s
    https://www.youtube.com/watch?v=calGCwG_B4Y&t=2s
  • https://velog.io/@suhongkim98/Front-Controller-%ED%8C%A8%ED%84%B4%EA%B3%BC-spring-MVC
  • https://yeonyeon.tistory.com/103
'Spring/개념' 카테고리의 다른 글
  • [Spring] Dispatcher-Servlet(디스패처 서블릿)이란? 디스패처 서블릿의 개념과 동작 과정
  • [Spring] Spring MVC Framework란? Spring MVC 구조, DispatcherServlet, 핸들러 매핑, 핸들러 어댑터
  • [Spring] 서블릿(Servlet)이란? 서블릿 컨테이너란?
  • [Spring] MVC 패턴이란?
s_y_130
s_y_130
  • s_y_130
    About SY
    s_y_130
  • 전체
    오늘
    어제
    • 분류 전체보기 (436) N
      • JAVA (54)
        • 더 자바 8 (0)
        • JAVA (41)
        • JAVA (JVM) (13)
      • Computer Science (86)
        • CS Basic (7)
        • OOP (11)
        • Design Pattern (16)
        • Network (8)
        • HTTP (6)
        • WEB (22)
        • OS (16)
      • DataBase (29)
        • DB theory (15)
        • MySQL (14)
        • Redis (0)
      • Collection Framework (1)
        • 구현 (1)
      • Data Structure (14)
        • Linear (9)
        • Non-Linear (5)
      • Algorithm (19)
        • Basic (12)
        • 응용 (2)
        • 완전 탐색(Brute Force) (1)
        • 다익스트라 (1)
        • Algorithm Problem (3)
      • Spring (104)
        • 스프링 핵심 원리 - 기본편 (9)
        • 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 (7)
        • 스프링 MVC 2편 - 백엔드 웹 개발 핵심 기술 (11)
        • 스프링 DB 1편 - 데이터 접근 핵심 원리 (6)
        • 스프링 DB 2편 - 데이터 접근 활용 기술 (10)
        • 스프링 핵심 원리 - 고급편 (13)
        • 스프링 부트 - 핵심 원리와 활용 (9)
        • Spring Security 6.x (2)
        • Spring Batch (2)
        • Spring Cloud로 개발하는 MSA (1)
        • 재고시스템으로 알아보는 동시성이슈 해결방법 (4)
        • 개념 (27)
        • 테스트 (0)
        • Annotation (1)
        • Error Log (2)
      • TEST (0)
        • 부하 테스트 (0)
        • Practical Testing: 실용적인 테스트.. (0)
      • JPA (40)
        • 자바 ORM 표준 JPA 프로그래밍 (12)
        • 1편- 실전! 스프링 부트와 JPA 활용 (7)
        • 2편- 실전! 스프링 부트와 JPA 활용 (4)
        • 실전! 스프링 데이터 JPA (6)
        • 실전! Querydsl (6)
        • 개념 (5)
      • 백엔드 부트캠프[사전캠프] (35)
        • TIL (12)
        • 문제풀이 (23)
      • 백엔드 부트캠프 (5) N
        • Calculator (3)
        • Kiosk (2) N
      • Open Source (0)
      • Book Study (1)
        • Morden Java in Action (1)
        • Real MySQL 8.0 Vol.1 (0)
        • TDD : By Example (0)
      • AWS (0)
        • EC2 (0)
      • git (2)
      • AI (22)
        • Machine Learning (17)
        • Deep Learning (0)
        • TensorFlow (1)
        • PyTorch (1)
        • YOLO (1)
        • Data Analysis (0)
        • Ai code Error (1)
        • Numpy (1)
      • MY (0)
      • WEB (15)
        • Django (3)
        • WEB 개념 (1)
        • React (1)
        • Maven (10)
      • Python (6)
      • 기초수학 (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
s_y_130
[Spring] 프론트 컨트롤러(Front Controller) 패턴
상단으로

티스토리툴바