본문 바로가기
네이버클라우드/JAVA 웹 프로그래밍

JAVA 62일차 (2023-08-21) 자바 프로그래밍_Servlet 정리_ex01~ex02

by prometedor 2023. 8. 21.
- 서블릿 프로그래밍
  - 서블릿, 필터, 리스너 컴포넌트 만들고 배치하는 방법
  - GET/POST/PUT 등 요청 메서드를 구분하는 방법
  - 요청 파라미터 값을 꺼내는 방법
  - multipart/form-data 로 전송된 파라미터 값을 다루는 방법
  - 썸네일 이미지를 생성하는 방법
  - HttpServlet 클래스의 역할 이해

 

Servlet 정리

servlet-app 프로젝트

build.gradle (servlet-app)

ㄴ 이제 인텔리제이를 사용하므로 이클립스 설정 주석 처리 해주기

=>

ㄴ settings.gradle (servlet-app)

ㄴ eomcs-app => servlet-app 으로 변경해주기

=>

build.gradle (servlet-app)

ㄴ Servlet API 설정 주석 처리 해주기

=>

build.gradle (app-server)

ㄴ 설정하는 김에 myapp(루트 프로젝트)에 있는 app-server(메인 프로젝트) 의 build.gradle 스크립트 파일도 수정해주도록 함

=>

build.gradle (servlet-app)

ㄴ servlet-app 도 임베디드 Tomcat 서버 설정을 위해 해당 코드 추가

=>

ㄴ gradle clean 을 실행해줌

ㄴ eclipse 설정은 모두 주석처리 해줬으므로 gradle cleanEclipse 는 실행할 필요 없음

=>

ㄴ app(메인 프로젝트) 바로 밑에 있는 .settings 삭제

=>

ㄴ bin 은 이클립스에서 사용하는 폴더이므로 삭제

=>

ㄴ .classpath, .project 파일도 이클립스에서 사용하는 파일이므로 삭제

=>

ㄴ servlet-app (루트 프로젝트) 바로 아래 있는 .gradle 삭제하기

=>

.gitignore

ㄴ 모든 실행 파일, node_modules, temp 는 git 에 commit 되지 않도록 .gitignore 파일 수정해주기

    ㄴ *.exe => 확장자가 .exe인 실행 파일을 무시하도록 함
    ㄴ node_modules/ => Node.js 프로젝트에서 생성되는 node_modules 폴더를 무시하도록 함

    ㄴ temp/ => temp 폴더를 무시하도록 함(임시 파일이나 캐시 파일 등이 위치할 수 있는 폴더)

 

 

servlet-app 프로젝트 Open 하기

ㄴ /Users/사용자명/git/bitcamp-study/servlet-app/settings.gradle > [Open] 선택

=>

ㄴ [Open as Project] 선택

=>

ㄴ [Trust Project] 선택

=>

ㄴ [This Window] 선택

=>

ㄴ 현재 사용하는 파일만 보이도록 해줌

=>

ㄴ servlet-app > app > main > java > eomcs 폴더에 App 이라는 이름의 새로운 자바 클래스 파일을 생성

=>

ㄴ [Add] 선택

=>

App.java (app-server)

ㄴ app-server(메인 프로젝트)의 App.java 파일 코드 복사하기

=>

App.java (servlet-app)

ㄴ 패키지를 제외하고 복사한 코드 붙여넣기

=>

App.java (servlet-app)

ㄴ Gradle 창에서 servlet-app > Tasks > build > build 더블 클릭하여 실행하기

=>

ㄴ 에러 발생

=>

build.gradle (app-server)

ㄴ app-server 프로젝트의 builde.gradle 에서 multipart/form-data 처리 라이브러리 코드 복사하기

=>

build.gradle (servlet-app)

ㄴ 복사한 코드 붙여넣기

=>

ㄴ Gradle 탭을 통해 build 해주기

=>

https://central.sonatype.com/

 

Maven Central

Official search by the maintainers of Maven Central Repository.

central.sonatype.com

