관리 메뉴

거니의 velog

(6) 서블릿이란? - 1 본문

Java_Servlet

(6) 서블릿이란? - 1

Unlimited00 2023. 8. 21. 19:52

* 웹 페이지의 문제점을 보완하여 나온 것이 동적 웹 페이지를 구현하는 JSP라고 했지만, 사실 동적 웹 페이지를 처음으로 구현한 방법은 JSP가 아닌 서블릿(Servlet, 자바로 만든 CGI 프로그램)을 이용해 구현했다.

* 그리고 이 서블릿의 문제점을 보완하여 나온 것이 JSP이다. JSP의 많은 기능은 서블릿의 기능을 따르므로 서블릿을 먼저 이해하고 나면 JSP를 좀 더 수월하게 이해할 수 있다. 실제 웹 어플리케이션을 개발할 때도 JSP와 서블릿이 각자의 고유한 역할을 나누어 기능을 구현하고 있다.


1. 서블릿이란?

* 서블릿은 서버 쪽에서 실행되면서 클라이언트의 요청에 따라 동적으로 서비스를 제공하는 자바 클래스이다. 서블릿은 자바로 작성되어 있으므로 자바의 일반적인 특징을 모두 가진다. 하지만 서블릿은 일반 자바 프로그램과 다르게 독자적으로 실행되지 못하고 톰캣과 같은 JSP/Servlet 컨테이너에서 실행된다는 점에서 차이가 있다.

* 서블릿은 서버에서 실행되다가 웹 브라우저에서 요청하면 해당 기능을 수행한 후 웹 브라우저에 결과를 전송한다. 서버에서 실행되므로 보안과 관련된 기능도 훨씬 안전하게 수행할 수 있다.

* 클라이언트가 웹 서버에 요청하면 웹 서버는 그 요청을 톰캣과 같은 웹 애플리케이션 서버(WAS)에 위임한다. 그러면 WAS는 각 요청에 해당하는 서블릿을 실행한다. 그리고 서블릿은 요청에 대한 기능을 수행한 후 결과를 반환하여 클라이언트에 전송한다.

* 서블릿은 다음과 같은 특징이 있다.

- 서버 쪽에서 실행되면서 기능을 수행한다.

- 기존의 정적인 웹 프로그램의 문제점을 보완하여 동적인 여러 가지 기능을 제공한다.

- 스레드 방식으로 실행된다.

- 자바로 만들어져 자바의 특징(객체 지향)을 가진다.

- 컨테이너에서 실행된다.

- 컨테이너 종류에 상관없이 실행된다(플랫폼 독립적).

- 보안 기능을 적용하기 쉽다.

- 웹 브라우저에서 요청 시 기능을 수행한다.

2. 서블릿 API 계층 구조와 기능

* 서블릿은 자바로 만들어 졌으므로 당연히 클래스들 간의 계층 구조를 가진다. 

* 서블릿 API는 Servlet과 ServletConfig 인터페이스를 구현해 제공하며 GenericServlet 추상 클래스가 이 두 인터페이스의 추상 메서드를 구현한다. 그리고 이 GenericServlet을 다시 HttpServlet이 상속받는다.

서블릿 API 기능

서블릿 구성 요소 기능
Servlet 인터페이스 - javax.servlet 패키지에 선언되어 있다.
- Servlet 관련 추상 메서드를 선언한다.
- init(), service(), destroy(), getServletInfo(), getServiceConfig()를 선언한다.
ServletConfig 인터페이스 - javax.servlet 패키지에 선언되어 있다.
- Servlet 기능 관련 추상 메서드를 선언되어 있다.
- getInitParameter(), getInitParameterNames(), getServletContext(), getSetvletName()이 선언되어 있다.
GenericServlet 클래스 - javax.servlet 패키지에 선언되어 있다.
- 상위 두 인터페이스를 구현하여 일반적인 서블릿 기능을 구현한 클래스이다.
- GenericServlet을 상속받아 구현한 사용자 서블릿은 사용되는 프로토콜에 따라 각각
service()를 오버라이딩해서 구현한다.
HttpServlet 클래스 - javax.servlet.http 패키지에 선언되어 있다.
- GenericServlet을 상속받아 HTTP 프로토콜을 사용하는 웹 브라우저에서 서블릿 기능을 수행한다.
- 웹 브라우저 기반 서비스를 제공하는 서블릿을 만들 때 상속받아 사용한다.
- 요청시 service()가 호출되면서 요청 방식에 따라 doGet()이나 doPost()가 차례대로 호출된다.

