<< 학습 목표 >>

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) 인자로 경로를 넣으며 해당 경로가 프로젝트 내에서 실제 경로가 어떻게 되는지 알려주는 메서드
특히! 파일 업로드 시에 반드시 필요한 메서드임
728x90
LIST