=>

ㄴ thumbnailator 검색 후 thumbnailator 0.4.20 선택

=>

ㄴ [Copy to clipboard] 선택하여 해당 Gradle (short) 코드 복사하기

=>

build.gradle (servlet-app/app)

ㄴ 복사한 코드 붙여넣기

=>

build.gradle (servlet-app/app)

ㄴ Gradle 탭을 통해 build 실행

=>

ㄴ Add unambiguous imports on the fly 체크

ㄴ Optimize imports on the fly 체크

=>

ㄴ [option] + [Enter] 이용하여 import 처리하기

=>

App.java

ㄴ Current File 선택 > [재생] 아이콘 선택

=>

ㄴ 해당 에러 발생

=>

ㄴ App.java 우클릭 > More Run/Debug > Modify Run Configuration... 선택하기

=>

ㄴ Working directory > 폴더 아이콘 선택

ㄴ 경로에 app 까지 추가해주기

=>

ㄴ [OK] 선택

=>

ㄴ App.java 실행

=>

=>

ㄴ [정지] 버튼 선택

=>

ㄴ 강제 중지

=>

ㄴ 이미 생성되어있는 temp 폴더 삭제해주기

=>

=>

ㄴ 서버 재 실행하여 temp 폴더 새로 추가되도록 해줌

ㄴ 대신 위에서 삭제한 temp 폴더가 있던 경로에 추가되는 것이 아니라 app 바로 밑에 추가됨

=>

=>

WEB-INF > index.html

ㄴ 해당 파일이 실행되는 것임

=>

=>

=>

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";
  }

}

=>

=>

ㄴ service 메서드는 요청 할 때마다 호출됨

=>

ㄴ [command] + [F12] 를 이용하여 Eclipse 에서의 outline 과 같은 기능 이용 가능 (한 번 더 누르면 상속된 메서드도 확인 가능)

=>

=>

Servlet02.java

ㄴ GenericServlet 을 상속받음

=>

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)");
  }
}

ㄴ GenericServlet 클래스를 상속 받는 서브 클래스는 service() 만 구현하면 됨

=>

Servlet03.java

=>

ㄴ ServletRequest와 ServletResponse를 HttpServletRequest와 HttpServletResponse로 형변환함

    ㄴ 이는 일반적으로 서블릿이 HTTP 요청을 처리하기 위해 사용되는 타입을 사용하기 위한 것

ㄴ 위의 형변환이 성공하면 HttpServletRequest와 HttpServletResponse로 형변환된 객체들을 이용하여 실제 service 메서드를 호출함 => HTTP 요청을 처리하는 로직을 실행하게 됨

=>

Servlet03.java

package eomcs.servlet.ex01;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebServlet("/ex01/s3")
public class Servlet03 extends HttpServlet {
  private static final long serialVersionUID = 1L;

  @Override
  protected void service(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {

    System.out.println("Servlet03.service() 호출됨!");

    HttpSession session = req.getSession();
    resp.sendRedirect("/ex01/s2");
  }

}

=>

 

 

ㄴ ex02 패키지 생성하기

=>

ㄴ /Users/사용자명/git/eomcs-java/eomcs-servlet/app/src/main/java/com/eomcs/web/ex02 에 존재하는 파일 모두 복사

=>

ㄴ 복사한 파일들 인텔리제이에서 ex02 폴더에 붙여넣기 > [OK] 선택

=>

패키지 자동으로 알맞게 변경됨

=>

Servlet01.java (ex02)

=>

Servlet01.java (ex02)

// 필터나 리스너를 테스트하기 위한 서블릿
package eomcs.servlet.ex02;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;

@WebServlet("/ex02/s1")
public class Servlet01 extends GenericServlet {

  private static final long serialVersionUID = 1L;

