BlueNyang
[멀티캠퍼스] 풀스택 개발자 아카데미 (17) - Servlet/JSP(1)
Java 풀스택 아카데미
· 멀티캠퍼스 JAVA 풀스택 개발자 아카데미 6회차 (17편)

[멀티캠퍼스] 풀스택 개발자 아카데미 (17) - Servlet/JSP(1)

BlueNyangBlueNyang
·
·
약 9분
·
# 부트캠프후기# 멀티캠퍼스it부트캠프# [현대이지웰] JAVA 풀스택 개발자 아카데미 6회차# was# servlet# jsp# tomcat# jakarta-ee
시리즈·멀티캠퍼스 JAVA 풀스택 개발자 아카데미 6회차(30개의 글)
  • ···
  • 16.[멀티캠퍼스] 풀스택 개발자 아카데미 (16) - Algorithm(5)
  • 17.[멀티캠퍼스] 풀스택 개발자 아카데미 (17) - Servlet/JSP(1)현재
  • 18.[멀티캠퍼스] 풀스택 개발자 아카데미 (18) - Servlet/JSP(2)
  • ···

1. 웹 개발의 시작

이번 내용부터는 자바(Java)를 기반으로 한 백엔드 개발을 Servlet과 JSP라는 가장 기초적인 기술커터, Spring Boot에 이르기까지 단계적으로 알아보고자 한다. 이를 통해 웹의 근본적인 동작 원리를 이해하고, 견고한 기초를 다져볼 수 있다.

이번 글에서는 동적 웹 프로그래밍의 첫 관문인 서블릿(Servlet)JSP(Java Server Page) 에 대해 알아본다. 정적인 HTML만으로는 불가능했던 "동적인 웹"을 구현하는 핵심 요소들을 살펴보고자 한다. 이를 통해 사용자가 주소창에 URL을 입력했을 때, 서버에서 어떤 일이 벌어지는지에 대한 큰 그림을 알아본다.

2. 동적 웹의 기본 원리

2.1. 정적 웹(Static Web) vs 동적 웹(Dynamic Web)

웹 페이지는 크게 정적 페이지와 동적 페이지로 나뉘다.

정적 웹 프로그래밍은 웹 서버에 미리 저장된 HTML, CSS, JavaScript, 이미지 파일을 사용자의 요청에 따라 그대로 전달하는 방식이다. 서버에는 이미 완성된 파일들이 존재하며, 누가 언제 접속하든 항상 동일한 내용을 보여준다. 이는 주로 내용이 바뀔 일이 없는 소개 페이지나 간단한 정보 안내 페이지에 적합하다.

반면, 동적 웹 프로그래밍은 사용자의 요청이나 시간, 데이터 베이스의 값 등 상황에 따라 각기 다른 내용과 결과를 보여주는 방식이다. 예를 들어, Naver에 접속하면 볼 수 있는 뉴스, 실시간 검색어, 로그인 정보 등은 모두 동적으로 생성되는 콘텐츠이다. 정적인 HTML만으로는 이러한 실시간 데이터 변화를 처리할 수 없기 때문에, 서버 측에서 데이터를 가공하여 새로운 HTML 문서를 만들어내는 기술이 필요했고, 이것이 바로 CGI, PHP, ASP, 그리고 이번 글에서 등장하는 JSP와 Servlet 같은 동적 웹 프로그래밍 기술이다.

클라이언트와-서버의-통신-구조
클라이언트와-서버의-통신-구조

2.2. 웹 서버와 WAS

