Servlet 01: 서블릿 만들기
비트캠프 서초본원 엄진영 강사님의 수업을 듣고 정리했습니다.
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)");
}
}