세션
세션 역시 웹 페이지들 사이의 공유 정보를 서버에 저장해두고 웹 페이지들을 매개해주는 방법이라는 점에서는 쿠키와 같습니다.
차이점은 쿠키는 보안에 취약하지만, 세션은 서버의 메모리에 생성되어 정보를 저장하므로 보안이 용이하여 웹 페이지에서 사용되는 정보 중에 로그인 정보처럼 보안이 요구되는 정보는 대부분 세션을 이용합니다.
세션은 각 브라우저 당 한개, 즉 사용하당 한 개가 생성됩니다. 단 브라우저를 Chrome 과 Explorer 를 사용하게 된다면 브라우저 별로 생성이 되겠죠?
세션의 특징은 다음과 같습니다.
- 브라우저의 세션 연동은 세션 쿠키를 이용합니다.
- 서버에 부하를 줄 수 있습니다.
- 세션은 유효시간을 가집니다.(기본 유효시간은 30분 입니다)
로그인 상태 유지 기능이나 쇼핑몰의 장바구니 담기 기능 등에 주로 사용됩니다.
세션 실행 과정
클라이언트 브라우저가 웹 서버에 요청하면 어떻게 세션이 생성되는지 알아보겠습니다.
1. 브라우저로 사이트에 접속합니다.
2. 서버는 접속한 브라우저에 대한 세션 객체를 생성합니다.
3. 서버는 생성된 세션 id 를 클라이언트 브라우저에 응답합니다.
4. 브라우저는 서버로부터 받은 세션 di 를 브라우저가 사용하는 메모리인 세션 쿠키에 저장합니다.(쿠키 이름 jsessionId)
5. 재접속 시 브라우저는 브라우저는 세션 쿠키에 저장된 세션 id 를 서버에 전달합니다.
6. 서버는 전송된 세션 di 를 이용해 해당 세션에 접근하여 작업을 수행합니다.
세션의 중요한 특징은 브라우저당 한 개씩 생성된다는 점입니다.
브라우저가 서버에 접속하여 브라우저에 저장된 세션 id 를 전송하면 서버는 그 값을 이용해서 해당 브라우저에 대한 세션을 구분하고 각 브라우저에 대한 세션 작업을 수행합니다.
세션 API
서블릿에서 세션을 이용하려면 HttpSession 클래스 객체를 생성해서 사용해야 합니다.
HttpSession 객체는 HttpServletRequest 의 getSession() 메서드를 호출해서 생성합니다.
- getSession() or getSession(true) : 기존의 세션 객체가 존재하면 반환하고 없으면 새로 생성합니다.
- getSession(false) : 기존의 세션 객체가 존재하면 반환하고 없으면 null 을 반환합니다.
HttpSession 클래스 메서드
반환 타입 | 메서드 | 기능 |
Object | getAttribute(String name) | 속성 이름이 name 인 속성 값을 Object 타입으로 반환합니다. 해당되는 속성 이름이 없을 경우 null 값을 반환합니다. |
Enumeration | getAttributeNames() | 세션 속성 이름들을 Enumeration 객체 타입으로 반환합니다. |
long | getCreationTime() | 1970년 1월 1일 0시 0초를 기준으로 현재 세션이 생성된 시간까지 경과한 시간을 계산하여 1/1000 초 값으로 반환합니다. |
String | getId() | 세션에 할당된 고유 식별자를 String 타입으로 반환합니다. |
int | getMaxInactiveInterval() | 현재 생성된 세션을 유지하기 위해 설정된 세션 유지 시간을 int 타입으로 반환합니다. |
void | invalidate() | 현재 생성된 세션을 소멸합니다. |
boolean | isNew() | 최초로 생성된 세션인지 기존에 생성되어 있었던 세션인지 판별합니다. |
void | removeAttribute(String name) | 세션 속성 이름이 name 인 속성을 제거합니다. |
void | setAttribute(String name, Object obj) | 세션 속성 이름이 name 인 속성에 속성 값으로 value 를 할당합니다. |
void | setMaxInactiveInterval(int interval) | 세션을 유지하기 위한 세션 유지 시간을 초 단위로 설정합니다. |
메서드 사용 예시입니다.
...
HttpSession session = request.getSession();
out.println("세션 아이디 : " + session.getId() + "<br>");
out.println("최초 세션 생성 시간 : " + new Date(session.getCreationTime()) + "<br>");
out.println("최근 세션 접근 시간 : " + new Date(session.getLastAccessedTime()) + "<br>");
out.println("기존 설정 세션 유효 시간 : " + session.getMaxInactiveInterval() + "<br>");
session.setMaxInactiveInterval(5);
out.println("다시 설정 세션 유효 시간 : " + session.getMaxInactiveInterval() + "<br>");
if (session.isNew()) {
out.print("새로운 세션 생성.");
}
session.invalidate(); // 세션 삭제
...
웹 브라우저로 요청하면 각 함수 별로 반환 값을 확인하실 수 있습니다.
함수 마지막 부분에 invalidate 로 계속 세션을 삭제하기 때문에 새로운 세션이 계속 생성되고 삭제되고가 반복 되네요..
encodeURL
브라우저에서 쿠키를 사용할 수 없게 된다면 세션도 사용할 수 없습니다.
사용자가 모든 쿠키를 다 차단해 버리면 둘다 사용할 수 없게 되버리는거죠.
그럴 경우에 encodeURL() 메서드를 이용해 직접 서버에서 브라우저로 응답을 먼저 보낸 후 URL Rewriting 방법을 이용해 jsessionId 를 서버로 전송하여 세선 기능을 사용하면 됩니다.
(URL Rewriting 방법은 보안에 취약하여 로그인 정보 등의 중요한 정보를 보내기에는 부적합한 방법이지만 쿠키랑 세션을 모두 사용할 수 없으니 어쩔수 없겠죠..)
...
session.setAttribute("user_id", user_id);
String url=response.encodeURL("login");
out.println("<a href="+url+">로그인 정보 전송</a>");
...
세션을 이용한 회원 로그인
기존에 만들었던 데이터베이스를 연동하여 로그인 한 후 세션을 이용해 로그인 상태를 유지하는 것에 알아보겠습니다.
먼저 로그인 화면을 보여줄 HTML 을 작성합니다.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인창</title>
</head>
<body>
<form name="frmLogin" method="post" action="login" encType="UTF-8">
아이디 :<input type="text" name="user_id"><br>
비밀번호 :<input type="password" name="user_pwd"><br>
<input type="submit" value="로그인">
<input type="reset" value="다시입력">
</form>
</body>
</html>
로그인 정보가 데이터베이스에 저장된 정보와 일치하는지 확인하는 부분을 memberDAO 에 추가합니다.
public boolean isExisted(MemberVO memberVO) {
boolean result = false;
String id = memberVO.getId();
String pwd = memberVO.getPwd();
try {
con = dataFactory.getConnection();
// 존재하면 true 없으면 false
String query = "select decode(count(*),1,'true','false') as result from t_member";
query += " where id=? and pwd=?";
System.out.println(query);
pstmt = con.prepareStatement(query); // 쿼리 할당
pstmt.setString(1, id); // 파리미터 1 할당
pstmt.setString(2, pwd); // 파라미터 2 할당
ResultSet rs = pstmt.executeQuery(); // 쿼리 실행
rs.next(); // 첫번째 레코드로 이동
result = Boolean.parseBoolean(rs.getString("result"));
System.out.println("result=" + result);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
로그인 정보에 대한 처리를 진행할 LoginServlet 를 작성합니다.
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doHandle(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doHandle(request, response);
}
private void doHandle(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
String user_id = request.getParameter("user_id");
String user_pwd = request.getParameter("user_pwd");
MemberVO memberVO = new MemberVO();
memberVO.setId(user_id);
memberVO.setPwd(user_pwd);
MemberDAO dao = new MemberDAO();
boolean result = dao.isExisted(memberVO);
if (result) {
HttpSession session = request.getSession();
session.setAttribute("isLogon", true);
session.setAttribute("login.id", user_id);
session.setAttribute("login.pwd", user_pwd);
out.print("<html><body>");
out.print("반갑습니다. " + user_id + " 호갱님!!<br>");
out.print("<a href='show'>회원 정보 보기</a>");
out.print("</body></html>");
} else {
out.print("<html><body>호갱님의 아이디가 아닙니다.");
out.print("<a href='login3.html'>다시 로그인 하기</a>");
out.print("</body></html>");
}
}
}
로그인에 성공했을때 회원 정보 보기 에서 보여줄 ShowMember 을 작성합니다.
@WebServlet("/show")
public class ShowMember extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
String id = "", pwd = "";
Boolean isLogon = false;
HttpSession session = request.getSession(false);
if (session != null) {
isLogon = (Boolean) session.getAttribute("isLogon");
if (isLogon == true) {
id = (String) session.getAttribute("login.id");
pwd = (String) session.getAttribute("login.pwd");
out.print("<html><body>");
out.print("아이디 : " + id + "<br>");
out.print("비밀번호 : " + pwd + "<br>");
out.print("</body></html>");
} else {
response.sendRedirect("login3.html");
}
} else {
response.sendRedirect("login3.html");
}
}
}
모두 작성한 후 웹 브라우저에서 요청하면 로그인 화면이 출력됩니다.
회원 ID 와 비밀번호를 입력하고 로그인 버튼을 클릭합니다.
로그인에 성공했으면 회원 정보 보기를 클릭하여 회원 정보를 확인합니다.
로그인에 실패하면 아쉽지만.. 다음 기회에..
다른 아이디로 로그인 했다가 다시 /show 로 요청을 해도 세션을 삭제 하지 않았으므로 저장된 회원 정보가 출력됩니다.
여기까지 임미다.
'개발 > Java' 카테고리의 다른 글
[JAVA - WEB] JSP 내장 객체(내장 요소) (0) | 2022.11.06 |
---|---|
[JAVA - WEB] JSP 스크립트 요소 (0) | 2022.11.06 |
[JAVA - WEB] JSP 정의와 구성 요소 (0) | 2022.11.06 |
[JAVA - WEB] 서블릿 리스너(Listener) (0) | 2022.11.05 |
[JAVA - WEB] 서블릿 필터(Filter) (0) | 2022.11.05 |
[JAVA - WEB] 쿠키(Cookie) (0) | 2022.11.03 |
[JAVA - WEB] 서블릿 바인딩(binding) (0) | 2022.11.02 |
[JAVA - WEB] 서블릿 포워드(forward) (0) | 2022.11.02 |
[JAVA - WEB] 서블릿과 데이터베이스 (0) | 2022.11.02 |
[ Eclipse ] 소스 정렬 방법 (0) | 2022.11.01 |