동적 웹 애플리케이션이 동작하기 위해서는 여러 구성 요소가 필요하다. 그중 가장 핵심적인 것이 웹 서버와 WAS(Web Application Server)이다.

  • 웹 서버(Web Server): HTTP 프로토콜을 기반으로, 클라이언트(웹 브라우저)로부터 요청을 받아 정적인 콘텐츠(HTML, CSS, 이미지 등)을 제공하는 소프트웨어다. 대표적으로 Apache, Nginx가 있다. 웹 서버는 받은 요청이 동적인 처리를 필요로 할 경우, 해당 요청을 WAS로 전달하는 역할도 수행한다.
  • 웹 애플리케이션 서버(WAS): 웹 서버로부터 전달받은 동적 요청을 처리하는 것이 주된 역할로, 데이터베이스 조회나 비즈니스 로직 수행 등 복잡한 작업을 처리하여 그 결과를 동적인 HTML 페이지로 생성해 웹 서버로 다시 전달한다. 우리가 사용할 아파치 톰캣(Apache Tomcat)은 WAS의 한 종류이며, 자체적으로 정적 콘텐츠를 처리하는 웹 서버 기능도 내장하고 있다.
  • 웹 컨테이너(Web Container): WAS 내부에 존재하며, Servle과 JSP의 생명주기를 관리하고, 요청에 따라 서블릿을 실행하는 역할을 담당하는 핵심 컴포넌트이다. 즉, 개발자가 만든 서블릭 코드가 길제로 실행되고 관리되는 환경을 제공한다.
웹-서버와-WAS의-관계
웹-서버와-WAS의-관계

정리하자면, 사용자가 브라우저에서 무언가를 요청하면, 웹 서버가 먼저 요청을 받고. 만약 동적인 처리가 필요한 경우, WAS 내의 웹 컨테이너에게 작업을 위임한다. 컨테이너는 서블릿을 실행하여 요청을 처리하고, 그 결과를 다시 웹 서버를 통해 사용자에게 응답는 구조다.

3. Servlet과 JSP

3.1. Servlet

서블릿(Servlet): Server + Applet의 합성어로, 서버 측에서 실행되면서 클라이언트의 요청을 처리하고, 그 결과를 반환하는 자바 클래스를 의미한다. 즉, 동적 웹 페이지를 생성하기 위한 자바 기반의 서버 사이드 기술이다. 서블릿은 자바 코드 안에 HTML을 포함하는 구조로 되어 있어, out.println("<html><body>...")과 같이 자바 코드로 직접 웹 페이지를 그려내야 한다.

3.1.1. 서블릿의 처리 순서와 생명주기

서블릿은 웹 컨테이너에 의해 그 생명주기가 관리된다.

  1. 클라이언트로부터 특정 서블릿에 대한 최초의 요청이 들어온다.
  2. 컨테이너는 해당 서블릿 클래스를 메모리에 로드하고, init() 메소드를 호출하여 초기화한다. 이 과정은 최초 한 번만 수행된다.
  3. 초기화된 서블릿 객체는 이후 모든 요청을 처리할 준비가 된 상태이다. 클라이언트의 요청이 들어올 때마다 컨테이너는 스레드(Thread)를 생성하고 service() 메소드를 호출한다. service() 메소드는 요청이 GET인지 POST인지에 따라 doGet() 또는 doPost() 메소드를 내부적으로 호출한다. 이 단계는 요청 시마다 반복 수행된다.
  4. 서버가 종료되거나, 서블릿 코드가 수정되어 재배포될 때, 컨테이너는 destroy() 메소드를 호출하여 서블릿 객체를 메모리에서 제거한다. 이과정 역시 마지막에 반 번만 수행된다.
서블릿의-생명주기
서블릿의-생명주기

이러한 구조 덕분에 서블릿은 최초 로딩 후 메모리에 상주하며 각 요청을 스레드 기반으로 빠르게 처리할 수 있어 효율적이다.

3.2. JSP

서블릿만으로 웹 페이지를 만드는 것은 매우 힘들다. 자바 코드 안에서 수만은 println()문으로 HTML 태그를 일일이 작성하는 것은 가독성을 해칠 뿐더러, 유지보수성을 낮추는 원인이 되기도 한다. 이러한 문제를 해결하기 위해 등장한 것이 바로 JSP(JavaServer Pages) 이다.

