<< 학습 목표 >>
1. Context와 ServletContext를 설명할 수 있다.
서블릿으로 개발하다 보면 ServletContext와 ServletConfig 타입 객체를 사용해야하는 경우가 종종 생김
여기서는 ServletContext 타입 객체가 무엇이고 이 객체들을 통해서 어떤것들을 할 수 있는지 알아보자
우선 컨텍스트(Context) 가 있음
컨텍스트란 웹 프로젝트의 정보를 뜻함
웹 프로젝트 이름은 무엇이고 웹 프로젝트는 어느 경로에 있고, 웹 프로젝트가 동작하는 서버의 정보는 어떻게 되고 등 웹 프로젝트의 정보를 담고 있는 것이 컨텍스트임
이 컨텍스트는 웹 프로젝트의 정보이므로 웹 프로젝트 마다 하나씩 생성됨
이 컨텍스트는 C 드라이브에 있는 톰캣의 경우에는 [ C 드라이브 내 톰캣 ] -> [ conf 폴더 ] -> [ server.xml ] 파일을 보면 Context 태그로 등록 되어있음
이클립스에 있는 톰캣의 경우에는 이클립스 왼쪽에 [ Explorer 창 ] -> [ Servers ] -> [ Tomcat ~ ] -> [ server.xml ] 파일을 보면 마찬가지로 Context 태그로 등록 되어있음
이 컨텍스트 태그에다가 웹 프로젝트와 관련된 여러 정보를 등록해둬야함
아직 우리는 그렇게 세세하게 웹 프로젝트 정보를 설정할 일이 없으므로 "그렇구나" 정도로만 기억해두면 됨
서블릿 안에서도 이 컨텍스트를 가져와서 웹 프로젝트의 정보를 확인해야되는 경우가 종종 생기는데 서블릿이 컨텍스트를 가져올 때 사용하는 객체가 ServletContext 임
위 이미지에서 [ 웹 프로젝트1 ] 만 더 확대한 그림을 보자
웹 프로젝트 안에는 HTML, CSS, JS, 서블릿(Servlet), JSP 등등이 들어있을 것
서블릿은 서블릿 컨테이너(ServletContainer)에 의해서 동작함
서블릿 컨테이너는 서블릿에서 웹 프로젝트의 정보가 필요할 때, 즉 컨텍스트가 필요할 때를 위해서 ServletContext 타입 객체를 갖고 있음
이 객체 안에는 컨텍스트가 가지고 있는 웹 프로젝트의 정보가 들어있음
위 그림에서 연결해놓은것처럼 컨텍스트(웹 프로젝트의 정보)는 ServletContext와 같다고 보면 됨
어떤 서블릿에서 ServletContext가 필요하다면 ServletContext를 가져다 사용할 수 있음
또한 회원 가입 서블릿에서 ServletContext에 무언가를 저장해두면 다른 서블릿에서는 ServletContext를 통해서 회원 가입 서블릿에서 저장해둔 값을 꺼낼 수도 있음
ServletContext 를 활용한 간단한 예시 서비스를 보자
우리 서비스에 어떤 경로로 접근했든 오늘의 방문자 수를 알고 싶은 상황임
그리고 방문자 수는 매 서비스 마다 카운팅을 하고 싶음
우리 서비스의 방문자 수가 0명인 상태에서 철수가 우리 서비스의 A 페이지로 바로 접속을 했다면 방문자 수가 1명이 됨
그 후 철수가 이어서 B 페이지로 접속을 했다면 방문자 수가 2명이 되도록 하고 싶은 상황
상식적으로 생각해보면 "방문자 수는 1명 아닌가?" 싶지만 그런 처리를 하려면 굉장히 복잡하고 또 다른 방향으로 깊은 얘기를 해야하므로 그런건 고려하지 않을 예정
그리고 이건 ServletContext 를 경험하기 위한 예시 상황으로 실제 서비스에서 방문자 수를 체크할 때는 ServletContext 로 체크하지 않음
chapter04 -> service1, service2 서블릿을 만들고 아래 코드를 각 서블릿에 차례대로 입력하자
package chapter04;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/chapter04/service_1")
public class Service1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext sc = getServletContext();
int count = 0;
if(sc.getAttribute("count") != null) {
count = (int) sc.getAttribute("count");
}
count++;
sc.setAttribute("count", count);
response.setCharacterEncoding("UTF-8");
PrintWriter pw = response.getWriter();
pw.print("<html>");
pw.print("<head>");
pw.print(" <meta charset=\"UTF-8\">");
pw.print(" <title>Service1</title>");
pw.print("</head>");
pw.print("<body>");
pw.print("<p>여기는 Service1 입니다</p>");
pw.print("<h1>전체 방문자 수는 " + count + " 명입니다.</h1>");
pw.print("</body>");
pw.print("</html>");
}
}
package chapter04;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/chapter04/service_2")
public class Service2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext sc = getServletContext();
int count = 0;
if(sc.getAttribute("count") != null) {
count = (int) sc.getAttribute("count");
}
count++;
sc.setAttribute("count", count);
response.setCharacterEncoding("UTF-8");
PrintWriter pw = response.getWriter();
pw.print("<html>");
pw.print("<head>");
pw.print(" <meta charset=\"UTF-8\">");
pw.print(" <title>Service1</title>");
pw.print("</head>");
pw.print("<body>");
pw.print("<p>여기는 Service2 입니다</p>");
pw.print("<h1>전체 방문자 수는 " + count + " 명입니다.</h1>");
pw.print("</body>");
pw.print("</html>");
}
}
별도의 웹 페이지는 없고 서블릿 두 개만 존재함
웹 페이지가 없는 이유는 서블릿에서 웹 페이지를 출력하기 때문에
다시 얘기하지만 이 예시(방문자 수 세기) 자체에 대해서 깊게 생각할 필요는 없음
단순히 "ServletContext가 있다" 는 걸 보여주기 위한 예시임
서블릿을 보자
컨테이너가 준비해둔 서블릿 컨텍스트를 가져오기 위해 getServletContext 메서드를 호출했음(1)
서블릿 컨텍스트 안에 값을 저장할 때는 setAttribute 메서드를 사용하고 값을 꺼낼 때는 getAttribute 메서드를 사용함
setAttribute 로 값을 저장할 때 저장할 값은 Object 로 형변환 되서 저장되고 꺼낼 때는 Object 로 꺼내짐
그래서 서블릿 컨텍스트 안에 들어있는 값을 꺼내는데 그러한 이름의 값이 없다면 null이 반환되고 그러한 이름의 값이 있다면 그 값이 Object 타입으로 꺼내짐
서블릿 컨텍스트 안에 이름이 count 인 속성(attribute)의 값이 있다면(2) 그 값을 꺼내서 원래의 형태로 형변환 후 count 변수에 저장함(3)
서블릿 컨텍스트 안에 이름이 count인 속성이 없다면 count 변수의 값은 그대로 0임
count변수는 웹 프로젝트 방문자의 수를 나타냄
count 변수의 값을 하나 증가 시킨 후 서블릿 컨텍스트의 setAttribute 메서드를 통해 서블릿 컨텍스트 안에 count 이름으로 현재 웹 프로젝트 방문자의 수를 저장함
그 후에는 HTML을 사용해 현재 웹 프로젝트 방문자의 수를 출력하고 있음
이제 서버를 실행시키고 Service1 또는 Service2 서블릿으로 접근하자
둘 중 어느 서블릿으로 먼저 접근해도 상관 없으며 방문자 수가 1부터 하나씩 증가하는걸 볼 수 있음
서블릿 컨텍스트는 서블릿 컨테이너가 생성하고 관리하므로 서버를 끄기 전까지 계속 유지됨
그래서 서버를 끄기 전까지는 웹 프로젝트 방문자 수가 누적됨
서버를 끄면 서블릿 컨테이너도 꺼지고 그에 따라 서블릿 컨텍스트도 사라지므로 웹 프로젝트 방문자 수가 사라짐
서블릿 컨텍스트는 컨텍스트(웹 프로젝트의 정보) 라고 했으므로 서블릿 컨텍스트를 사용해서 웹 프로젝트의 몇 가지 정보를 출력해보자
chapter04 -> serverInfo 서블릿을 추가하고 아래 코드를 추가하자
package chapter04;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/chapter04/server_info")
public class ServerInfo extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext sc = getServletContext();
System.out.println("프로젝트 명 => " + sc.getServletContextName());
System.out.println("서블릿 버전 => " + sc.getMajorVersion());
System.out.println("컨테이너 정보 => " + sc.getServerInfo());
}
}
이를 통해 "서블릿 컨텍스트가 컨텍스트구나" 를 알 수 있을 것
실제 개발에서 서블릿 컨테이너를 활용하는 상황은 거의 없음
딱 한순간! 파일 업로드 기능을 구현할 때 서블릿 컨텍스트가 필요함
그래서 사실 지금까지 언급한 내용은 전혀 몰라도 상관 없음
파일 업로드 기능은 이 카테고리의 마지막에 설명할 것이니 그때가서도 "ServletContext 이 블로그에서 알려줬었는데 뭐였지?" 정도로 기억해도 무방함
서블릿 컨텍스트(ServletContext) 객체를 통해서 그나마 자주 사용하는 메서드는 아래와 같음
메서드 명 | 설명 |
setAttribute(String, Object) | 서블릿 컨텍스트 안에 값을 저장함 값은 Object 타입으로 형변환되 저장되며 첫 번째 인자가 저장할 값의 이름임 |
getAttribute(String) | 이름을 사용해 값을 꺼냄 꺼낸 값은 Object 타입이므로 원래의 형태로 형변환 해줘야함 |
removeAttribute(String) | 이름에 저장된 값을 삭제함 |
getRealPath(String) | 인자로 경로를 넣으며 해당 경로가 프로젝트 내에서 실제 경로가 어떻게 되는지 알려주는 메서드 특히! 파일 업로드 시에 반드시 필요한 메서드임 |
'Servlet + JSP > Serlvet-Chapter04' 카테고리의 다른 글
Chapter04. 자바와 DB 연동 (0) | 2023.03.04 |
---|---|
Chapter04. ServletConfig (0) | 2023.03.03 |
Chapter04. 포워딩을 할 때 값을 전달하는 방법 (0) | 2023.03.03 |
Chapter04. 포워딩(Forwarding) / 클라이언트 몰래 요청 넘기기 (2) | 2023.03.03 |
Chapter04. 포워딩(Forwarding) / 클라이언트에게 "여기로 가!" 지시하기 (0) | 2023.03.02 |