* GenericServlet은 일반적인 여러 통신 프로토콜에 대한 클라이언트/서버 프로그램에서 서블릿 기능을 구현하는 클래스이다. HttpServlet은 이 GenericServlet을 상속받는다. HttpServlet은 이름에서 알 수 있듯이 HTTP 프로토콜을 사용하는 서블릿 기능을 구현하는 클래스이다. 바로 이 HttpServlet을 상속받아 HTTP 프로토콜로 동작하는 웹 브라우저의 요청을 처리하는 서블릿이 우리가 사용할 서블릿이다. 그 외 다른 서블릿 구성 요소들의 기능은 API 문서를 참고하길 바란다.

메서드 기능
protected doDelete(HttpServletRequest req, HttpServletResponse res) 서블릿이 DELETE request를 수행하기 위해 service()를 통해서 호출된다.
protected doGet(HttpServletRequest req, HttpServletResponse res) 서블릿이 GET request를 수행하기 위해 service()를 통해서 호출된다.
protected doHead(HttpServletRequest req, HttpServletResponse res) 서블릿이 HEAD request를 수행하기 위해 service()를 통해서 호출된다.
protected doPost(HttpServletRequest req, HttpServletResponse res) 서블릿이POST request를 수행하기 위해 service()를 통해서 호출된다.
protected service(HttpServletRequest req, HttpServletResponse res) 표준 HTTP request를 public service()에서 전달받아 doXXX메서드를 호출한다.
public service(HttpServletRequest req, HttpServletResponse res) 클라이언트의 request를 protected service()에게 전달한다.

* 클라이언트 요청 시 public service() 메서드를 먼저 호출한 후 다시 protected service() 메서드를 호출한다. 그런 다음 다시 request 종류에 따라 doXXX() 메서드를 호출하는 과정으로 실행한다.


3. 서블릿의 생명주기 메서드

* 서블릿도 자바 클래스이므로 실행하면 당연히 초기화 과정 그리고 메모리에 인스턴스를 생성하여 서비스를 수행한 후 다시 소멸하는 과정을 거친다. 이런 단계를 거칠 때마다 서블릿 클래스의 메서드가 호출되어 초기화, 데이터베이스 연동, 마무리 작업을 수행한다. 각 과정에서 호출되어 기능을 수행하는 메서드들이 서블릿 생명주기 메서드이다.

* 따라서 서블릿 생명주기(Life Cycle) 메서드란 서블릿 실행 단계마다 호출되어 기능을 수행하는 콜백 메서드를 말한다.

생명주기 단계 호출 메서드 특징
초기화 init() - 서블릿 요청 시 맨 처음 한 번만 호출된다.
- 서블릿 생성 시 초기화 작업을 주로 수행한다.
작업 수행 doGet()
doPost()
- 서블릿 요청 시 매번 호출된다.
- 실제로 클라이언트가 요청하는 작업을 수행한다.
종료 destroy() - 서블릿이 기능을 수행하고 메모리에서 소멸될 때 호출된다.
- 서블릿의 마무리 작업을 주로 수행한다.

* init() 메서드는 실행 초기에 서블릿 기능 수행과 관련된 기능을 설정하는 용도로 많이 사용됩니다. 그리고 destroy()는 서블릿이 메모리에 소멸될 때 여러 가지 종료 작업을 수행한다. 따라서 만약 이런 기능이 필요 없으면 생략해도 상관없다. 반면에 doGet() 이나 doPost()와 같이 do로 시작하는 메서드는 서블릿의 핵심 기능을 처리하므로 반드시 구현해야 한다.


4. FirstServlet을 이용한 실습

* 이번에는 사용자 정의 서블릿을 실제로 만들어서 서블릿의 동작 과정을 실습해 본다.