  @Override
  public void service(ServletRequest req, ServletResponse res)
      throws ServletException, IOException {
    System.out.println("/ex02/s1 서블릿 실행!");
  }
}

ㄴ @WebServlet("/ex02/s1") 주석 풀어주어 선언

 

Filter01.java

package eomcs.servlet.ex02;

import javax.servlet.*;
import java.io.IOException;

// 서블릿 컨테이너가 관리하는 컴포넌트
// => 서블릿, 필터, 리스너
//
// 필터 만들기
// => javax.servlet.Filter 인터페이스 규칙에 따라 작성한다.
//
// 필터 배포하기
// => DD 파일(web.xml)에 설정하기
//      <!-- 필터 등록 -->
//      <filter>
//          <filter-name>f01</filter-name>
//          <filter-class>com.eomcs.web.ex02.Filter01</filter-class>
//      </filter>
//
//      <!-- 필터를 적용할 URL 설정 -->
//      <filter-mapping>
//          <filter-name>f01</filter-name>
//          <url-pattern>/ex02/*</url-pattern>
//      </filter-mapping>
// => 애노테이션으로 설정하기
//      @WebFilter(URL)
//
// 필터의 용도
// => 서블릿을 실행하기 전후에 필요한 작업을 수행
// => 서블릿 실행 전
// - 웹브라우저가 보낸 암호화된 파라미터 값을 서블릿으로 전달하기 전에 암호 해제하기
// - 웹브라우저가 보낸 압축된 데이터를 서블릿으로 전달하기 전에 압축 해제하기
// - 서블릿의 실행을 요청할 권한이 있는지 검사하기
// - 로그인 사용자인지 검사하기
// - 로그 남기기
// => 서블릿 실행 후
// - 클라이언트로 보낼 데이터를 압축하기
// - 클라이언트로 보낼 데이터를 암호화시키기
//
@WebFilter("/ex02/*")
public class Filter01 implements Filter {

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
    // 웹 애플리케이션을 시작할 때 필터 객체를 생성한다.
    // 이 메서드는 필터 객체를 생성한 후 자동으로 호출된다.
    // 필터가 사용할 자원을 이 메서드에서 준비한다.
    // => 웹 애플리케이션을 시작할 때 필터는 자동 생성된다.
    System.out.println("Filter01.init()");
  }

  @Override
  public void destroy() {
    // 웹 애플리케이션을 종료할 때 호출된다.
    // init()에서 준비한 자원을 해제한다.
    System.out.println("Filter01.destroy()");
  }

  @Override
  public void doFilter(
      ServletRequest request,
      ServletResponse response,
      FilterChain chain)
          throws IOException, ServletException {
    // 요청이 들어 올 때 마다 호출된다.
    // => 단 필터를 설정할 때 지정된 URL의 요청에만 호출된다.
    // => 서블릿이 실행되기 전에 필터가 먼저 실행된다.
    // => 서블릿을 실행한 후 다시 필터로 리턴한다.
    System.out.println("Filter01.doFilter() : 시작");

    // 다음 필터를 실행한다.
    // 만약 다음 필터가 없으면,
    // 요청한 서블릿의 service() 메서드를 호출한다.
    // service() 메서드 호출이 끝나면 리턴된다.
    chain.doFilter(request, response);

    // 체인에 연결된 필터나 서블릿이 모두 실행된 다음에
    // 다시 이 필터로 리턴될 것이다.
    System.out.println("Filter01.doFilter() : 종료");
  }
}

ㄴ 필터 객체는 웹 애플리케이션을 시작할 때 생성됨

=>

ㄴ App 실행 시 Filter01.init() 실행됨을 확인

=>

ㄴ 콘솔 우클릭 > Clear All 선택

=>

=>

ㄴ Filter 는 서블릿을 실행하기 전후에 필요한 작업을 수행할 수 있도록 해줌

=>

Filter02.java

package eomcs.servlet.ex02;

import javax.servlet.*;
import java.io.IOException;

