ServletContext란?
웹 어플리케이션을 실행할 때 톰캣 컨테이너에서 각 컨텍스트(프로젝트) 마다 하나씩 객체가 생성되는 클래스
여러 명의 사용자가 웹 애플리케이션을 실행하면 각각 사용자에게 하나씩 ServletContext 객체가 생성되고, 톰캣 컨테이너(서버) 종료 시 소멸된다.
ServletContext 객체끼리는 저장 공간을 공유하므로, 공통 자원을 미리 바인딩하고 서블릿에서 해당 자원에 접근할 때 사용한다.
package sec05.ex01;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
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("/cset")
public class SetServletContext extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
// ServletContext 객체 가져오기
ServletContext context = getServletContext();
List member = new ArrayList();
member.add("이순신");
member.add(30);
// ServletContext에 ArrayList set하기
context.setAttribute("member",member);
out.print("<html><body>"+member.get(0)+", "+member.get(1)+" 설정</body></html>");
}
}
getServletContext()
메서드를 호출해 ServletContext
객체의 주소를 가져올 수 있다. request
에 바인딩할 때와 마찬가지로 get/setAttribute()
메서드를 호출해 데이터를 바인딩하고 가져올 수 있다.
package sec05.ex01;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
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;
import javax.servlet.http.HttpSession;
@WebServlet("/cget")
public class GetServletContext extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
// ServletContext 객체 가져오기
ServletContext context = getServletContext();
// ServletContext에 바인딩한 ArrayList 가져오기
List member = (ArrayList) context.getAttribute("member");
String name = (String) member.get(0);
int age = (Integer) member.get(1);
out.print("<html><body>바인딩한 데이터 : "+name+", "+age+"</body></html>");
// 세션 ID 비교
HttpSession session = request.getSession();
out.print("<br>"+session.getId());
}
}
💻 실행 결과
/cset 에서 바인딩 후 /cget 에 접근했을 때 각각 다른 세션(브라우저) 에서 접근해 동일한 데이터를 가져온 것을 확인할 수 있다.
web.xml
파일에 <context-param>
태그로 컨텍스트에서 사용할 초기 파라미터를 설정해 놓으면 ServletContext
객체의 메서드로 해당 파라미터를 사용할 수 있다.
파일명 : web.xml
<web-app>
...
<!-- 컨텍스트 파라미터 초기 설정 :
컨테이너 생성 시 ServletContext 객체에 초기 값으로 등록됨 -->
<context-param>
<param-name>menu_member</param-name>
<param-value>회원등록 회원조회 회원수정</param-value>
</context-param>
<context-param>
<param-name>menu_order</param-name>
<param-value>주문조회 주문등록 주문수정 주문취소</param-value>
</context-param>
<context-param>
<param-name>menu_goods</param-name>
<param-value>상품조회 상품등록 상품수정 상품삭제</param-value>
</context-param>
</web-app>
// 메뉴 이름을 미리 설정해놓고 쓰기 실습
...
@WebServlet("/initMenu")
public class ContextParamServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
// ServletContext 객체 가져오기
ServletContext context = getServletContext();
// ServletContext 객체에서 파라미터 가져오기
String menu_member = context.getInitParameter("menu_member");
String menu_order = context.getInitParameter("menu_order");
String menu_goods = context.getInitParameter("menu_goods");
out.print("<html><body>");
out.print("<table border=1 cellspacing=0><tr>메뉴 이름</tr>");
out.print("<tr><td>"+menu_member+"</td></tr>");
out.print("<tr><td>"+menu_order+"</td></tr>");
out.print("<tr><td>"+menu_goods+"</td></tr>");
out.print("</table></body></html>");
}
}
ServletContext
의 getResourceAsStream()
메서드로 파일의 데이터를 읽어와 출력할 수 있다.
// /WEB-INF/bin 폴더 내에 init.txt 파일 만들어 놓기
package sec05.ex03;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.StringTokenizer;
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("/cfile")
public class ContextFileServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
ServletContext context = getServletContext();
// 파일을 읽어들이기 위해 InputStream 객체 필요
InputStream is = context.getResourceAsStream("/WEB-INF/bin/init.txt");
// InputStream 객체가 담은 파일(바이너리 데이터) 내용을 문자로 바꿔 읽기 위해 Reader 객체 필요 (보조 스트림 Buffer 사용)
BufferedReader buffer = new BufferedReader(new InputStreamReader(is));
// buffer를 사용해 파일 내용을 읽을 수 있음
String menu = null, menu_member = null, menu_order = null, menu_goods = null;
// buffer에 다음 줄 내용이 있으면 계속 반복
while((menu = buffer.readLine()) != null) {
// 파일 내용을 콤마(,)를 구분자로 분리
StringTokenizer tokens = new StringTokenizer(menu, ",");
menu_member = tokens.nextToken();
menu_order = tokens.nextToken();
menu_goods = tokens.nextToken();
String data = "";
data += "<html><body>";
data += menu_member+"<br>"+menu_order+"<br>"+menu_goods+"<br>";
data += "</body></html>";
out.print(data);
}
}
}
init.txt
메뉴1, 메뉴2, 메뉴3
회원등록 회원조회 회원수정, 주문조회 주문등록 주문수정 주문취소, 상품조회 상품등록 상품수정 상품삭제
[실행 결과]
메뉴1
메뉴2
메뉴3
회원등록 회원조회 회원수정
주문조회 주문등록 주문수정 주문취소
상품조회 상품등록 상품수정 상품삭제
ServletConfig란?
톰캣 컨테이너에서 각 서블릿마다 하나씩 객체가 생성되는 클래스
각 서블릿에서만 접근할 수 있으며 공유는 불가능하다. 서블릿과 동일하게 생성되고 서블릿이 소멸 시 같이 소멸된다.
ServletContext 객체를 얻거나 서블릿에 대한 초기화 작업을 할 수 있다.
이클립스에서 서블릿을 생성할 때 (프로젝트 우클릭 - New
- Servlet
@WebServlet의 구성 요소(url 패턴, 서블릿의 파라미터 등) 설정 가능
설정 후 서블릿을 생성하면 아래 코드처럼 @WebServlet의 내용이 자동으로 설정됨
package sec06.ex01;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(
urlPatterns = {
"/sInit",
"/sInit2"
},
initParams = {
@WebInitParam(name = "email", value = "admin@web.com"),
@WebInitParam(name = "tel", value = "010-1111-2222")
})
public class InitParamServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
// 서블릿에 설정된 초기 파라미터 가져오기
String email = getInitParameter("email");
String tel = getInitParameter("tel");
String data = "";
data += "<html><body><table>";
data += "<tr><td>email</td><td>"+email+"</td></tr>";
data += "<tr><td>tel</td><td>"+tel+"</td></tr>";
data += "</table></body></html>";
out.print(data);
}
}
[실행 결과]
email admin@web.com
tel 010-1111-2222
HTTP 프로토콜 통신은 stateless 방식으로 통신을 하므로 웹 페이지들끼리 어떤 상태나 정보도 공유하지 않는다. 브라우저에서 새 페이지를 열면 기존의 페이지가 수행한 작업이나 정보를 알 수 없다. 따라서 웹 페이지나 서블릿끼리 상태나 정보를 공유하려면, 세션 트래킹이라는 웹 페이지 연결 기능을 구현해야 한다.
<input type="hidden">
태그 이용 : hidden 속성의 input에 name을 넣어 전송<!-- 화면에는 보이지 않지만 제출하면 user_hp 데이터가 이동한 페이지에 전송됨 -->
<form>
<input type="hidden" name="user_hp" value="010-1111-2222">
</form>
URL Rewriting
: URL 뒤에 정보를 붙여 다른 페이지로 전송 (GET 방식)<!-- 페이지 이동 시 URL의 ?뒤에 있는 데이터가 전송됨 -->
<a href="이동할 URL?키=값&키=값&...">이동</a>
쿠키
: 클라이언트 PC의 Cookie 파일에 정보를 저장한 후 여러 페이지에서 공유세션
: 서버 메모리에 정보를 저장한 후 여러 페이지에서 공유쿠키(Cookie)란?
클라이언트 PC마다 정보를 저장해 놓고 필요할 때 여러 웹 페이지에서 사용할 수 있도록 하는 방법
속성 | Persistence 쿠키 | Session 쿠키 |
---|---|---|
생성 위치 | 파일로 생성됨 | 브라우저 메모리에 생성됨 |
종료 시기 | 쿠키 파일 삭제, 쿠키에 설정된 유지 시간이 종료된 경우 | 브라우저를 종료한 경우 |
용도 | 자동 로그인, 팝업창 보지 않기 설정 등 | 사이트 접속 시에만 인증 정보를 유지해야 할 경우 |
쿠키의 유지 시간을 양수로 설정하면 클라이언트 PC에 쿠키 파일이 생성되어 Persistence
쿠키로 저장되고, 설정하지 않거나 음수로 설정하면 Session
쿠키로 저장된다.
HttpServletResponse
의 addCookie()
메서드로 각 클라이언트에 쿠키 정보를 전송한 후 저장
HttpServletRequest
의 getCookie()
메서드로 쿠키 정보를 서버로 가져옴
(주의) 쿠키에 한글 데이터를 저장하고 꺼내 쓸 때는 인코딩/디코딩 과정이 필요함
package sec02.ex01;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/set")
public class SetCookieValue extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
Date date = new Date();
// 쿠키에 저장 : cookieTest라는 키(이름)에 한글을 인코딩해서 값으로 저장
Cookie cookie = new Cookie("cookieTest",URLEncoder.encode("JSP 프로그래밍입니다.","utf-8"));
// 쿠키 유효 기간 설정 (Persistence 쿠키 : 파일로 저장됨)
cookie.setMaxAge(24*60*60); // 초 단위, 24h
// 세션 쿠키 만드는 방법 : 유효 시간을 음수로 지정하기
// cookie.setMaxAge(-1);
// 생성된 쿠키를 브라우저로 전송
response.addCookie(cookie);
out.println("현재 시간 : "+date);
out.println("문자열을 Cookie에 저장합니다.");
}
}
package sec02.ex01;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/get")
public class GetCookieValue extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
// 브라우저의 모든 쿠키 정보(쿠키 이름 모음) 배열로 가져오기
Cookie[] allValues = request.getCookies();
for(int i=0; i < allValues.length; i++) {
if(allValues[i].getName().equals("cookieTest")) {
// 쿠키 이름이 cookieTest 인 쿠키 정보 찾기
// 한글로 된 쿠키 값을 가져올 때는 디코딩 작업이 필요함
out.println("<h2>Cookie 값 가져오기 : " + URLDecoder.decode(allValues[i].getValue(),"utf-8") + "</h2>");
}
}
}
}
💻 실행 결과
쿠키에 저장한 값을 /get 에서 확인할 수 있다.
크롬 브라우저의 개발자 도구
- 애플리케이션
- 쿠키
에서 현재 사용중인 웹 애플리케이션에 저장된 쿠키 정보를 확인할 수 있다.
자바스크립트를 이용해 쿠키에 접근하여 팝업창을 제어하는 예제
파일명 : popUpTest.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>자바스크립트에서 쿠키 사용</title>
<script type="text/javascript">
// 페이지가 로드될 때 pageLoad 함수 호출
window.onload = pageLoad;
function pageLoad() {
// getCookieValue() 메서드 호출해 반환받은 쿠키 값을 변수에 담기
notShowPop = getCookieValue();
if(notShowPop != "true") {
// notShowPop 값이 true가 아니면 팝업창 띄우기
window.open("/pro09/popUp.html","pop","width=400, height=500, history=no, resizable=no, status=no, scrollbars=yes, menubar=no");
}
}
function getCookieValue() {
let result = "false";
if(document.cookie != "") {
// 쿠키 정보가 있으면 실행
// document의 쿠키 정보는 "쿠키이름=값;쿠키이름=값;..." 문자열로 나타남
// 쿠키 정보를 ; 로 분리해 각각의 쿠키 정보를 배열 형태로 얻기
cookie = document.cookie.split(";");
for(let i=0; i<cookie.length; i++) {
// 각각의 쿠키 정보를 쿠키이름과 값으로 분리
// element : [쿠키이름, 값]
element = cookie[i].split("=");
value = element[0];
// 정규식을 이용해 쿠키이름 문자열의 공백을 제거
// ^시작부분 \s 공백을 * 모두 지우기
value = value.replace(/^\s*/,'');
if(value=="notShowPop") {
// 쿠키 이름이 notShowPop인 쿠키 정보의 값을 반환
result = element[1];
}
}
}
return result;
}
function deleteCookie() {
// notShowPop 쿠키 값을 false로 만들고 유효 기간 삭제하기 (session 쿠키)
document.cookie = "notShowPop=" + "false" + ";path=/; expires=-1";
}
</script>
</head>
<body>
<form>
<input type="button" value="쿠키 삭제" onclick="deleteCookie()">
</form>
</body>
</html>
파일명 : popUp.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script type="text/javascript">
function setPopUpStart(obj) {
// 체크박스의 체크 여부 확인
if(obj.checked == true) {
// 현재 날짜와 시간 가져오기
let expireDate = new Date();
let days = 1;
// 가져온 Date에서 1일 더한 값으로 set
expireDate.setDate(expireDate.getDate() + days);
// notShowPop 쿠키 정보 추가하기, 유효 기간은 1일로 설정(persistence 쿠키)
document.cookie = "notShowPop=" + "true" + ";path=/;expires=" + expireDate.toGMTString();
window.close();
}
}
</script>
</head>
<body>
알림 팝업창입니다.
<br><br><br><br><br><br><br><br>
<form>
<input type="checkbox" onclick="setPopUpStart(this)"> 오늘 더 이상 팝업 띄우지 않기
</form>
</body>
</html>
💻 실행 결과
체크박스에 체크를 하면 팝업창이 사라지고 설정 정보가 계속 유지된다.
💻 체크박스에 체크한 후 / 쿠키 삭제 버튼을 누른 후 쿠키 값 비교
체크하면 notShowPop 쿠키 값이 true가 되고 유효 기간이 지정되어 persistence 쿠키가 되고, 쿠키 삭제 버튼을 누르면 쿠키 값이 false가 되고 유효 기간이 사라져 session 쿠키로 등록된다.