🔥 Vamos/JSP & Servlet

0509 | Servlet&Jsp (4) // cookie, redirect, 쿠키지우기, doGet,doPost

unikue 2023. 5. 9. 19:53

[1] Cookie

: 상태값을 서버에다 저장해두는게 아니라, 클라이언트가 직접 갖고 다니는 것

: 상태유지에 사용된다

: 즉 서버쪽 상태저장소는 ApplicationSession, 클라이언트쪽 저장소는 Cookie

 

 

1-1) 클라이언트-서버사이 쿠키가 오가는 관계

 

 

 

1-2) 쿠키 저장하고 읽기

// 쿠키 저장하기
Cookie cookie = new Cookie("c", String.valueOf(result));
response.addCookie(cookie); // 세션저장, 서버저장도 싫을때 클라이언트가 저장하라고 값을 저장해 보냄

// 쿠키 읽기
Cookie[] cookies = request.getCookies();
String _c=""; // 쿠키 담을 곳

if(cookies !=null)
	for(Cookie cookie: cookies)
    	if("c".equals(cookie.getName())) // 키값을 찾아서 value값 반환
        	_c = cookie.getValue();

👉 쿠키를 보낼때는 문자열로, 그것도 url로 사용할 수 있는 값으로 보내야 한다

 

public class Calc2 extends HttpServlet {

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		Cookie[] cookies = req.getCookies(); // 쿠키가 서버로 왔을때 읽을 배열 생성

		resp.setCharacterEncoding("UTF-8");
		resp.setContentType("text/html; charset=UTF-8");

		String value_ = req.getParameter("value");
		String operator = req.getParameter("operator");

		int value = 0;

		if (!value_.equals(""))
			value = Integer.parseInt(value_);
            
    //------------------------------------------- 값 검증 완료

		if (operator.equals("=")) {// 계산
			int x = 0;

			// 쿠키꺼내기
			for (Cookie c : cookies) { // 배열을 돌면서 값 꺼내기
				if (c.getName().equals("v")) { // 키값으로 있는지 먼저 찾음
					x = Integer.parseInt(c.getValue()); //value값이 String이므로 변환
					break; // 찾으면 for문을 더 돌 필요가 없으므로 빠져나오기
				}
			}

			int y = value;
			String op = "";
            
			for (Cookie c : cookies) {
				if (c.getName().equals("op")) {
					op = c.getValue();
					break;
				}
			}
            
			int result = 0;

			if (op.equals("+"))
				result = x + y;

			else
				result = x - y;

			resp.getWriter().printf("result is %d%n", result);

		} else { // 값을 저장
			Cookie valueCookie = new Cookie("v", String.valueOf(value)); // 쿠키생성해서 클라에게 보내기
			Cookie opCookie = new Cookie("op", operator);
			resp.addCookie(valueCookie);
			resp.addCookie(opCookie); // respond 헤더에 심어진다
		}
	}
}

 

 

1-3) 쿠키의 path옵션

: 쿠키는 모든 서블릿이 동일하게 쓰는게 아니라, 해당 서블릿 혹은 해당 범위의 서블릿을 찾을때 해당 쿠키를 쓰도록 되어있다.

: 쿠키의 이름충돌, 여러값을 전달하거나 하는 오류를 막기 위함

valueCookie.setPath("/"); // 모든 페이지를 접속할때마다 쿠키를 가져올 것
valueCookie.setPath("/notice/"); //notice가 포함된 url에 접속할때마다 쿠키를 가져올 것

서버에서 반환하면서 쿠키와 해당 path를 설정해서 돌려준다
요청시에 세션과 더불어 쿠키에 저장된 값이 옮겨가는걸 볼 수 있다. 단, 경로가 일부 서블렛(/notice)로 지정되어있다면 해당 url이 아닐떄 가지않는다

 

 

 

1-4) Cookie의 maxAge옵션

: 브라우저가 닫혀도 쿠키가 유효한가? ▶ 브라우저가 닫혀도 쿠키에 원하는 기간을 설정해두면 값이 유지된다

Cookie valueCookie = new Cookie("v", String.valueOf(value));
			Cookie opCookie = new Cookie("op", operator);
			valueCookie.setPath("/calc2"); // 모든 페이지를 접속할때마다 쿠키를 가져올것
			valueCookie.setMaxAge(24*60*60); // 지금으로부터 쿠키가 살아있어야 하는 날짜 설정
			opCookie.setPath("/calc2");
			resp.addCookie(valueCookie);
			resp.addCookie(opCookie); // respond 헤더에 심어진다

 

 

 

 

