Servlet 01: 서블릿 만들기

업데이트:
3 분 소요

비트캠프 서초본원 엄진영 강사님의 수업을 듣고 정리했습니다.


Servlet 01: 서블릿 만들기

  • Servlet 인터페이스를 구현해야 한다. 하지만 Servlet 인터페이스를 구현하려면, 5가지 메서드를 모두 구현해야 한다.
  • 필요 없는 메서드까지 모두 구현하기는 힘들기 때문에 GenericServlet이라는 추상클래스를 상속받아 구현하기도 한다. GenericServlet은 Servlet 인터페이스를 상속받은 추상클래스인데, service()를 제외한 나머지 4개의 메서드를 구현했다. 따라서 GenericServlet을 상속받으면 service()만 구현하면 된다.
  • 그런데, HTTP 프로토콜을 다루려면 GenericServlet을 상속 받지 말고 HttpServlet을 상속 받아 서블릿 클래스를 만들면 된다.

1. javax.servlet.Servlet 인터페이스 구현

서블릿 생성 후 배포

서블릿 클래스를 만든 후, 배치 파일(web.xml; DD 파일)에 서블릿 정보를 등록해야만 실행될 수 있다.

  • WEB-INF/web.xml
  • DD File: Deployment Descriptor File
  • 배치 예:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  version="4.0"
  metadata-complete="false">

<!-- 서블릿 등록 -->
	<servlet>
		<servlet-name>서블릿별명</servlet-name>
		<servlet-class>서블릿 클래스의 전체이름(패키지명 포함)</servlet-class>
	</servlet>

<!-- 서블릿을 실행할 때 사용할 URL path를 설정 -->
	<servlet-mapping>
		<servlet-name>서블릿별명</servlet-name>
		<url-pattern>클라이언트에서 요청할 때 사용할 URL(/로 시작해야 한다.)</url-pattern>
	</servlet-mapping>

	</web-app>
  • web.xml을 수정한 후에는 반드시 서버를 재시작 해야한다.

서블릿 실행 방법

  • 배치 파일(web.xml; DD 파일)에 서블릿 정보를 등록한다.
  • http://서버주소:포트번호/웹애플리케이션이름/서블릿URL
  • 예) http://localhost:8080/eomcs-java-web/ex01/first

서블릿 구동 과정

1) 웹 브라우저가 서블릿 실행을 요청한다.

2) 서블릿 컨테이너는 해당 URL의 서블릿 객체를 찾는다.

3.1) 서블릿 객체를 아직 만들지 않았다면,

  • 서블릿 클래스에 대해 인스턴스를 생성한다.
  • 생성자를 호출한다.
  • init()를 호출한다.
  • service()를 호출한다.

3.2) 서블릿 객체가 생성되어 있다면,

  • service()를 호출한다.

4) 만약 웹 애플리케이션이 종료된다면 생성된 모든 서블릿들의 destroy() 메서드를 호출한다.

결론!

  • 특별한 옵션을 주지 않으면 클라이언트가 최초로 요청했을 때 서블릿 인스턴스를 생성한다.
  • 그리고 그 서블릿 인스턴스는 클래스 마다 오직 한 개만 생성된다.
  • init(), destroy()은 오직 한 번만 호출된다.
  • service()는 클라이언트가 요청할 때 마다 호출된다.

주의!

  • 서블릿 인스턴스는 오직 클래스 마다 한 개만 생성된다.
  • 그래서 모든 클라이언트가 같은 서블릿 인스턴스를 사용한다.
  • 클라이언트마다 구분되어야 할 데이터는 서블릿 인스턴스 변수에 보관해서는 안된다.
    • 왜? 인스턴스는 모든 클라이언트가 공유하기 때문이다.
public class Servlet01 implements Servlet {

  ServletConfig config;

  public Servlet01() {
    System.out.println("Servlet01()");
  }

  @Override
  public void init(ServletConfig config) throws ServletException {
    // 서블릿 객체를 생성한 후 생성자 다음에 이 메서드가 호출된다.
    // => 서블릿을 실행할 때 사용할 자원을 이 메서드에서 준비한다.
    // => 파라미터로 받은 ServletConfig 객체는 인스턴스 변수에 보관해 두었다가 필요할 때 사용한다.
    // => 각각의 서블릿 클래스마다 객체는 한 개만 생성된다.
    // => 따라서 각 서블릿에 대해 init()는 한 번만 호출된다.
    this.config = config;
    System.out.println("Servlet01.init(ServletConfig)");
  }

  @Override
  public void service(ServletRequest req, ServletResponse res)
      throws ServletException, IOException {
    // 클라이언트가 이 서블릿의 실행을 요청할 때마다 호출된다.
    // 클라이언트가 요청한 작업을 수행한다.
    System.out.println("Servlet01.service(ServletRequest,ServletResponse)");
  }

