URL 라우팅 — 누가 어디로 보내는가

주소창에 뭔가를 입력했을 때, 서버 안에서 벌어지는 일을 아래 시뮬레이터로 직접 눌러봅시다. localhost:8081/test/ 뒤에 /, /login, /board 중 하나를 넣어보세요.

시뮬레이터

waiting

주소창에 경로를 입력해보세요

예: localhost:8081/test/, localhost:8081/test/login, localhost:8081/test/board

서버 내부에서 무슨 일이 일어났을까

1. 브라우저
-
2. Servlet
-
3. View (JSP)
-

URL을 바꿔가며 눌러보세요. 2번 노드의 Servlet 이름이 URL마다 달라진다는 점이 핵심입니다. 각 Servlet은 각각 독립된 Java 파일이고, 그 안에서 resp.sendRedirect("xxx.jsp") 로 브라우저에게 "이 JSP 보러 가" 라고 안내합니다.

핵심 개념: URL 하나 = Servlet 하나 = Java 파일 하나

학생이 가장 먼저 오해하는 지점: "/login 을 치면 login.jsp가 바로 열리는 거 아니에요?" 실제로는 그 사이에 Servlet(Java 파일)이 끼어서 "이 주소로 온 요청에 무슨 일을 해줄지" 처리합니다.

이 수업에서 우리는 각 URL마다 담당 Servlet 파일을 따로 만드는 패턴을 씁니다. /loginLoginServlet.java 가, /boardBoardServlet.java 가 받습니다. 기능이 늘어나면 src/main/java 아래에 Servlet 파일이 하나씩 추가되는 식이에요.

"그럼 누가 /login 요청은 LoginServlet 으로 가야 한다고 결정하나요?" — 그건 Tomcat (서블릿 컨테이너) 의 역할입니다. 여러분이 아래처럼 @WebServlet("/login") 어노테이션 한 줄만 붙여두면, Tomcat이 시작될 때 그 매핑 표를 읽어두고 요청이 올 때마다 정해진 Servlet을 자동으로 호출해줍니다.

Servlet은 직접 화면을 안 그린다 — sendRedirect로 JSP에 떠넘긴다

Servlet의 일과 JSP의 일은 다릅니다. Servlet은 "요청 받기, 파라미터 처리, DB 호출"까지 담당하고, 그 다음 화면을 그리는 일은 JSP에게 떠넘깁니다. 그 떠넘기는 방법이 바로 resp.sendRedirect("xxx.jsp") 예요. 의미는 단순합니다: 서버가 브라우저에게 "이 JSP를 다시 요청해" 라고 알려주는 거죠.

LoginServlet.java — /login 전용 파일

// src/main/java/com/edu/controller/LoginServlet.java
package com.edu.controller;

import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;

@WebServlet("/login")   // ← Tomcat에게 "나는 /login 담당이에요"
public class LoginServlet extends HttpServlet {

  @Override
  protected void service(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {

    String userId = req.getParameter("userId");
    String pw     = req.getParameter("password");

    // TODO: DB에서 userId/pw 검증
    boolean ok = checkLogin(userId, pw);

    if (ok) {
      resp.sendRedirect("main.jsp");    // ← 성공: 메인으로
    } else {
      resp.sendRedirect("login.jsp");   // ← 실패: 로그인 화면 다시
    }
  }
}

BoardServlet.java — /board 전용 파일 (별개의 .java 파일!)

// src/main/java/com/edu/controller/BoardServlet.java
package com.edu.controller;

import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;

@WebServlet("/board")   // ← 다른 Servlet은 다른 URL 담당
public class BoardServlet extends HttpServlet {