JSP는 서블릿과 반대로, HTML 문서 내부에 자바 코드를 삽입하는 형태를 가진다. 이로 인해 웹 디자이너는 HTML 구조에 집중할 수 있고, 개발자는 <% %>와 같은 Scriptlet 태그 안에 동적 로직을 구현하는 역할 분담이 가능해 졌다.

3.2.1. JSP의 동작 원리

흥미로운 점은 JSP가 내부적으로는 서블릿으로 변환되고, 결과적으로 하나의 class가되어 실행된다는 것이다. 클라이언트가 .jsp 파일을 최초로 요청하면, 웹 컨테이너는 다음과 같은 과정을 거치게 된다.

  1. 변환(Translation): .jsp 파일은 .java 형태의 서블릿 소스코드로 변환한다.
  2. 컴파일(Compilation): 생성된 .java 파일을 자바 컴파일러를 이용해 .class 파일로 컴파일 한다.
  3. 실행(Execution): 컴파일된 class 파일을 메모리에 로드하고, 서블릿과 동일한 생명주기에 따라 실행하여 요청을 처리한다.
JSP파일이-서블릿으로-변환되는-과정
JSP파일이-서블릿으로-변환되는-과정

이후 동일한 JSP에 대한 요청이 들어오면, 이미 생성된 서블릿 클래스를 재사용하므로, 빠른 응답이 가능하다. 결국 JSP는 개발자가 서블릿 코드를 직접 작성하는 수고를 덜어주기 위한, 편리한 템플릿 기술이라고 할 수 있다.

4. 동적 페이지 예제

멀티캠퍼스에서는 기본적으로 IDE를 Eclipse(Eclipse IDE for Enterprise Java and Web Developers)를 사용한다. 하지만 IntelliJ IDEA를 사용하면서 Eclipse 실습 시 수행하는 작업을 IDEA로 할 수 있고, 환경에 따라 발생하는 문제를 해결할 수 있다면 IntelliJ를 사용해도 무관하다.

향후 본 교육과정(멀티캠퍼스 Java 풀스택 아카데미)를 수강하는 독자 중, IDEA를 사용하고픈 독자를 위해서 이클립스로 수행하는 실습 과정과 이를 IDEA에서 따라가는 방법을 함께 서술하고자 한다.

멀티캠퍼스의 교육과정에서는 JDK11, Eclipse IDE, Apache Tomcat 9.0을 사용하였으며, 필자는 Servlet 실습 과정에서 기존에 사용을 하고 있던 일부 환경을 그대로 사용하였기 때문에 JDK21, IntelliJ IDEA Ultimate(학생 라이선스), Apache Tomcat 10.0(Apache Tomcat 11.0.11도 함께 사용)을 사용하였다.

4.0. 참고 사항

멀티캠퍼스에서 진행하는 Servlet 연습 프로젝트는 javax 네임스페이스의 클래스들을 사용하게 되는데, 이는 Java EE(Enterprise Edition) 표준이다. 하지만 Java EE가 Java 9 이후 이클립스 재단으로 기술이 이관되면서 Jakarta EE로 이름이 바뀌었고, 이에 따라 패키지 이름도 jakarta로 변경되었다.

이 네임스페이스가 중요한 이유는 Tomcat 9.0까지는 javax를, Tomcat 10.0 이후로는 jakarta를 사용해야 하기 때문이다. 만약 Tomcat의 버전이 9.0인 경우, jakarta 패키지를 지원하지 않는다. 따라서 필자와 같이 최신 환경(JDK 21, Tomcat 10.0)을 사용하는 경우 jakarta 네임스페이스를 사용하는 것이 올바르다. 필자는 JDK21, Tomcat 10.0 이상을 사용하므로, 이에 따라 jakarta 패키지를 자연스럽게 사용하게 될 것이다.