  @Override
  public void destroy() {
    // 웹 애플리케이션을 종료할 때(서버 종료 포함) 호출된다.
    // => 이 서블릿이 만든 자원을 해제하는 코드를 이 메서드에 둔다.
    System.out.println("Servlet01.destroy()");
  }

  @Override
  public ServletConfig getServletConfig() {
    // 서블릿에서 작업을 수행하는 중에 서블릿 관련 설정 정보를 꺼낼 때 이 메서드를 호출한다.
    // 이 메서드가 리턴하는 값이 ServletConfig 객체인데
    // 이 객체를 이용하면 서블릿 설정 정보를 알 수 있다.
    // 보통 init()의 파라미터 값을 리턴한다.
    System.out.println("Servlet01.getServletConfig()");
    return this.config;
  }

  @Override
  public String getServletInfo() {
    // 서블릿 컨테이너가 관리자 화면을 출력할 때 이 메서드를 호출한다.
    // 이 메서드의 리턴 값은 서블릿을 소개하는 간단한 문자열이다.
    System.out.println("Servlet01.getServletInfo()");
    return "Servlet01";
  }

}

2. javax.servlet.GenericServlet 추상 클래스 상속

GenericServlet 추상 클래스

  • javax.servlet.Servlet 인터페이스를 구현하였다.
  • service() 메서드만 남겨두고 나머지 메서드들은 모두 구현하였다.
  • 따라서 이 클래스를 상속 받는 서브 클래스는 service() 만 구현하면 된다.
public class Servlet02 extends GenericServlet {
  // GenericServlet 추상 클래스는 java.io.Serialize 인터페이스를 구현하였다.
  // => serialVersionUID 변수 값을 설정해야 한다.
  private static final long serialVersionUID = 1L;

  public Servlet02() {
    System.out.println("Servlet02()");
  }

  @Override
  public void service(ServletRequest req, ServletResponse res)
      throws ServletException, IOException {
    System.out.println("Servlet02.service(ServletRequest,ServletResponse)");
  }
}

3. javax.servlet.http.HttpServlet 추상 클래스 상속

  • 실무에서 가장 많이 사용하는 방법

HttpServlet 추상 클래스

  • javax.servlet.GenericServlet 추상 클래스를 상속 받았다.
  • service() 메서드도 구현했다.
  • service() 메서드는 웹브라우저가 요청한 명령에 따라 doGet(), doPost(), doHead(), doPut() 등을 호출하게 프로그램 되어 있다.
  • HTTP 프로토콜을 다루려면 GenericServlet을 상속 받지 말고 HttpServlet을 상속 받아 서블릿 클래스를 만들라!
public class Servlet03 extends HttpServlet {
  
  // GenericServlet 추상 클래스가 java.io.Serialize 인터페이스를 구현하였고,
  // HttpServlet 클래스가 GenericServlet 추상 클래스를 상속 받았으니
  // HttpServlet 클래스를 상속 받는 이 클래스도 마찬가지로
  // serialVersionUID 변수 값을 설정해야 한다.
  private static final long serialVersionUID = 1L;

  // service()를 오버라이딩 하는 대신에
  // doGet(), doPost(), doHead() 등을 오버라이딩 하라.
  // 호출과정:
  // => 웹브라우저
  //   => 톰캣 서버
  //     => Servlet03.service(ServletRequest, ServletResponse) 
  //       => Serlvet03.service(HttpServletRequest, HttpServletResponse)
  //         => Servlet03.doGet(HttpServletRequest, HttpServletResponse)
  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse res)
      throws ServletException, IOException {
    System.out.println("Servlet03.doGet(HttpServletRequest,HttpServletResponse)");
  }
}

4.@WebServlet 애노테이션

@WebServlet 애노테이션

  • web.xml 에 서블릿 정보를 설정하는 대신에 이 애노테이션을 사용하여 서블릿을 설정할 수 있다.
  • 이 애노테이션을 활성화시키려면 web.xml의 태그에 다음 속성을 추가해야 한다.
    • metadata-complete=”false”
    • 속성의 값은 false 여야 한다.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                      http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
  version="4.0"
  metadata-complete="false">

...

</web-app>
@WebServlet("/ex01/fourth")
public class Servlet04 extends GenericServlet {
  
  private static final long serialVersionUID = 1L;

  @Override
  public void service(ServletRequest req, ServletResponse res)
      throws ServletException, IOException {
    System.out.println("Servlet04.service(ServletRequest,ServletResponse)");
  }
}

태그:

카테고리:

업데이트: