버퍼 사용 안 함 = write 하는 즉시 넣어버린다.
리다이렉트 할 수 있었던 건 버퍼라는 개념으로 보낼 것들을 차곡차곡 쌓아놨었기 때문에
<error-page>
<error-code>404</error-code>
<location>ErrorHandler</location>
</error-page>
서버단에서 404 에러 발생하면 errorhandler로 가라
쿠키 : 작은 과자 부스러기
작은 정보를 저장한 조각 > 브라우저에 저장이 됨
브라우저의 쿠키를 통해서 사용자에 대한 정보들을 브라우저단에 저장을 할 수 있는데 그게 쿠키
쿠키를 서블릿을 이용해서 직접 생성해보자
쿠키랑 대응되는 세션
세션은 서버단(톰켓)에 서블릿단으로 저장하고 관리하는...
>>>쿠키의 단점 : 클라이언트단이라 보안에 취약. 노출되기가 쉬움
쿠키를 서블렛이라는 자바를 가지고 생성하고 삭제하는 CRUD 할 거임
쿠키는 브라우저에 저장이 됨 누굴 위해? 서버를 위해서.. 우리가 사용하는 서버가 http프로토콜 >> 비연결 지향>>>상태 값 보존(저장)이 불가함. 즉 그 의미는 요청자가 누군지 알 수 없다. 구분인 안된다. 매번 새로운 사람이 요청하는 느낌인 거임
그래서 쿠키를 통해서 사용자가 자기 pc에 쿠키를 저장해 두고 네이버에 들어가면, 네이버가 필요한 필요한 정보들을 쿠키라는 이름으로 내 브라우저에 심어놓음. 그다음에 요청을 하면 쿠키 요청할 때 그 요청한 유알엘과 맵핑된 쿠키가 잇따면 헤더 정보에 같이 보내는 거임. 네임이라는 쿠키에 홍길동 적어뒀으면 서버에 요청할 때마다 나는 홍길동이야 홍길동이야 계솔 알려준다는 거임
쿠키는 사용자 관련된 정보, 서버가 필요로 하는 정보를 브라우저에 심는 거임.
name value domain
http는 자바스크립트나 이런 거 말고 http 만 접근,,
expire는 유효시간
priority 우선순위
도메인과 유알엘에 맞는 요청을 할 때마다 쿠키를 계속 던져주는 거임
package kr.or.ddit.basic;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
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 //서블릿3.0부터 지원.. 이게 web.xml세팅하는걸 어노테이션으로 처리한거임 이거 하고 web.xml하면 충돌남 하나만 해야함
public class T05_ServletCookieTest extends HttpServlet {
/**
* 쿠키정보를 다루기 위한 예제 (웹 서버와 브라우저는 애플리케이션을 사용하는 동안 필요한 값을 쿠키를 통해 공유하여 상태를 유지함.)
* 1. 구성요소
* - 이름
* - 값
* - 유효시간(초)
* - 도메인 : EX)www.somehost.com, .somehost.com => 쿠키의 도메인
* 이 쿠키를 생성한 서비스의 도메인을 벗어나면 브라우저는 쿠키를 저장(생성)하지 않는다. (보안때문에...)
* - 경로 : 쿠키를 공유할 기준 경로를 지정한다. (도메인 이후 부분으로 디렉토리 수준) => 지정하지 않으면 실행한 URL의 경롭부분이 사용됨.
*
* 2. 동작방식
* - 쿠키생성단계 : 생성한 쿠키를 응답데이터의 헤더에 저장하여 브라우저에 전송함.
* - 쿠키저장단계 : 웹 브라우저는 응답데이터에 포함된 쿠키를 저장소에 보관함.(쿠키종류에 따라 메모리나 파일에 저장함)
* - 쿠키전송단계 : 브라우저는 저장한 쿠키를 요청이 있을 때마다 웹서버에 전송한다.
* (삭제되기 전까지...)
* 웹서버는 브라우저가 전송한 쿠키를 사용해서 필요한 작업을 수행함.
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
setCookieExam(req, resp); //쿠키설정 예제
}
private void setCookieExam(HttpServletRequest req, HttpServletResponse resp) throws IOException {
/**
* 쿠키 정보를 설정하는 방법...
* 1. 쿠키객체를 생성한다. 사용불가문자(공백,[]()=,"/?@:;)
* Cookie cookie = new Cookie("키값", "value값");
* 쿠키값을 사용불가문자를 제외한 나머지 출력가능한 아스키 문자 사용가능. => 이외의 값 (예를 들면 한글)을 사용시에는
* URLEncoder.encode()사용하여 인코딩 처리 해준다.
* 2. 쿠키 최대 지속시간을 설정한다. (초단위) = > 지정하지 않으면 웹브라우저를 종료할 때 쿠키를 함께 삭제한다.
* cookie.setMaxAge(60 * 60 * 24); //24시간
*
* 3. 응답헤더에 쿠키 객체를 추가한다.
* response.addCookie(cookie);
* => 출력버퍼가 플러시 된 이후에는 쿠키를 추가할 수 없다.
* (응답헤더를 통해서 웹브라우저에 전달하기 때문에..)
*/
//쿠키 생성하기
Cookie userId = new Cookie("userId", req.getParameter("userId"));
//쿠키값에 한글을 사용 시 인코딩 처리를 해준다.
Cookie name = new Cookie("name",URLEncoder.encode(req.getParameter("name"),"utf-8"));
//쿠키 소멸시간 설정(초단위) => 지정하지 않으면 브라우저가 종료할 때 쿠키를 함계 삭제한다.
userId.setMaxAge(60*60*24); //1일
name.setMaxAge(60*60*248); //2일
//응답헤더에 쿠키 추가하기
resp.addCookie(userId);
resp.addCookie(name);
//응답헤더에 인코딩 및 Content-Type 설정
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
String title = "쿠키 설정 예제";
out.println("<html>");
out.println("<head>");
out.println("<title>" + title + "</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1 align=\"center\">"+title+"</h1>");
out.println("<ul>");
out.println("<li><b>ID</b>: "+ req.getParameter("userId")+"</li><li><b>이름</b>: "+req.getParameter("name")+"</li>");
out.println("</ul>");
out.println("</body>");
out.println("</html>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<display-name>ServletTest</display-name>
<servlet>
<servlet-name>ServletLifeCycle</servlet-name>
<servlet-class>kr.or.ddit.basic.T01_ServletLifeCycle</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ServletLifeCycle</servlet-name>
<url-pattern>/ServletLifeCycle</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>ServletTest</servlet-name>
<servlet-class>kr.or.ddit.basic.T02_ServletTest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletTest</servlet-name>
<url-pattern>/ServletTest</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>ServletParameterTest</servlet-name>
<servlet-class>kr.or.ddit.basic.T03_ServletParameterTest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletParameterTest</servlet-name>
<url-pattern>/ServletParameterTest.do</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>ErrorHandler</servlet-name>
<servlet-class>kr.or.ddit.basic.T04_ErrorHandler</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ErrorHandler</servlet-name>
<url-pattern>/ErrorHandler</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>ServletCookieTest</servlet-name>
<servlet-class>kr.or.ddit.basic.T05_ServletCookieTest</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletCookieTest</servlet-name>
<url-pattern>/ServletCookieTest</url-pattern>
</servlet-mapping>
<error-page>
<error-code>404</error-code>
<location>/ErrorHandler</location>
</error-page>
<error-page>
<exception-type>javax.servlet.ServletException</exception-type>
<location>/ErrorHandler</location>
</error-page>
</web-app>
쿠키 읽어보자
쿠키 삭제
세션
쿠키랑 비교를 자주함
쿠키는 브라우저에 저장됨 (사용자, 클라이언트 측 > 보안 이취 약, 누가삭제하거나 변경해 버릴 수 있음)
요청과 응답 사이에 정보가 저장이 안 되기 때문에 세션을 활용해서 사용자별 유저별 정보를 저장할 수가 있다
정보는 서버 쪽에 저장하는 게 안전할 것 같음.
근데
이런작업을 해줘야하는 근본적인이유?
http의 특성땜시.. 비연결지향이기때문에 상대방을 구분할수있는방법이 필요하기떄문에
쿠키를 이용하든 세션을 이용하든 해야함
세션을 쓴다는 것> 쿠키를 안쓴다느건 아님 하지만 세션아이디를 쿠키에 저장을 함
서버의 정보의 객체에 접근할수잇는 아이디값.. 사용자가 아이디만 쿠키로 가지고있고, 정보는 세션에 저장을 할거임
그 정보를 사용자별로 구분위에서 세션아이디가 필요하고 그 아이디는 클라이언트브라우저에 저장해둠
아이디에 해당하는 세션객체를 가져다가 필요한 작업을 하면됨
세션 생성. 삭제등.. >> 서버단임
setAttribute 로 사용자별로 사용자정보를 저장하는게 세션의 키포인트
세션은 세션이 유지되는동안은 계속 살아있음. 세션이 끊기는 순간 객체는 사라짐.
req, resp보다는 세션이 더 유지기간이 길수잇음
세션이 쿠키에 비해 보안이 좋으니까 세션만 쓸가? no
세션의 단점은 일단 모든데이터가 서버에 저장되니까 사용자들이 많은 대형사이트가 되면 사용자들이 동시접속해서 각자의 세션객체를 만들어서 저장하기 시작하면 세션객체는 서버의 메모리르 사용하기때문에... 모두 세션으로 사용하면 안된다는말임
세션에서 데이터 가져온는 방법
세션은 req객체안의 getsession호출하면됨 (new session어쩌구하는게아니고)
누군가가 로긴했따는걸 세션객체를 만들엇는데, 거기에 로긴정보 넣어놨는데, 넣고나서 나중에 다시요청이 왔을때, 그사람이 로그인한사람인지아닌지 알고싶다면, 그 사람이 세션아이디가지고잇을거고, 그거가지고 찾아보면 .. 그 아이디로 세션객체가 만들어져있다면 꺼내오면 됨. 있으면 로긴한사람맞고 없으면 로긴한사람아닌거임.. < 로긴체크할때 이렇게ㅔ하면됨.
new session 이 아니고 req에서 get session이다.
package kr.or.ddit.basic;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class T06_ServletSessionTest extends HttpServlet{
/**
* 세션(HttpSession)객체에 대하여...
* - 세션을 통해서 사용자(웹브라우저)별로 구분하여 정보를 관리할 수 있다.
* (세션ID 이용)
* - 쿠키를 사용할 때보다 보안이 향상된다. (서버에 정보가 저장되기 때문에...)
*
* - 세션객체를 가져오는 방버
* HttpSession session = request.getSession(boolean값);
* boolean값 : true 인경우 => 세션객체가 존재하지 않으면 새로 생성함.
* false인경우 => 세션객체가 존재하지 않으면 null 리턴함.
* - 세션 삭제처리 방법
* 1. invalidate()메서드 호출 -- 강제적으로 없애는 방법
* 2. setMaxInactiveInterval(int interval) 메서드 호출
* => 일정시간(초)동안 요청이 없으면 세션객체 삭제됨.
* 객체는 세션이 건들때마다 체크를 하고잇었음.. 그래서 일정시간동안 신호가없으면 메모리에서 삭제해라 라는 메서드임
* 3. web.xml에 <session-config>설정하기 (분단위)
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//세션을 가져오는데 없으면 새로 생성한다.
HttpSession session = req.getSession(true);
//생성시간 가져오기
Date createTime = new Date(session.getCreationTime());
//마지막 접근시간 가져오기
Date lastAccessTime = new Date(session.getLastAccessedTime());
String title = "재방문을 환영합니다.";
int visitCount = 0;// 방문횟수
String userId = "sem"; //사용자 아이디
if(session.isNew()) {//세션이 새로 만들어졌는지 확인..
title = "처음 방문을 환영합니다.";
session.setAttribute("userId", userId);
}else {
visitCount = (Integer) session.getAttribute("visitCount");
visitCount++;
userId = (String) session.getAttribute("userId");
}
System.out.println("visitCount : " + visitCount);
session.setAttribute("visitCount", visitCount);
//응답 헤더에 인코딩 및 Content-Type설정
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.println("<html>");
out.println("<head><title>" + title + "</title></head>");
out.println("<body><h1 align=\"center\">"+ title + "</h1>");
out.println("<h2 align=\"center\">세션정보</h2>");
out.println("<table border=\"1\" align=\"center\">");
out.println("<tr bgcolor=\"orange\">");
out.println("<th>구분</th><th>값</th>" + "</tr>");
out.println("<tr><td>세션ID</td><td>"+ session.getId() + "</td></tr>");
out.println("<tr><td>생성시간</td><td>"+ createTime + "</td></tr>");
out.println("<tr><td>마지막접근시간</td><td>"+ lastAccessTime + "</td></tr>");
out.println("<tr><td>UserID</td><td>"+ userId + "</td></tr>");
out.println("<tr><td>방문횟수</td><td>"+visitCount+ "</td></tr>");
out.println("</table></body></html>");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
세션을 만들었고, 새고(요청)할때마다 세션 아이디 참조중
세션은 언제까지 유지될까?
브라우저가 꺼질때!
껏다켜보기
또 다른 방법 (삭제하는)
필터
걸러주는 역할
package kr.or.ddit.basic;
import java.io.IOException;
import java.util.Date;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class T07_ServletFilter implements Filter{
//서블릿이 아니고 필터임 그래서 filter라고하는 인터페이스
/**
* 서블릿 필터에 대하여... (사용자요청정보를 처리해주는게 서블릿임. 근데 그 서블릿이 엄청마니만들어질텐데. 이제 어떤고민이생겼냐면.... 공통기능
* 예를들자면 인코딩하는작업을 매번해야하는데... 그걸 필터에서 가로채서 해줄수있음...
* 1. 사용목적
* - 클라이언트의 요청을 수행하기 전에 가로채 필요한 작업을 수행할 수 있다.
* - 클라이언트에 응답정보를 제공하기 전에 응답정보에 필요한 작업을 수행할 수 있다.
*
* 2. 사용 예
* - 인증필터
* - 데이터 압축 필터
* - 인토딩 필터
* - 로깅 및 감사처리 필터
* - 이미지 변환 필터 등
*
*/
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain fc) //http서블릿보다 상위개념
throws IOException, ServletException {
//요청응답할때 서블릿작업전, 후의 작업을 여기서 해줄수있음
System.out.println("필터 시작!!");
// 클라이언트 IP주소 가져오기
String ipAdress = req.getRemoteAddr();
System.out.println("IP주소 : " + ipAdress + "\n포트번호 : " + req.getRemotePort() + "\n현재시간: "+ new Date().toString());
//필터체인을 실행한다 (req, resp객체 전달)
fc.doFilter(req, resp);//중요한거!! filter >>>> 서블렛모여있는곳으로 보내는거임 ! 그래서 파라미터 담아서 보내는것
//결국 서블렛입장에서는 필터의 존재를 모르고 그냥 브라우저가 요청한거랑 똑같은데 사실 중간에 필터가 거른거임
//콜스택에 호출된 상태로 기다림... 서블릿이 처리 다하고
System.out.println("필터처리 완료...");
//resp될때 여기서부터 다시 시작임 // 응답을 톰캣이 받기 전에 이게 아직 종료가 되지않았기때문에 여기로 돌아오는것
//어떤 고객기 로드를 남겨달라고 하면 모든 서블릿 다 까가지고 해야하는데, 이걸 필터에서 모든 요청을 거르니까 필터에 실행하면 됨
//이런 목적으로 쓰는게 필터임
//이름이 필터체인인 이유는 필터를 여러개를 둘 수 있는거임
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}