본문 바로가기
백엔드/JSP & Servlet

[Servlet] 서블릿(Servlet)을 이해하고, 구현해보자

by 책 읽는 개발자_테드 2021. 10. 4.
반응형

학습 목표

· 서블릿이란?

· 서블릿 구현

· web.xml로 매핑

· 애노테이션으로 매핑

· HTTP 각 방식별 구현 메서드

· 서블릿 로딩과 초기화

· 초기화 파라미터

· URL 패턴 매핑 규칙

 


서블릿이란?

· 서블릿은 자바웹 어플리케이션을 개발할 수 있도록 하기 위해 만들어진 표준

   - 응답과 요청을 위한 객체들을(HttpServletRequest, HttpServletResponse, HttpServlet) 제공한다.

   - JSP 표준이 나오기 전에 만들어짐

· 서블릿의 개발 과정

   1. 서블릿 규약에 따라 자바 코드 작성

   2. 자바 코드를 컴파일해서 클래스 파일 생성

   3. 클래스 파일을 /WEB-INF/classes 폴더에 패키지에 알맞게 위치시킴

   4. web.xml 파일에 서블릿 클래스를 설정

   5. 톰캣 등의 컨테이너를 실행

   6. 웹 브라우저에서 확인

·  MVC 패턴을 지원하는 프레임워크를 만들어야 하는 경우 서블릿으로 기반 코드를 개발하는 경우가 많음

 

예제 프로젝트 생성

· 이클립스에서 [File]->[New]->[Dynamic Web Project] 메뉴를 실행하여 웹 어플리케이션 프로젝트 생성

 

서블릿 구현

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class NowServlet extends HttpServlet{

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        response.setContentType("text/html; charset=utf-8");

        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head><title>현재시간</title></head>");
        out.println("<body>");
        out.println("현재 시간은");
        out.println(new Date());
        out.println("입니다.");
        out.println("</body></html>");
    }
}

· HttpServlet 클래스를 상속받아야 서블릿으로 동작함

· 처리하고자하는 HTTP 방식(method)에 따라 알맞은 메서드를 재정의

   - 위에서는 doGet() 메서드를 재정의

   - doGet() 메서드가 갖는 HttpServletRequest HttpServletResponse 두 파라미터는

      각각 JSP의 request 기본 객체 response 기본 객체에 해당함

· 재정의한 메서드는 request를 기용해서 웹 브라우저의 요청 정보를 읽어오거나,

  response를 이용해서 응답을 전송함

   - 응답을 전송하려면 response.setContentType() 메서드를 이용하여 응답 컨텐츠 타입을 지정해야함

   - setContentType() 메서드에 전달되는 값은 JSP에서 page 디렉티브의 contentType 속성값과 동일함

· 웹 브라우저에 데이터를 전송하려면(응답 컨텐츠 타입 지정 후),

response.getWriter()로 문자열 데이터를 출력할 수 있는 PrintWriter를 구함

   - PrintWriter는 println() 메서드를 제공하며, 이 메서드를 이용해서 전송할 응답 데이터를 전달함

 

web.xml로 매핑

· WEB-INF 폴더의 web.xml 파일에서 서블릿 클래스를 등록 가능

 

▶ 예시 - NowServlet 클래스를 web.xml에 등록

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
   <servlet>
        <servlet-name>now</servlet-name>
        <servlet-class>ch17.NowServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>now</servlet-name>
        <url-pattern>/now</url-pattern>
    </servlet-mapping>
</web-app>

· 서블릿을 등록하려면 두 가지 설정이 필요

   1. 서블릿으로 사용할 클래스

   2. 서블릿과 URL 간의 매핑

· <servlet> 태그를 이용해서 서블릿 클래스를 등록

   - <servlet-name> 태그를 이용해서 서블릿을 참조할 때 사용할 이름 등록

   - <servlet-class> 태그를 이용해서 서블릿 클래스의 완전한 이름 입력

 

· <servlet-mapping> 태그를 이용해서 서블릿이 어떤 URL을 처리할지에 대한 매핑 정보 등록

   - <servlet-name> 태그를 이용해서 서블릿 이름 등록

   - <url-pattern> 태그를 이용해서 매핑할 URL 패턴 지정

 