* 다음은 이클립스에서 서블릿을 만들고 실행하는 과정이다.


(1) 사용자 정의 서블릿 만들기

* 실제 웹 프로그래밍에서 사용되는 사용자 정의 서블릿은 HttpServlet 클래스를 상속받아 만든다. 
  그리고 3개의 생명주기 메서드, 즉 init(), doGet(), destroy() 메서드를 오버라이딩해서 기능을 구현한다.

public class FirstServlet extends HttpServlet {

	@Override
	public void init() throws ServletException {
		...
	}
	
	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse res) {
		...
	}
	
	@Override
	public void destroy() {
		...
	}
	
}

(2) 톰캣의 servlet-api.jar 클래스 패스 설정하기

* 사용자 정의 서블릿을 실습하기 위해 새로운 프로젝트를 생성한다. 이 때 주의할 것이 있다. 앞에서 설명한 서블릿 API 들은 톰캣의 servlet-api.jar 라이브러리로 제공되므로 이클립스의 프로젝트에서 서블릿을 사용하려면 반드시 클래스 패스를 설정해야 한다.

1. 이클립스 상단의 New 아이콘을 클릭한 후 Dynamic Web Project를 선택한다.

2. 프로젝트 이름을 pro05로 입력한 후 Next를 클릭한다.

3. 경로를 확인한 후 Next를 클릭한다.

4. Generate web.xml deployment descriptor 옵션의 체크박스에 체크한 후 Finish를 클릭한다.

5. 프로젝트 이름을 선택하고 마우스 오른쪽 버튼 클릭 > Build Path > Configure Build Path... 를 선택한다.

6. 설정창에서 Libraries 탭을 클릭하고 Classpath 를 선택한 후 Add External JARs... 를 클릭한다.

7. CATALINA_HOME(톰캣 루트 디렉터리)의 lib 디렉터리에 있는 servlet-api.jar을 선택한 후 열기 클릭

8. servlet-api.jar의 클래스 패스 설정 확인 후 Apply and Close를 클릭해 종료한다.


(3) 첫 번째 서블릿 만들기

1. pro05 프로젝트의 Java Resource 디렉터리 하위의 src를 선택하고 마우스 오른쪽 버튼을 클릭 > New > Package를 선택

2. sec01.ex01이라는 이름으로 패키지 생성

3. 이 패키지 이름 위에 마우스 오른쪽 버튼 클릭 > New > Class 선택

4. 클래스 이름으로 FirstServlet 을 입력한 후 Finish를 클릭

package sec01.ex01;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class FirstServlet extends HttpServlet {

	@Override
	public void init() throws ServletException {
		System.out.println("init 메서드 호출");
	}
	
	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		System.out.println("doGet 메서드 호출");
	}
	
	@Override
	public void destroy() {
		System.out.println("destroy 메서드 호출");
	}
	
}

* 우리가 만든 서블릿은 HttpServlet을 상속받고 3개의 생명주기 메서드를 차례로 구현한다. 각 메서드는 호출 시 메시지만 출력한다.

* 소스 코드를 작성했으니 이제 첫 번째 서블릿을 어떻게 실행하여 동작시키는지 알아보자.


(4) 서블릿 매핑하기

* 브라우저에서 서블릿 이름으로 요청하는 방법은 다음과 같다. 프로젝트 이름 뒤에 패키지 이름이 포함된 클래스 이름 전부를 입력한다.

* 단점은 클래스 이름이 길어지면 입력하기 불편할 것이다. 그리고 일반적으로 클래스 이름을 보면 그 클래스가 어떤 기능을 하는지 짐작할 수 있는데, 브라우저에서 버젓이 클래스 이름으로 입력하면 보안에도 좋지 않다. 따라서 지금은 이런 식으로 사용하지 않고 서블릿 클래스 이름에 대응되는 서블릿 매핑 이름으로 실제 서블릿을 요청한다.

* 그럼 지금부터 서블릿 매핑 방법에 대해 알아보자. 

(1) 각 프로젝트에 있는 web.xml에서 설정한다.