  @Override
  protected void service(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {

    // TODO: DB에서 게시글 목록을 session에 담아두기
    resp.sendRedirect("board.jsp");     // ← 게시판 화면으로 보냄
  }
}

파일 구조가 이렇게 쌓입니다:

src/main/java/com/edu/controller/
  ├── IndexServlet.java     // @WebServlet("/")       — 메인 진입
  ├── LoginServlet.java     // @WebServlet("/login")  — 로그인 처리
  └── BoardServlet.java     // @WebServlet("/board")  — 게시판 처리

src/main/webapp/
  ├── main.jsp              // 메인 화면
  ├── login.jsp             // 로그인 폼
  ├── board.jsp             // 게시판 화면
  └── WEB-INF/
      └── web.xml
수업 포인트: JSP 파일들이 WEB-INF/views 안이 아니라 webapp 루트에 그냥 있다는 점을 주목하세요. sendRedirect 는 "브라우저가 직접 그 URL로 다시 접속" 하는 방식이라, JSP 파일이 외부에서 접근 가능한 위치에 있어야 합니다. WEB-INF 안 파일은 외부에서 직접 접근이 막혀있어서 sendRedirect 대상이 될 수 없어요.

sendRedirect와 forward — 무엇이 다른가

Servlet에서 JSP로 넘기는 방법은 사실 두 가지가 있습니다. 학생들이 처음 헷갈리는 부분이라 비교해두면 좋아요.

구분sendRedirectforward
요청 횟수 2번 (Servlet 한 번 + JSP 한 번)1번 (서버 내부 이동)
주소창 URL JSP의 URL로 변경됨 변경 안 됨
request 데이터 전달 안 됨 (날아감) 그대로 유지
JSP 위치 제약 외부 접근 가능 위치 WEB-INF 안에 둘 수 있음
주 사용처 처리 끝난 후 다른 페이지로 이동모델 데이터를 화면에 그대로 전달

이 수업의 학생들 코드는 sendRedirect 위주이므로, request로 데이터를 넘기고 싶을 때는 session에 담거나 URL 파라미터로 붙여서 전달합니다. 예: resp.sendRedirect("main.jsp?msg=welcome").

주의 · @WebServlet("/") 는 "default servlet"

@WebServlet("/") 는 단순히 "/" 만 처리하는 게 아니라, 다른 어떤 Servlet에도 매칭되지 않은 요청까지 모두 떠안는 fallback 역할을 합니다. 그래서 매칭 우선순위는 이렇게 작동해요:

요청 URL매칭되는 Servlet이유
/login LoginServlet정확 매치 (exact match 최우선)
/board BoardServlet정확 매치
/ IndexServletdefault servlet
/unknownIndexServlet매칭 안 된 나머지도 default로 감!
학생들에게 꼭 짚어주세요: "/ 는 그냥 메인 페이지용이 아니라 '미아 보호소' 역할도 한다." 이걸 모르고 있으면 "왜 오타친 주소도 메인 페이지가 뜨지?" 하면서 한참 디버깅하게 됩니다. 404를 내고 싶으면 IndexServlet의 service 에서 path를 검사해서 resp.sendError(404) 를 직접 호출해야 합니다.

참고 · web.xml 로 매핑하는 예전 방식

어노테이션이 안 되는 환경에선 web.xml 에 직접 써주기도 합니다. 결과는 같아요.

<!-- src/main/webapp/WEB-INF/web.xml -->
<servlet>
  <servlet-name>LoginServlet</servlet-name>
  <servlet-class>com.edu.controller.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>LoginServlet</servlet-name>
  <url-pattern>/login</url-pattern>
</servlet-mapping>

<servlet>
  <servlet-name>BoardServlet</servlet-name>
  <servlet-class>com.edu.controller.BoardServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>BoardServlet</servlet-name>
  <url-pattern>/board</url-pattern>
</servlet-mapping>
수업 포인트: 시뮬레이터에서 버튼을 바꿔 누를 때 "2. Servlet" 노드의 이름이 LoginServletBoardServletIndexServlet 으로 바뀌는 걸 주목하게 해주세요. 그게 바로 "각 URL마다 담당 Java 파일이 다르다" 는 증거입니다. 기능 하나 추가 ⇒ Servlet 하나 추가 ⇒ Java 파일 하나 추가. 이 패턴이 학생 프로젝트의 기본 구조입니다.

주소 규칙 요약

입력 URLController 결정열리는 JSP
localhost:8081/test/ index 분기 index.jsp
localhost:8081/test/login login 분기 login.jsp
localhost:8081/test/board board 분기 board.jsp
localhost:8081/test/unknownelse → 404에러 페이지