· 위와 같이 NowServlet을 등록하고 톰캣을 실행한 후 매핑한 주소를 웹 브라우저에 입력하면, 다음과 같은 결과를 볼 수 있음 

결과

· <url-pattern>은 한 번 이상 사용 가능하고, 이 경우 각각의 URL 패턴에 해당 서블릿을 매핑

<servlet-mapping>
	<servlet-name>now</servlet-name>
    <url-pattern>/now</url-pattern>
	<url-pattern>/now2</url-pattern>
</servlet-mapping>

 

· <url-pattern>은 웹 어플리케이션 경로를 제외한 나머지 경로를 기준으로 적용

   - 아래의 경우 실제 매핑되는 URL은 <url-pattern>의 /now와 매핑되는 웹 어플리케이션 경로를 포함한 /ch17/now가 됨

 

    <servlet-mapping>
        <servlet-name>now</servlet-name>
        <url-pattern>/now</url-pattern>
    </servlet-mapping>

 

애노테이션으로 매핑

· 서블릿 2.5 버전까지는 web.xml 파일에 서블릿으로 등록해야 서블릿 클래스를 사용할 수 있었지만,

서블릿 3.0 버전부터 @WebServlet 애노테이션을 사용하면 파일에 따로 등록 없이 서블릿이 등록됨

 

▶ 예시 - @WebServlet을 통한 서블릿 등록

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@WebServlet(urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
        request.setCharacterEncoding("utf-8");
        response.setContentType("text/html; charset=utf-8");

        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head><title>인사</title></head>");
        out.println("<body>");
        out.println("안녕하세요, ");
        out.println(request.getParameter("name"));
        out.println("님");
        out.println("</body></html>");
    }
}

· @WebServlet 애노테이션의 urlPatterns 속성은 해당 서블릿과 매핑될 URL 패턴을 지정할 때 사용

· 두 개 이상의 URL 패턴을 처리하려면, urlPatterns 속성값으로 배열을 전달

@WebServlet(urlPattern = {"/hello","/hello1"})

· @WebServlet 애노테이션을 사용할 경우 서블릿이 처리해야 할 URL 패턴이 변경될 때마다

자바 소스 코드의 urlPatterns 속성값을 변경하고 다시 컴파일해야 하지만,

web.xml 파일을 사용하면 URL 경로가 바뀔 경우 web.xml 파일만 변경하면 됨

   - 서블릿의 용도에 따라서 @WebServlet 애노테이션, web.xml 설정 사용을 결정하기

 

· @WebServlet 애너테이션이 적용된 서블릿을 web.xml 파일에 등록하면,

두 설정에 적용된 URL 패턴이 모두 매핑되고, 각각의 객체가 생성됨

 

HTTP 각 방식별 구현 메서드

· HTTP는 GET, POST, PATCH, HEAD, PUT, DELETE 방식을 지원

   - 일반적으로 웹에서 사용되며 웹 브라우저가 지원하는 방식은 GET, POST

· HttpServlet은 HTTP 각 방식에 따라 알맞은 메서드를 이용해서 구현하도록 정의

   - GET 방식은 doGet() 메서드를 이용해서 처리

   - POST 방식의 경우 doPost() 메서드를 이용해서 처리

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException

 

서블릿 로딩과 초기화

· 서블릿 컨테이너는 서블릿을 최초 요청할 때 서블릿 객체를 생성하고, 이후 요청이 오면 앞서 생성한 서블릿 객체를 그대로 사용함

https://velog.io/@jsj3282/서블릿-기초

· 서블릿 컨테이너는 서블릿을 초기화하기 위해 ServletConfig 파라미터를 갖는 init() 메서드를 실행함

· init() 메서드의 기본 구현:

// GenericServlet 구현
public void init(ServletConfig config) throws ServletException {
    this.config = config;
    this.init();
}

public void init() throws ServletException {
}

 

· init(ServletConfig) 메서드는 파라미터가 없는 init() 메서드를 호출하므로,