4.1. 프로젝트 생성

이클립스에서는 File > New > Dynamic Web Project를 선택하여 새로운 프로젝트를 생성한다. 프로젝트 이름을 입력하고, Target runtime으로 Apache Tomcat을 지정하며. web.xml을 생성하는 옵션을 체크하여 생성한다.

IntelliJ IDEA에서는 File > New > Project...를 선택하여 프로젝트를 생성할 수 있으며, 좌측 메뉴의 Generator에서 Jakarta EE를 선택하면 쉽게 생성할 수 있다.

  1. Name, Location. Git repository를 적절히 설정한다.
  2. Template: Web application을 선택한다.
  3. Application Server: New... 버튼을 눌러 로컬에 설치된 Tomcat 서버 경로를 지정해준다. 한 번 지정해두면 이후로는 목록에서 선택할 수 있다.
  4. Build System: 멀티캠퍼스 과정을 원활히 따라가기 위해 Maven을 권장한다.
  5. JDK: 설치해둔 JDK(필자의 경우 JDK 21)를 선택한다.
  6. Dependencies: Next를 누르면 나오는 부분으로, Tomcat 버전에 대응되는 Jakarta EE 버전을 선택해야 한다.
IntelliJ-IDEA에서-Jakarta-EE-웹-애플리케이션-프로젝트-생성-화면
IntelliJ-IDEA에서-Jakarta-EE-웹-애플리케이션-프로젝트-생성-화면

4.2. Hello Servlet 생성하기

프로젝트를 구성하였다면, 이제 동적인 콘텐츠를 생성할 서블릿 클래스를 만들어 볼 수 있다.

src/main/java 디렉터리 아래에 com.example.hello와 같은 새로운 패키지를 생성한다. Template으로 이미 패키지와 서블릿이 있을 수 있는데, 삭제해도 무관하다. 이후 해당 패키지를 우클릿하고 New > Servlet을 선택하여 HelloServlet이라는 이름의 서블릿을 생성한다.

Tip
만약 New 메뉴에 Servlet 항목이 보이지 않는다면, 먼저 New > Java Class를 선택하여 클래스를 생성하고 코드 내에서 extends HttpServlet을 입력하여 상속받으면 된다. 필요한 메소드는 Ctrl+O(MacOS: ⌘+O)를 눌러 doGet(), doPost() 등을 쉽게 오버라이딩할 수 있다.

4.3. 서블릿 코드 작성 및 URL 매핑

이제 HelloServlet.java 파일을 수정하여 브라우저에 "Hello Servlet!" 메시지를 출력하도록 doGet() 메소드를 수정한다.

java
// HelloServlet.java
// package 문 생략

import java.io.IOException;  
import java.io.Serial;  

import jakarta.servlet.annotation.WebServlet;  
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;  
import jakarta.servlet.http.HttpServletResponse;  
  
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    /**  
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)  
     */
     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {  
		// 1. 응답 콘텐츠 타입과 문자 인코딩 설정
		response.setContentType("text/html;charset=UTF-8");
		// 2. 클라이언트로 텍스트를 출력할 PrintWriter 객체 얻기
		try (PrintWriter out = response.getWriter()) {
		// 3. HTML 응답 작성
			out.println("<!DOCTYPE html>");
			out.println("<html>");
			out.println("<head><title>Hello Servlet</title></head>");
			out.println("<body>");
			out.println("<h1>Hello Servlet! (from Jakarta EE)</h1>");
			out.println("</body>");
			out.println("</html>");
		}
    }
}

서블릿을 만들었다면, 클라이언트가 어떤 URL로 요청해야 이 서블릿이 실행될 지 알려주어야 한다. 이를 URL Mapping이라고 하고, 두 가지 방식이 있다.

4.3.1. Mapping 방법 1 - web.xml

과거에는 src/main/webapp/WEB-INF/web.xml 파일에 서블릿 정보를 명시적으로 등록하여 매핑 했다.

