Skip to Content
공부백엔드Servlet과 웹 서버4. Front Controller Pattern

Front Controller Pattern

모든 요청을 하나의 컨트롤러가 받아서 처리하는 디자인 패턴이다. Spring MVC의 DispatcherServlet이 바로 이 패턴을 사용한다.

패턴의 탄생 배경

초기 웹 개발에서는 CGI(Common Gateway Interface) 방식으로 각 요청마다 새로운 프로세스를 생성했다. Servlet은 이를 개선했지만, 여전히 요청마다 별도의 Servlet이 필요했다. Front Controller 패턴은 이러한 문제를 해결하기 위해 등장했다.

기존 서블릿 작성 방식의 문제점

  • 사용자의 요청과 이를 처리하는 Servlet이 1:1 매칭됨
    • 요청이 추가될 때마다 매번 새로운 Servlet 생성 필요
    • 동일한 루틴으로 서블릿 생성 필요 (상속, 메서드 재정의 등)
  • 개별 서블릿에서
    • 비즈니스 로직과 함께 로깅, 예외 처리, 응답 처리 방식 등을 함께 처리: 코드의 중복 발생
    • 서블릿마다 요청 처리 과정이 흩어져 있어 복잡성이 증가하고 유지보수가 어려워짐

Front Controller Pattern이란?

Front Controller = 전면에서 모든 요청을 받아들이는 Servlet

장점

  • 단일 진입점: 모든 요청을 front controller에서 접수하므로 요청 처리의 일관성
  • 공통 처리: 모든 작업이 front controller를 거쳐감
    • 필요한 전/후 작업 (인증, 권한 검사, 로깅 등)의 일괄 처리 가능
  • 유연한 확장성: 새로운 요청 처리를 추가할 때 기존의 구조를 크게 변경하지 않고도 쉽게 확장 가능
  • 코드 간결성: 여러 개의 Servlet을 만드는 번거로움이 줄고 코드의 가독성도 향상

기본 Front Controller 구현

HashMap으로 URL과 Handler를 매핑하여 관리한다.

FrontController.java
@WebServlet("/app/*") // /app/* 로 들어오는 모든 요청 처리 public class FrontController extends HttpServlet { private Map<String, Handler> handlerMap; @Override public void init() throws ServletException { handlerMap = new HashMap<>(); // URL과 Handler 매핑 - HashMap으로 등록 handlerMap.put("/app/home", new HomeHandler()); handlerMap.put("/app/login", new LoginHandler()); handlerMap.put("/app/board/list", new BoardListHandler()); // 추가 매핑... } @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String uri = request.getRequestURI(); String mappingKey = uri.substring(request.getContextPath().length()); // 컨텍스트 경로 제거 try { // 1. 공통 전처리 (인코딩, 로깅 등) request.setCharacterEncoding("UTF-8"); // 응답 인코딩 설정 response.setContentType("text/html; charset=UTF-8"); // 2. Handler 찾기 Handler handler = handlerMap.get(mappingKey); if (handler == null) { response.sendError(404, "페이지를 찾을 수 없습니다"); return; } // 3. Handler 실행 String viewName = handler.handle(request, response); // 4. View 처리 if (viewName != null) { if (viewName.startsWith("redirect:")) { // 리다이렉트 String redirectUrl = viewName.substring(9); response.sendRedirect(request.getContextPath() + redirectUrl); } else { // JSP 포워드 String viewPath = "/WEB-INF/views/" + viewName + ".jsp"; request.getRequestDispatcher(viewPath).forward(request, response); } } } catch (Exception e) { e.printStackTrace(); response.sendError(500, "시스템 오류가 발생했습니다"); } } }

인코딩 처리 상세 설명

POST vs GET 인코딩 차이점

구분POST 요청GET 요청
한글 데이터 위치HTTP Body (form-data)URL Query String
인코딩 설정 방법request.setCharacterEncoding("UTF-8")WAS 설정 파일 (server.xml)
설정 시점getParameter() 호출 전WAS 시작 시
예시<form method="post">?name=홍길동&age=20

Tomcat server.xml 설정 예시

<!-- GET 요청의 한글 처리를 위한 설정 --> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8" /> <!-- GET 쿼리스트링 인코딩 -->

중요: request.getRequestURI()는 컨텍스트 경로(예: /myapp)를 포함하므로, 위 코드처럼 request.getContextPath() 길이만큼 잘라낸 값을 매핑 키로 사용해야 정확한 URL 패턴 매칭이 가능하다.