// 서블릿 컨테이너가 관리하는 컴포넌트
// => 서블릿, 필터, 리스너
//
// 필터 만들기
// => javax.servlet.Filter 인터페이스 규칙에 따라 작성한다.
//
// 필터 배포하기
// => DD 파일(web.xml)에 설정하거나 애노테이션으로 설정하면 된다.
// => 다음과 같이 애노테이션으로 할 수도 있다.
//
// 필터 실행 순서
// => 필터의 실행 순서를 임의로 조정할 수 없다.
// => 필터를 정의할 때 순서에 의존하는 방식으로 프로그래밍 하지 말라.
// => 필터의 실행 순서에 상관없이 각 필터가 독립적으로 동작하도록 작성하라.

@WebFilter("/ex02/a/*")
public class Filter02 implements Filter {

  @Override
  public void init(FilterConfig filterConfig) throws ServletException {
    // 필터 객체를 생성한 후 제일 처음으로 호출된다.
    // 필터가 사용할 자원을 이 메서드에서 준비한다.
    System.out.println("Filter02.init()");
  }

  @Override
  public void destroy() {
    // 웹 애플리케이션이 종료될 때 호출된다.
    // init()에서 준비한 자원을 해제한다.
    System.out.println("Filter02.destroy()");
  }

  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    // 요청이 들어 올 때 마다 호출된다.
    // => 단 필터를 설정할 때 지정된 URL의 요청에만 호출된다.
    // => 서블릿이 실행되기 전에 필터가 먼저 실행된다.
    // => 서블릿을 실행한 후 다시 필터로 리턴한다.
    System.out.println("Filter02.doFilter() : 시작");

    // 다음 필터를 실행하거나 요청한 서블릿을 실행하려면 다음 코드를 반드시 실행해야 한다.
    chain.doFilter(request, response);

    // 체인에 연결된 필터나 서블릿이 모두 실행된 다음에 다시 이 필터로 리턴될 것이다.
    System.out.println("Filter02.doFilter() : 종료");
  }
}

=>

ㄴApp 실행 시 Filter01 과 Filter02 모두 실행됨을 확인

=>

Servlet02.java (ex02)

// 필터나 리스너를 테스트하기 위한 서블릿
package eomcs.servlet.ex02;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;

@WebServlet("/ex02/a/s2")
public class Servlet02 extends GenericServlet {

  private static final long serialVersionUID = 1L;

  @Override
  public void service(ServletRequest req, ServletResponse res)
      throws ServletException, IOException {
    System.out.println("/ex02/a/s2 서블릿 실행!");
  }
}

=>

=>

=>

ㄴ 해당 순서로 실행됨을 확인

=>

Filter02.java

ㄴ doFilter 메서드는 요청이 들어 올 떄마다 호출됨

=>

Listener01.java

package eomcs.servlet.ex02;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

// 서블릿 컨테이너가 관리하는 컴포넌트
// => 서블릿, 필터, 리스너
//
// 리스너 만들기
// => 서블릿 컨테이너 또는 서블릿, 세션 등의 객체 상태가 변경되었을 때 보고 받는 옵저버
// => "Observer" 디자인 패턴이 적용된 것이다.
// => ServletContextListener
//    - 서블릿 컨테이너를 시작하거나 종료할 때 보고 받고 싶다면 이 인터페이스를 구현하라.
// => ServletRequestListener
//    - 요청이 들어오거나 응답할 때 보고 받고 싶다면 이 인터페이스를 구현하라.
// => HttpSessionListener
//    - 세션이 생성되거나 종료될 때 보고 받고 싶다면 이 인터페이스를 구현하라.
// => XxxListener
//    - 기타 다양한 인터페이스가 있다. 문서를 참고하라.
//
// 리스너 배포하기
//=> DD 파일(web.xml)에 설정하기
//      <listener>
//          <listener-class>com.eomcs.web.ex02.Listener01</listener-class>
//      </listener>
//
//=> 애노테이션으로 설정하기
//      @WebListener
//
// 리스너의 용도
// => 서블릿 컨테이너나, 세션 등이 특별한 상태일 때 필요한 작업을 수행한다.
// => ServletContextListener
//    - 웹 애플리케이션을 시작할 때 Spring IoC 컨테이너 준비하기
//    - 웹 애플리케이션을 시작할 때 DB 커넥션 풀 준비하기
//    - 웹 애플리케이션을 종료할 때 DB 커넥션 풀에 들어 있는 모든 연결을 해제하기
// => ServletRequestListener
//    - 요청이 들어 올 때 로그 남기기
//
//
@WebListener
public class Listener01 implements ServletContextListener {