[2] Application / Session / Cookie의 차이점 정리

2-1) Application

사용범위: 전역 범위에서 사용하는 저장공간

생명주기: WAS가 시작해서 종료할때까지

저장위치: WAS서버의 메모리

 

2-2) Session

사용범위: 세션 범위에서 사용하는 저장공간 (특정 사용자만 사용할 수 있는 공간)

생명주기: 세션이 시작해서 종료할 때 까지

저장위치: WAS서버의 메모리

 

2-3) Cookie

사용범위: web browser별 지정한 path 범주 공간 (특정 url에 대해서만 사용되도록 할 수 있다)

생명주기: Browser에 전달한 시간부터 만료시간까지 (서버의 생명주기와 관련 없으므로 서버에 부담을 주지 않는다)

저장위치: web Browser의 메모리 또는 파일


Q. 1년정도 데이터를 저장하려고 할때 어디에 저장해야하는가?

A. 기간이 길다면 쿠키. 세션은 1년이란 기간을 쓸 수 없음. 게다가 세션id도 쿠키로 식별이 되므로 브라우저를 닫으면 쿠키가 사라지고 세션이 만료된다. 

 

Q. notice외에는 그 데이터를 쓸만한 서블릿이 없을때 어디에 저장해야 하는가?

A. 특정 범위, url로 지정할 수 있는건 쿠키뿐


 

 

[3] 서버에서 페이지 전환하기 (response.sendRedirect("string"));

: 현재는 값 입력시 흰화면이 반환되고, 다시 뒤로가기를 눌러서 두번째 계산값을 입력한다. 첫 계산시 흰 화면 반환이 아니라 바로 원래의 html화면이 뜰 수 있도록 html화면을 연결해주는 것 (경로우회) = redirect

Cookie valueCookie = new Cookie("v", String.valueOf(value));
			Cookie opCookie = new Cookie("op", operator);
			valueCookie.setPath("/calc2"); // 모든 페이지를 접속할때마다 쿠키를 가져올것
			opCookie.setPath("/calc2");
			resp.addCookie(valueCookie);
			resp.addCookie(opCookie); // respond 헤더에 심어진다
			
			resp.sendRedirect("calc2.html");

 

 

[4] 동적인 페이지 (서버페이지) 필요성

: html로 화면을 구성하기에는 한계가 있다.

: 동적 문서(서버문서) = 실행 시에 만들어지는 문서

: 반환시 원래 있던 기존 문서로 반환하는게 아니라, 요청받은 값을 꽂아서 새 화면을 가공하여 동적으로 문서를 출력한다.

: 즉 servlet → html (정적문서)  클라에 구현이 아니라 servlet  servlet (동적문서)  클라에 전달된다.

 

4-1) write()함수로 서블릿 만들어보기

① 동적인 페이지를 만들기 위해서는 html 문서를 복사한 서블릿(java) 파일을 만들어야 한다

② html 문서 내용을 모두 out.write()로 감싸고 계산 식은 out.printf를 이용한다

③ 요청이 들어오면 서버에서 서블릿 파일이 만들어져 클라에 전송한다

public class CalcPage extends HttpServlet {

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		resp.setCharacterEncoding("UTF-8");
		resp.setContentType("text/html; charset=UTF-8");
		PrintWriter out = resp.getWriter();
        
        //(중략)
        out.write("<tr>");
		out.printf("<td class=\"output\" colspan=\"4\">%d</td>",3+4);
        //html은 3+4 그대로 출력되지만 동적문서는 값으로 7이 떠있다
		out.write("</tr>");
		out.write("<tr>");
		out.write("<td><input type=\"submit\" name=\"operator\" value=\"CE\" /></td>");
		out.write("<td><input type=\"submit\" name=\"operator\" value=\"C\" /></td>");
		out.write("<td><input type=\"submit\" name=\"operator\" value=\"BS\" /></td>");
		out.write("<td><input type=\"submit\" name=\"operator\" value=\"÷\" /></td>");
		out.write("</tr>");

 

웹 계산기
0

 

 

4-2)쿠키 지우기

: 계산기에서 C 버튼을 눌렀을땐, 값을 지우는게 아니라 사실상 이때까지 누적된 쿠키를 지우는 것

