## 56. 웹 애플리케이션 자바 표준 기술 JavaEE 도입
- JavaEE 기술 소개
- JavaEE 버전 별 하위 기술 버전
- JavaEE 구현 서버 및 Servlet 컨테이너 관계
- Servlet API 사용법
gradle 설정
servlet-app/build.gradle
plugins {
id 'java'
id 'eclipse-wtp'
id 'war'
}
repositories {
mavenCentral()
}
dependencies {
// Servlet API
// => providedCompile?
// 컴파일 할 때만 사용하는 라이브러리
// 배포할 때 제외하는 라이브러리
// 배포 받는 쪽에서 라이브러리를 갖고 있을 때 이 옵션을 사용한다.
providedCompile 'javax.servlet:javax.servlet-api:4.0.1'
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
implementation 'com.google.guava:guava:31.1-jre'
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
tasks.named('test') {
useJUnitPlatform()
}
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
sourceCompatibility = '17'
targetCompatibility = '17'
}
// eclipse 프로젝트 이름을 설정하기
eclipse {
project {
name = "servlet-app"
}
jdt {
sourceCompatibility = 17
targetCompatibility = 17
javaRuntimeName = "JavaSE-17"
}
wtp {
facet {
facet name: 'jst.java', version: '17'
//facet name: 'jst.web', version: '4.0'
}
component {
contextPath = '/'
//deployName = 'web'
}
}
}
war {
archiveBaseName = "servlet-app"
}
ㄴ gradle 설정
=>
ㄴ gradle 재설정 해주기
=>
테스트 서버 준비하기
=>
=>
=>
패키지 및 클래스 준비
ㄴ eomcs.servlet.ex01 패키지 생성
ㄴ Servlet01 클래스 파일 생성
Servlet01.java
package eomcs.servlet.ex01;
// 서블릿 만들기 - javax.servlet.Servlet 인터페이스 구현
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
// 서블릿 클래스를 만든 후, 서블릿 컨테이너에 등록해야만 사용할 수 있다.
// 등록 방법 1)
// 웹 애플리케이션 배치 파일(web.xml; DD(Deploy Description) 파일)에 서블릿 정보를 등록한다.
// => WEB-INF/web.xml
// => DD File: Deployment Descriptor File
// => 배치 예:
// <servlet>
// <servlet-name>서블릿별명</servlet-name>
// <servlet-class>서블릿 클래스의 전체이름(패키지명 포함)</servlet-class>
// </servlet>
//
// <servlet-mapping>
// <servlet-name>서블릿별명</servlet-name>
// <url-pattern>클라이언트에서 요청할 때 사용할 URL(/로 시작해야 한다.)</url-pattern>
// </servlet-mapping>
// 등록 방법 2)
// 서블릿 클래스 선언부에 @WebServlet 애노테이션을 붙인다.
// => @WebServlet
// @WebServlet(URL)
// @WebServlet(value=URL)
// @WebServlet(urlPatterns={"URL1", "URL2", ...})
//
// 서블릿 실행 방법
// => http://서버주소:포트번호/웹애플리케이션이름/서블릿URL
// 예) http://localhost:8080/eomcs-java-web/ex01/s01
//
// 서블릿 구동 과정
// 1) 웹 브라우저가 서블릿 실행을 요청한다.
// 2) 서블릿 컨테이너는 해당 URL의 서블릿 객체를 찾는다.
// 3.1) 서블릿 객체를 아직 만들지 않았다면,
// => 서블릿 클래스에 대해 인스턴스를 생성한다.
// => 생성자를 호출한다.
// => init()를 호출한다.
// => service()를 호출한다.
// 3.2) 서블릿 객체가 생성되어 있다면,
// => service()를 호출한다.
//
// 만약 웹 애플리케이션이 종료된다면
// => 생성된 모든 서블릿들의 destroy() 메서드를 호출한다.
//
// 결론!
// => 특별한 옵션을 주지 않으면 클라이언트가 최초로 요청했을 때 서블릿 인스턴스를 생성한다.
// => 그리고 그 서블릿 인스턴스는 클래스 마다 오직 한 개만 생성된다.
// => init(), destroy()은 오직 한 번만 호출된다.
// => service()는 클라이언트가 요청할 때 마다 호출된다.
//
// 주의!
// => 서블릿 인스턴스는 오직 클래스 마다 한 개만 생성된다.
// 그래서 모든 클라이언트가 같은 서블릿 인스턴스를 사용한다.
// => 클라이언트마다 구분되어야 할 데이터는
// 서블릿 인스턴스 변수에 보관해서는 안된다.
// => 왜?
// 인스턴스는 모든 클라이언트가 공유하기 때문이다.
//
@WebServlet("/ex01/first")
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 {
HttpServletRequest req2 = (HttpServletRequest) req;
HttpServletResponse res2 = (HttpServletResponse) res;
// 클라이언트가 이 서블릿의 실행을 요청할 때마다 호출된다.
// 클라이언트가 요청한 작업을 수행한다.
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";
}
}
=>
=>
=>
=>
=>
=>
=>
=>
web.xml
=>
ㄴ 톰캣 경로에 있는 web.xml 파일 VsCode 로 열기
=>
ㄴ 해당 코드 복사
=>
servlet-app
web.xml
ㄴ 복사한 코드 붙여넣기
=>
servlet-app
web.xml
=>
=>
=>
=>
servlet-app
web.xml
ㄴ metadata-complete 를 "false" 로 변경해줌
=>
=>
=>
=>
=>
=>
ㄴ Servers 탭에 있는 우측에 빨간 정지버튼 선택 시 아래와 같이 출력됨
=>
서버 restart
=>
ㄴ 브라우저에서 요청할 때마다 위와 같이 출력됨을 확인
=>
servlet-app
web.xml
ㄴ Servlet02 클래스 파일 생성
Servlet02.java
// 서블릿 만들기 - javax.servlet.GenericServlet 추상 클래스 상속
package eomcs.servlet.ex01;
import java.io.IOException;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
// GenericServlet 추상 클래스
// => javax.servlet.Servlet 인터페이스를 구현하였다.
// => service() 메서드만 남겨두고 나머지 메서드들은 모두 구현하였다.
// => 따라서 이 클래스를 상속 받는 서브 클래스는 service() 만 구현하면 된다.
//
// @WebServlet 애노테이션
// => web.xml 에 서블릿 정보를 설정하는 대신에
// 이 애노테이션을 사용하여 서블릿을 설정할 수 있다.
// => 이 애노테이션을 활성화시키려면
// web.xml의 <web-app> 태그에 다음 속성을 추가해야 한다.
// metadata-complete="false"
// 속성의 값은 false 여야 한다.
//
// @WebServlet(urlPatterns={"/ex01/s2","/ex01/ss2","/ex01/sss2"})
// @WebServlet(urlPatterns={"/ex01/s2"})
// @WebServlet(urlPatterns="/ex01/s2")
// @WebServlet(value="/ex01/s2")
@WebServlet("/ex01/s2")
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)");
}
}
ㄴ Servlet03.java 클래스 파일 생성
=>
Servlet03.java
=>
Servlet03.java
=>
Servlet03.java
=>
Servlet03.java
=>
=>
=>
=>
Servlet03.java
=>
=>
=>