서블릿에서도 쿠키를 추출하는 것이 가능한데요. 그 전에 쿠키에 대해서 모르시는 분들이 계시다면 다음의 링크에서 한 번 확인하시고 와보시는것을 추천드립니다. 아무튼 이러한 쿠키는 특히 사용자를 인증하는 정보로 주로 사용하고 있는 만큼 없어서는 안될 중요한 개념인데요. 이러한 쿠키는 서버가 사용자한테 지급을 해주어야 하는 만큼 세팅하는 메서드에 대해서도 알 필요가 있습니다. 이번 섹션에서는 그 사용법을 한 번 익혀보도록 하겠습니다.
Cookie 클래스는 클라이언트와 서버 간의 상태 정보를 저장하기 위해 사용됩니다. 클라이언트으ㅢ HTTP 응답에서 서버는 클라이언트에게 쿠키를 보내고, 클라이언트는 이후 요청에서 해당 쿠키를 서버로 다시 전송합니다. 그러면 서버는 클라이언트로부터 받은 요청에서 쿠키를 읽고, 이를 통해 클라이언트의 상태를 관리하거나 맞춤형 응답을 생성하는 용도로서 쿠키를 사용하게 되죠.
이러한 쿠키는 기본적으로 인스턴스를 생성하듯이 new 키워드와 함께 기입하면 되는데, 이때 첫번째 매개변수는 쿠키의 이름으로 오직 문자열 타입만 가능하고, 두번째는 쿠키의 값도 마찬가지로 문자열 타입만 저장할 수 있습니다.
또한 이때 쿠키의 이름은 처음 세팅할 때에만 지정 가능하고 수정은 불가능 하다는 점도 기억해야 합니다.
Cookie cookie1 = new Cookie("onlyStringCookieName", "onlyStringCookieValue");
이클립스에서 확인해보는 쿠키 클래스의 내부 구조
쿠키가 해당 앱 어플리케이션에 남아있는 유효 기간을 설정합니다. 이때 설정하는 매개변수는 정수형이며, 초 단위로 설정이 가능합니다. 그래서 0을 전달하면 즉시 쿠키가 없어지고, 60을 전달하면 60초 동안 해당 쿠키가 유효한데요.
다만 음수를 설정하면 브라우저가 종료될 때 해당 쿠키를 삭제하게 됩니다.
// cookie1의 유효 시간을 60초 * 60초, 즉 60분인 1시간 동안으로 설정함. cookie1.setMaxAge(60*60)
쿠키가 해당 어플리케이션의 특정 url에서 유효한지를 지정할 때 사용하는 메서드로, / 기호를 단독으로 사용할 경우 해당 어플리케이션 내에서는 어느 url이든 해당 쿠키가 유효하다는 의미입니다.
// cookie1의 유효 경로는 해당 어플리케이션의 모든 곳에서 유효함 cookie1.setPath("/")
해당 쿠키가 다른 어플리케이션, 즉 다른 서버에서도 유효한 경우로 사용하고자 할 때 지정하는 메서드입니다. 예를 들어 ("www.naver.com") 으로 지정했다면 해당 쿠키는 생성된 어플리케이션 뿐만 아니라 네이버, 즉 다른 서버에서도 유효한 쿠키가 됩니다. 물론 ("ver.com") 으로 지정하면 도메인 중 ver.com 단어가 포함된 도메인에서도 해당 쿠키는 유효하게 됩니다.
그러나 이러한 행위는 쿠키 탈취, 혹은 노출과 같이 보안 상에 큰 타격을 줄 수 있기에 계열사 홈페이지와 같이 연관된 홈페이지가 아니라면 사용을 하지 않는 것을 권장합니다.
// cookie1는 네이버 서버에서도 유효한 쿠키로 지정 cookie1.setDomaion("www.naver.com")
특정 시점에서 사용자에게 응답을 보낼 때 세팅 된 쿠키를 전송하는 용도로 사용합니다.
// 응답을 보낼 때 cookie1을 보냄 res.addCookie(cookie1);
클라이언트가 전송한 모든 쿠키를 배열로 반환받습니다. 이때 쿠키의 유효기간이 지나 쿠키가 만료된 상태에서 해당 메서드로 요청을 할 때 반환된 배열이 null일 수도 있으므로, null 체크를 넣어줍시다.
// 쿠키를 배열로 얻어옴 Cookie[] cookieList = req.getCookies(); // 쿠키를 임시로 만들어 넣을 용도 Cookie cookie1; // 만약 얻어온 쿠키가 없는 상태라면 새로운 쿠키를 만들어 사용자에게 전송 if (cookieList == null) { cookie1 = new Cookie("CookieName", "CookieValue"); res.addCookie(cookie1); }else { // 쿠키가 있다면 배열을 돌리며 쿠키를 출력 for (Cookie cookie : cookieList) { out.print("<p>Cookie Name: " + cookie.getName() + "</p>"); out.print("<p>Cookie Value: " + cookie.getValue() + "</p>"); } }
얻어온 쿠키 배열 중에서 특정 쿠키의 이름을 반환받습니다.
얻어온 쿠키 배열 중에서 특정 쿠키의 값을 반환받습니다.
그럼 지금까지 알아본 내용으로 페이지를 이동할 때마다 쿠키를 생성하고 출력해보는 예제를 만들어 보겠습니다.
우선 서블릿을 총 네 개를 만들어 줍니다.
메인 페이지에는 쿠키를 생성하지 않을거고, 다른 페이지를 이동할 때마다 쿠키를 생성해서 사용자에게 주도록 할것이므로 한 번 해당 코드를 만들어보도록 하겠습니다.
subServlet1의 쿠키
Cookie user1 = new Cookie("user1", "guest"); user1.setPath("/"); // 쿠키가 웹 애플리케이션 전체에서 유효하도록 설정 user1.setMaxAge(60); // 60초 동안 유효 res.addCookie(user1);
subServlet2의 쿠키
Cookie user2 = new Cookie("user2", "worker"); user2.setPath("/"); // 쿠키가 웹 애플리케이션 전체에서 유효하도록 설정 user2.setMaxAge(60 * 60); // 1시간 동안 유효 res.addCookie(user2);
subServlet3의 쿠키
Cookie user3 = new Cookie("user3", "operator"); user3.setPath("/"); // 쿠키가 웹 애플리케이션 전체에서 유효하도록 설정 user3.setMaxAge(60 * 60 * 24); // 1일 동안 유효 res.addCookie(user3);
자, 이제 사용자는 페이지를 방문할 때마다 쿠키를 받게 될텐데요. 받았으니 사용자로부터 한 번 받아봐야겠죠? 해당 코드도 만들어 줍시다.
// 쿠키 받아오기 Cookie[] cookieList = req.getCookies(); // 만약 쿠키가 남아있으면 다음과 같이 html 요소를 만들고 getName과 getValue로 화면에 표시하기 if (cookieList != null) { out.print("<h4>쿠키 목록:</h4>"); out.print("<ul>"); for (Cookie cookie : cookieList) { out.print("<li>"); out.print("쿠키 이름: " + cookie.getName() + ", "); out.print("쿠키 값: " + cookie.getValue()); out.print("</li>"); } out.print("</ul>"); // 쿠키가 없을 경우 없다고 표시하기 } else { out.print("<p>쿠키가 존재하지 않습니다.</p>"); }
이제 사용자가 버튼을 누를 때마다 해당 서블릿 페이지로 이동하도록 a 태그를 활용해 경로를 지정해 줄건데요. 이때 본인이 사용하고 있는 프로젝트부터 web.xml에 매핑한 루트(또는 @WebServlet으로 매핑한 경로)를 올바르게 적어야 하기 때문에 주의가 필요합니다.
제 프로젝트 이름은 project이므로 다음과 같이 적어주도록 하겠습니다.
mainServlet 페이지 버튼
@WebServlet("/mainServlet") @Override protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { res.setContentType("text/html;charset=UTF-8"); PrintWriter out = res.getWriter(); out.print("<h3>여기는 메인 서블릿 입니다.</h3>"); out.print("<h3>경로를 이동해 보세요.</h3>"); out.print("<a href=\"/project/subServlet1\">서브 서블릿1</a>"); out.print("<br>"); out.print("<a href=\"/project/subServlet2\">서브 서블릿2</a>"); out.print("<br>"); out.print("<a href=\"/project/subServlet3\">서브 서블릿3</a>"); }
SubServlet1 페이지 버튼
@WebServlet("/subServlet1") out.print("<h3>경로를 이동해 보세요.</h3>"); out.print("<a href=\"/project/mainServlet\">메인 서블릿</a>"); out.print("<br>"); out.print("<a href=\"/project/subServlet2\">서브 서블릿2</a>"); out.print("<br>"); out.print("<a href=\"/project/subServlet3\">서브 서블릿3</a>");
SubServlet2 페이지 버튼
@WebServlet("/subServlet2") out.print("<h3>경로를 이동해 보세요.</h3>"); out.print("<a href=\"/project/mainServlet\">메인 서블릿</a>"); out.print("<br>"); out.print("<a href=\"/project/subServlet1\">서브 서블릿1</a>"); out.print("<br>"); out.print("<a href=\"/project/subServlet3\">서브 서블릿3</a>");
SubServlet3 페이지 버튼
@WebServlet("/subServlet3") out.print("<h3>경로를 이동해 보세요.</h3>"); out.print("<a href=\"/project/mainServlet\">메인 서블릿</a>"); out.print("<br>"); out.print("<a href=\"/project/subServlet2\">서브 서블릿1</a>"); out.print("<br>"); out.print("<a href=\"/project/subServlet3\">서브 서블릿2</a>");
자, 이제 페이지 작성을 모두 완료했으니 한 번 작동을 시켜보겠습니다.
최초 방문입니다. 해당 메인 페이지는 쿠키를 설정하지 않았습니다. 서브 서블릿1 페이지로 이동해 보겠습니다. 개발자 도구에는 쿠키가 생성되었군요? 하지만 서브 서블릿1에는 생성된 쿠키가 표시되지 않습니다. 정상입니다. 사용자가 최초로 서브 서블릿1에 진입하는 시점에는 쿠키가 없는 상태이니까요. 서블릿 페이지의 두번째로 이동했습니다. 이 시점에는 사용자가 서브 서블릿 페이지1에서 받은 쿠키가 있으므로 해당 쿠키가 정상적으로 노출되는 모습을 확인할 수 있습니다. 서브 서블릿 페이지 3도 마찬가지죠. 다시 다른 페이지로 이동하면 이제 세 개의 서브 서블릿 페이지에서 사용자에게 전달한 쿠키를 사용자로부터 받아 출력할 수 있게 되는거죠! 물론 서브 서블릿 페이지 1의 쿠키 유효 기간은 60초 이므로 시간이 지나면 삭제되는 모습도 보실 수 있고요!
쿠키를 이용하면 해당 어플리케이션의 방문을 몇 번 했는지도 알 수 있는데요. 기본적으로 사용자가 방문할 때 해당 방문자의 고유 쿠키를 갖고 있을 것이고, 이 사용자가 매번 어플리케이션, 즉 홈페이지에 접속할 때마다 해당 쿠키의 이름을 대조하여 사용자가 맞을 경우 값(방문 횟수)을 증가시키는 방식으로 활용할 수 있기 때문이죠.
그래서 아래 코드를 살펴보시면 얻어온 쿠키가 널이 아니고 배열의 길이보다 작을 때까지 for문을 돌리면서 특정 사용자일 경우 방문 횟수(값)을 증가시켜주는 코드임을 알 수 있습니다.
물론 doGet 메서드는 사용자의 요청마다 호출되고 종료되므로 cnt 변수도 매번 초기화 되겠으나 매번 사용자로부터 쿠키 값을 가져와 cnt에 담고(물론 문자열을 정수로 변환) 그 값을 증가시켜 다시 사용자의 쿠키로 담아주면 결국 사용자의 쿠키 값은 매번 증가할 수 있는 겁니다.
package com.practice.test; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; 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; import java.io.IOException; import java.io.PrintWriter; @WebServlet("/mainServlet") public class MainServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setContentType("text/html;charset=UTF-8"); PrintWriter out = resp.getWriter(); // cnt 선언 int cnt = 0; // 쿠키 가져오기 Cookie[] list = req.getCookies(); // 가져온 쿠키가 비어있지 않고 i가 배열의 길이보다 작을 떄까지 반복 // 하는 동안 만약 사용자의 쿠키 이름이 특정 이름과 같으면 // 쿠키의 값을 가져와 정수 변환 후 cnt에 저장 for(int i = 0 ;list!=null&& i < list.length;i++) { if(list[i].getName().equals("cookieName")) { cnt = Integer.parseInt(list[i].getValue()); } } // cnt를 증가시킨 후 쿠키 이름과 함께 값으로 새로운 쿠키 생성 cnt++; Cookie cookie = new Cookie("cookieName", cnt+""); // 유효 기간 재세팅 cookie.setMaxAge(60*60); // 사용자에게 전달 resp.addCookie(cookie); out.print("<h1> 고객님의 " + cnt + "번째 방문을 환영합니다!</h1>"); } }