else if (operator != null && operator.equals("C")) { // clear를 위해 쿠키 지우기
			exp=""; // 이렇게하면 빈문자열이 쿠키로 전달되므로 0이 아닌 빈화면만 뜬다
		}

		else { // 누적
			exp += (value == null) ? "" : value;
			exp += (operator == null) ? "" : operator;
			exp += (dot == null) ? "" : dot;
		}

		Cookie expCookie = new Cookie("exp", exp);
		if (operator != null && operator.equals("C")) //C를 누른경우에 값을 0으로 설정해준다
			expCookie.setMaxAge(0);
		
		resp.addCookie(expCookie);
		resp.sendRedirect("calcpage");
	}

 

 

[5] get/post에 특화된 서비스함수

 

5-1) 서비스함수에서 구분하는 법

: 요청 Method에 따른 특화된 메소드들을 이용하기

: service함수는 HttpServlet의 doGet(), doPost()를 오버라이드하므로 get요청 > 서비스함수 > super()호출 > 오버라이드된 do get 호출

: get & post를 동시에 처리하고싶다면 service함수만 구현하여 처리 (super가 있으면 자동으로 do~를 호출하므로)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form action="calculator" method="post">
		<input type="submit" value="요청"> 
	</form>
</body>
</html>
@WebServlet("/calculator")
public class Calculator extends HttpServlet{
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		if(req.getMethod().equals("GET")) { // html form태그의 method get/post를 체크하는 위치
			System.out.println("Get요청이 왔습니다");
		}
		
		else if(req.getMethod().equals("POST")) {
			System.out.println("post요청이 왔습니다");
		}
		
//		super.service(req, resp);
	} 
	
//	@Override
//	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//		System.out.println("do get 메소드 호출");
//	}
	
//	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//		System.out.println("do post 메소드 호출");
//	}
}

 

 

5-2) 특화된 서비스함수 doGet, doPost

: 서블릿 - 서블릿으로 값을 받는경우 url이 나누어져있어 쿠키문제가 있다.

: 전역변수로 쿠키를 다 뿌리던가, 한쪽은 쿠키는 못받던가...하는 문제가 있음.

: 오버라이드로 doGet, doPost를 받아서 한 서블릿 안에서 서로 주고받을 수 있도록 설정 가능

@WebServlet("/calculator") // 서블릿 두개로 쪼개져있던 계산기를 하나로 합칠때 doGet, doPost활용한 케이스
public class Calculator extends HttpServlet {

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//get요청
		Cookie[] cookies = req.getCookies();

		String exp = "0";

		if (cookies != null) {
			for (Cookie c : cookies)
				if (c.getName().equals("exp")) {
					exp = c.getValue();
					break;
				}
		}

		//인코딩설정 생략

		PrintWriter out = resp.getWriter();

		//html생략
        
		out.write("<form method=\"post\">"); 
        //메소드를 post로 명시해뒀으므로 post로 전달된다. 여기서 쓰던 path는 필요가 없어졌다. 자기자신에게 전달하므로.
	}

	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		Cookie[] cookies = req.getCookies();

		// 입력값만 처리됨
		String value = req.getParameter("value");
		String operator = req.getParameter("operator");
		String dot = req.getParameter("dot");

		String exp = "";
		if (cookies != null) // 쿠키 확인해서 쿠키값 읽어오기
			for (Cookie c : cookies)
				if (c.getName().equals("exp")) {
					exp = c.getValue();
					break;
				}

		if (operator != null && operator.equals("=")) { // 계산
		// 아직 구현못함
		}

		else if (operator != null && operator.equals("C")) { // clear를 위해 쿠키 지우기
			exp = ""; // 이 부분 없이 아래에서 setMaxAge(0)만으로도 쿠키 제거 가능
		}

		else { // 누적
			exp += (value == null) ? "" : value;
			exp += (operator == null) ? "" : operator;
			exp += (dot == null) ? "" : dot;
		}

		Cookie expCookie = new Cookie("exp", exp);
		if (operator != null && operator.equals("C"))
			expCookie.setMaxAge(0); //쿠키유지시간이 0초

// doPost를 활용함으로써 이점. 1. 쿠키 범위 축소  2. 자기자신 호출로 서블릿 하나에서 진행
		expCookie.setPath("/calculator"); //다른 url에는 쿠키가 전달되지않음. 범위가 축소됨
		resp.addCookie(expCookie);
		resp.sendRedirect("calculator"); // 리디렉트는 자기가 자기를 호출하더라도 겟요청으로 넘어감
	}
}