(2) <servlet> 태그와 <servlet-mapping> 태그를 이용한다.

(3) 여러 개의 서블릿 매핑 시에는 <servlet> 태그를 먼저 정의하고 <servlet-mapping> 태그를 정의한다.

* 실제 서블릿 매핑을 보면 <servlet> 태그와 <servlet-mapping> 태그의 하위 태그에 <servlet-name> 태그가 공통으로 있다. <servlet-name> 태그의 값 aaa가 <servlet>과 <servlet-mapping> 태그를 연결시켜 준다.

* 그러면 웹 브라우저에서 <url-pattern> 태그의 /first로 요청할 경우 aaa 값을 가지는 <servlet> 태그를 찾아 실제 서블릿인 sec01.ex01.FirstServlet을 실행한다.

  <servlet>
  	<servlet-name>aaa</servlet-name> // <servlet> 태그와 <servlet-name> 태그를 연결시켜 준다.
  	<servlet-class>sec01.ex01.FirstServlet</servlet-class>
  </servlet>
  
  <servlet-mapping>
  	<servlet-name>aaa</servlet-name> // <servlet> 태그와 <servlet-name> 태그를 연결시켜 준다.
  	<url-pattern>/first</url-pattern> // 웹 브라우저에서 요청하는 매핑 이름
  </servlet-mapping>

* 지금부터 서블릿 매핑 형식을 실제 프로젝트에 적용해 보자.

(1) pro05 프로젝트의 WebContent > WEB-INF 폴더를 클릭한 후 web.xml을 선택하여 엽니다.

(2) web.xml에 <web-app> 태그의 하위 태그를 지우고 다음과 같이 서블릿 매핑을 작성한다.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <servlet> // 브라우저에서 요청하는 매핑 이름에 대해 실제로 실행하는 서블릿 클래스를 설정하는 태그
  	<servlet-name>aaa</servlet-name> // <servlet-mapping> 태그의 <servlet-name> 태그와 값이 동일
  	<servlet-class>sec01.ex01.FirstServlet</servlet-class> // 브라우저에서 요청하는 매핑 이름에 대해 실제로 기능을 수행하는 서블릿 클래스를 설정합니다.
  </servlet>
  
  <servlet-mapping> // 브라우저에서 요청하는 논리적인 서블릿을 설정한다.
  	<servlet-name>aaa</servlet-name> // 매핑 이름으로 요청시 값이 같은 <servlet> 태그 안의 <servlet-name> 태그와 연결된다.
  	<url-pattern>/first</url-pattern> // 브라우저에서 sec01.ex01.FirstServlet을 요청하는 논리적인 서블릿 이름이다.
  </servlet-mapping>
</web-app>

5. 톰캣에 프로젝트 실행

* 이제 새로 만든 프로젝트를 다시 톰캣 서버에 등록한 후 톰캣을 다시 실행하여 웹 브라우저에서 서블릿 매핑 이름인 /first로 요청한다. 이때 콘솔로 메시지가 출력되는 것을 확인하면 된다.

(1) 톰캣 서버를 선택하고 마우스 오른쪽 버튼을 클릭한 후 Add and Remove... 를 선택한다.

(2) pro05 프로젝트를 선택한 후 Add를 클릭하여 추가하고 Finish를 클릭한다.

(3) 톰캣에 정상적으로 새 프로젝트가 등록된 것을 확인할 수 있다.


6. 브라우저에서 서블릿 요청하기

* 이번에는 실제로 웹 브라우저에서 서블릿을 요청하는 방법을 알아보자.

* 웹 브라우저에서 서블릿을 요청하려면 다음과 같이 웹 브라우저 주소창에 프로젝트 이름까지 입력하고 web.xml에 매핑한 매핑 이름을 슬래시(/) 다음에 입력한 후 요청하면 된다.

- http://IP주소:포트번호/프로젝트이름(컨텍스트이름)/서블릿매핑이름

- 요청 예) http://127.0.0.1:8090/pro05/first

* /first로 웹 브라우저에 요청하면 이클립스 콘솔에 각각의 메서드가 호출되면서 메시지가 출력된다.