이러한 방식은 위의 Java 코드에서, class 상단의 @WebServlet("/hello") 구문을 작성하지 않고, web.xml을 다음과 같이 수정하는 것이다.

xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="...." ... version="6.0">
	<display-name>...</display-name>
	<!-- 이 부분 추가 -->
	<servlet>
		<servlet-name>FirstServlet</servlet-name>  
    <servlet-class>com.example.sec01.FirstServlet</servlet-class>  
	</servlet>  
	<servlet-mapping>  
	    <servlet-name>FirstServlet</servlet-name>  
	    <url-pattern>/FirstServlet</url-pattern>  
	</servlet-mapping>
</web-app>

이러면 Tomcat Server를 실행했을 때, localhost:8080/<project명>/hello으로 접속 시, HelloServlet의 응답을 확인할 수 있다. 이 방식은 서블릿과 URL의 관계를 한눈에 파악할 수는 있으나, 서블릿을 추가/수정할 때마다 web.xml 파일을 변경해야하는 문제가 있었다.

4.3.2. Mapping 방법2 - Annotation(@)

최신 방식은 현재 Java 코드와 같이 @WebServlet("/hello") 구문을 클래스 선언부 바로 위에 추가하는 것이다. 이렇게 하면 web.xml을 수정할 필요 없이 /hello라는 URL 패턴으로 이 서블릿에 직접 매핑되며, 훨씬 간결하고 직관적이다.

Note
Annotation은 주석처럼 보이지만, 실제로는 프로그램에게 특정 기능을 수행하도록 지시하는 "메타데이터"이다. 앞으로 Spring 프레임워크를 학습하면서 @Controller, @Service 등 더 댜양한 Annotation을 접하게 될 것이다.

4.4. 서버 실행 및 결과 확인

IntelliJ IDEA 우측 상단의 실행 구성 (Run Configuration)에서 Tomcat 서버를 선택하고 실행 버튼을 누르면, 서버가 정상적으로 구동되면서 자동으로 웹 브라우저가 열리고, http://localhost:8080/프로젝트명/매핑한url 주소로 접속하여 확인해 볼 수 있다. (포트 번호와 프로젝트 이름은 환경에 따라 다를 수 있다.)

브라우저에서-실행된-Jakarta-서블릿-결과-화면
브라우저에서-실행된-Jakarta-서블릿-결과-화면

성공적으로 "Hello Servlet! (from Jakarta EE)" 메시지가 브라우저에 나타난다면, 첫 동적 웹 애플리케이션이 성공적으로 동작한 것이다.

5. 마무리하며

이번 글에서는 자바 기반의 동적 웹 프로그래밍을 위한 가장 기초적인 두 가지 기술, Servlet과 JSP가 무엇인지, 정적인 페이지를 넘어 사용자와 상호작용하는 웹을 만들기 위해 웹 서버와 WAS가 어떻게 협력하는지, 그리고 그 중심에서 Servlet과 JSP가 어떤 역할을 수행하는 지 알아보았다. Servlet은 강력한 자바 코드를 통해 서버의 로직을 처리하고, JSP는 HTML과 자바 코드를 결합하여 동적인 화면을 보다 쉽게 구성할 수 있게 해준다.

다음 글에서는 클라이언트로부터 데이터를 입력받는 방법(GET/POST)과 MVC Model 1 Architecture에 대해 파고들어, 보다 실용적인 웹 애플리케이션을 만드는 방법을 다뤄볼 것이다.

BlueNyang
작성자BlueNyang
라이선스
CC BY NC
BlueNyang

BlueNyang

BlueNyang의 개발 log

카테고리

  • Development
  • Framework
  • Language
  • Dev Tools
  • DevOps & Infra
  • Studies

페이지

© 2026 BlueNyang. All rights reserved.

Made with Nuxt.js and Directus