Handler 인터페이스

Handler.java
// Handler 인터페이스 public interface Handler { String handle(HttpServletRequest request, HttpServletResponse response) throws Exception; }
LoginHandler.java
// Handler 구현 예시 public class LoginHandler implements Handler { @Override public String handle(HttpServletRequest request, HttpServletResponse response) throws Exception { String method = request.getMethod(); if ("GET".equals(method)) { // 로그인 폼 표시 return "user/login"; } else if ("POST".equals(method)) { // 로그인 처리 로직 // 1. 파라미터 받기 // 2. 인증 처리 // 3. 세션 설정 // 4. 적절한 뷰 반환 return "redirect:/app/home"; } return null; } }

요청의 구분과 URL 매핑

WAS에서 들어온 요청을 어떻게 구분하고 처리할지 결정하는 것이 URL 매핑이다.

URL 매핑 전략

1. 쿼리 파라미터로 작업 지정

URL에 특정 작업을 의미하는 파라미터(예: action)를 추가하여 하나의 Servlet에서 여러 기능 처리

// /main?action=gugu&dan=3 // /main?action=hello // /main?action=add&num1=10&num2=20 @WebServlet("/main") public class MainServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) { String action = request.getParameter("action"); switch(action) { case "gugu": int dan = Integer.parseInt(request.getParameter("dan")); // 구구단 처리 break; case "hello": // 인사 처리 break; case "add": int num1 = Integer.parseInt(request.getParameter("num1")); int num2 = Integer.parseInt(request.getParameter("num2")); // 덧셈 처리 break; } } }

2. 와일드카드를 이용한 URL 매핑

URL 패턴특징예시경로 파악 방법
/main/*도메인(기능) 단위로 하위 모든 경로 수용/main/hello
/main/gugu?dan=3
getServletPath(): /main
getRequestURI(): 전체 경로
*.do확장자 기반 매핑
경로와 무관하게 .do로 끝나는 모든 요청 처리
/hello.do
/board/list.do
getServletPath(): 빈 문자열
getRequestURI(): 전체 경로
/매핑되지 않은 모든 요청의 폴백
(Default Servlet)
정적 리소스 처리
Spring MVC 기본 매핑
모든 요청 처리

와일드카드 매핑 예제

// 도메인 단위 매핑 @WebServlet("/board/*") public class BoardServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) { String uri = request.getRequestURI(); // /contextPath/board/list String contextPath = request.getContextPath(); // /contextPath String command = uri.substring(contextPath.length()); // /board/list if (command.equals("/board/list")) { // 게시글 목록 처리 } else if (command.equals("/board/write")) { // 게시글 작성 처리 } else if (command.equals("/board/view")) { // 게시글 조회 처리 } } }
// 확장자 기반 매핑 @WebServlet("*.do") public class ControllerServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) { String uri = request.getRequestURI(); // /contextPath/board/list.do String contextPath = request.getContextPath(); // /contextPath String command = uri.substring(contextPath.length()); // /board/list.do if (command.equals("/board/list.do")) { // 게시글 목록 처리 } else if (command.equals("/member/login.do")) { // 로그인 처리 } } }

URL 매핑 우선순위

Servlet Container는 다음 순서로 URL 패턴을 매칭한다:

  1. 정확한 매칭: /board/list (exact match)
  2. 경로 매칭: /board/* (longest path match)
  3. 확장자 매칭: *.do
  4. 기본 서블릿: /

도메인별 Front Controller

Front Controller라고 앞에서 모든 것을 처리하지 않음. 도메인별로 가져갈 수 있다.

  • Main Front Controller (/main/*, 일반 요청 처리)
  • Member Front Controller (/member/*, 멤버 관련 요청 처리)
  • Board Front Controller (/board/*, 게시판 관련 요청 처리)

MVC 패턴과의 관계

Front Controller는 MVC 패턴의 Controller 부분을 더 체계화한 것이다.

  • Model: 비즈니스 로직과 데이터
  • View: JSP, HTML 등 화면 처리
  • Controller: Front Controller + Handler들

정리

  • Front Controller 패턴은 모든 요청을 하나의 Servlet이 받아 처리
  • HashMap으로 URL과 Handler를 매핑하여 관리
  • 공통 로직을 한 곳에서 처리할 수 있어 유지보수가 용이
  • Spring MVC의 DispatcherServlet이 이 패턴을 사용
Last updated on