- 서블릿 프로그래밍
- 서블릿, 필터, 리스너 컴포넌트 만들고 배치하는 방법
- 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 해주기
=>
=>
ㄴ 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() 호출됨을 확인
=>
=>
=>
=>
ㄴ 세 번 요청한 결과
=>
=>
ㄴ 한 번 더 요청한 결과