  public Listener01() {
    System.out.println("Listener01() 호출됨!");
  }

  @Override
  public void contextInitialized(ServletContextEvent sce) {
    // 웹 애플리케이션이 시작될 때 호출된다.
    System.out.println("Listener01.contextInitialized()");
  }

  @Override
  public void contextDestroyed(ServletContextEvent sce) {
    // 웹 애플리케이션이 종료될 때 호출된다.
    System.out.println("Listener01.contextDestroyed()");
  }
}

=>

App 실행

=>

ㄴ contextInitialized 메서드는 웹 애플리케이션이 시작될 때 호출됨을 확인

=>

App.java

ㄴ 종료될 때까지 JVM 을 끝내지 말고 기다리는 코드 주석 처리 해주기

ㄴ 엔터를 치면 서버를 종료하도록 함

=>
App 실행

=>

=>

ㄴ 서버 종료 시 Filter01, Filter02 의 destroy 메서드 호출됨을 확인

ㄴ 서버 종료 시 Listener01 의 contextDestroyed 메서드 호출됨을 확인

 

Listener02.java

package eomcs.servlet.ex02;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
// 리스너 만들기
// => 서블릿 컨테이너 또는 서블릿, 세션 등의 객체 상태가 변경되었을 때 보고 받는 옵저버
// => "Observer" 디자인 패턴이 적용된 것이다.
// => ServletContextListener
//    - 서블릿 컨테이너를 시작하거나 종료할 때 보고 받고 싶다면 이 인터페이스를 구현하라.
// => ServletRequestListener
//    - 요청이 들어오거나 종료될 때 보고 받고 싶다면 이 인터페이스를 구현하라.
// => HttpSessionListener
//    - 세션이 생성되거나 종료될 때 보고 받고 싶다면 이 인터페이스를 구현하라.
// => XxxListener
//    - 기타 다양한 인터페이스가 있다. 문서를 참고하라.
//
// 리스너 배포하기
// => DD 파일(web.xml)에 설정하거나 애노테이션으로 설정하면 된다.
//
// 리스너의 용도
// => 서블릿 컨테이너나, 세션 등이 특별한 상태일 때 필요한 작업을 수행한다.
// => ServletContextListener
//    - 웹 애플리케이션을 시작할 때 Spring IoC 컨테이너 준비하기
//    - 웹 애플리케이션을 시작할 때 DB 커넥션 풀 준비하기
//    - 웹 애플리케이션을 종료할 때 DB 커넥션 풀에 들어 있는 모든 연결을 해제하기
// => ServletRequestListener
//    - 요청이 들어 올 때 로그 남기기
//
//
@WebListener
public class Listener02 implements ServletRequestListener {

  public Listener02() {
    System.out.println("Listener02() 호출됨!");
  }

  @Override
  public void requestInitialized(ServletRequestEvent sre) {
    // 요청이 들어 왔을 때 호출된다.
    System.out.println("Listener02.requestInitialized()");
    HttpServletRequest request = (HttpServletRequest) sre.getServletRequest();
    System.out.println("클라이언트 IP: " + request.getRemoteAddr());
    System.out.println("요청 URL: " + request.getServletPath());
  }

  @Override
  public void requestDestroyed(ServletRequestEvent sre) {
    // 요청 처리를 완료할 때 호출된다.
    System.out.println("Listener02.requestDestroyed()");
  }
}

=>

App 실행

=>

ㄴ Listener02() 호출됨을 확인

=>

=>

=>

=>

ㄴ 세 번 요청한 결과

=>

=>

ㄴ 한 번 더 요청한 결과