초기화가 필요한 서블릿은 파라미터가 없는 init() 메서드를 재정의한다.

public class DBCPInit extends HttpServlet {

    @Override
    public void init() throws ServletException {  // 서블릿을 초기화할 때 사용
        loadJDBCDriver();
        initConnectionPool();
    }

 

· 초기화 작업은 상대적으로 시간이 오래 걸리므로, 

처음 서블릿을 사용하는 시점보다 웹 컨테이너를 처음 구동하는 시점에 초기화를 진행하는 것이 좋고,

이를 위한 <load-on-startup> 태그가 존재함

<servlet>
  <servlet-name>DBCPInit</servlet-name>
  <servlet-class>jdbc.DBCPInit</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>

<load-on-startup> 태그로 서블릿을 미리 초기화할 수 있음

·  <load-on-startup> 태그의 값은 로딩 순서를 의미하고, 값을 기준으로 오름차순으로 서블릿을 로딩함

· @WebServlet 태그를 사용하는 경우 loadOnStartup 속성을 이용해 로딩 값 지정

@WebServlet(urlPatterns = "/hello", loadOnStartup = 1)
public class InitServlet extends HttpServlet{
    ...
}

 

초기화 파라미터

· 서블릿은 web.xml의 <init-param> 태그를 이용해서 서블릿을 초기화할 때 필요한 값을 전달하는 방법을 제공함

 

<servlet>
	<init-param>
    	<param-name>jdbcdrvier</param-name>
        <param-value>com.mysql.jdbc.Driver</param-value>
    </init-param>
<servlet>

· <init-param> 태그의 자식 태그

   - <param-name> 태그: 초기화 파라미터의 이름을 지정

   - <param-value> 태그: 초기화 파라미터의 값을 지정

 

· 서블릿 클래스에서 초기화 파라미터에 접근하려면 getInitParamter() 메서드를 사용함

   - 이때, 초기화 파라미터가 존재하지 않으면 null을 리턴

String driverClass = getInitParameter("jdbcdriver");

 

· @WebServlet 애노테이션으로 매핑한 경우 초기화 파라미터를 전달하려면,

initParams 속성의 값으로 @WebInitParam 애노테이션 목록을 전달함

@WebServlet(urlPatterns = {"/hello", "/hello1"},
  initParams = {
      @WebInitParam(name="greeting", value="Hello"),
      @WebInitParam(name="title", value="제목")
  }
}

 

URL 패턴 매핑 규칙

· <url-pattern> 태그와 urlPatterns 속성에서 사용할 수 있는 URL 패턴이 어떻게 서블릿과 매핑되는가?

 

· URL 패턴이 서블릿을 매핑하는 규칙:

   - '/'로 시작하고 '/*'로 끝나는 url-pattern은 경로 매핑을 위해서 사용

   - '*.'로 시작하는 url-pattern은 확장자에 대한 매핑을 할 때 사용

   - 오직 '/'만 포함하는 경우 어플리케이션의 기본 서블릿으로 매핑

   - 이 규칙 외, 나머지 다른 문자열은 정확한 매핑을 위해 사용

 

▶ 예시 - URL 패턴에 따른 처리 서블릿

URL 패턴 매핑 서블릿
/foo/bar/* servlet1
/baz/* servlet2
/catalog servlet3
*.bop servlet4

· 위와 같은 URL 패턴을 설정한 경우 실제 요청 경로에 따라서 요청을 처리하는 서블릿

요청 경로 일치 URL 패턴 요청 처리 서블릿
/foo/bar/index.html /foo/bar/* servlet1
/foo/bar/index.bop /foo/bar/* servlet1
/baz /baz/* servlet2
/baz/index.html /baz/* servlet2
/catalog /catalog servlet3
/catalog/racecar.bop *.bop servlet4
/index.bop *.bop servlet4

 

TODO: 서블릿3에 추가된 비동기 서블릿 https://javacan.tistory.com/entry/Servlet-3-Async

 

출처

최범균의 JSP 2.3 웹프로그래밍 기초부터 중급까지

 

반응형

댓글