Session

跟踪客户状态

• Web服务器跟踪客户状态通常有四种方法
– 建立含有跟踪数据的隐藏字段
– 重写包含额外参数的URL
– 使用持续的Cookie
– 使用Servlet API中的Session(会话)机制

Session的概念

Session用于跟踪客户的状态。Session指的是在一段时间内,单个客户与Web服务器的一连串相关的交互过程 。 在 一 个Session中,客户可能会多次请求访问同一个网页,也有可能请求访问各种不同的服务器资源。

Session的例子

例1:在电子邮件应用中,从一个客户登录到电子邮件系统开始,经过收信、写信和发信等一系列操作,直至最后退出邮件系统,整个过程为一个Session。

例2:在购物网站应用中,从一个客户开始购物 , 到最后结账 , 整 个 过 程 为 一 个Session。

Session的运行机制

  1. 当一个 Session 开 始 时 , Servlet 容 器 将 创 建 一 个HttpSession对象,在HttpSession对象中可以存放客户状态的信息(例如购物车)。
  2. Servlet容器为HttpSession分配一个唯一标志符,称为Session ID。Servlet容器把Session ID作为Cookie保存在客户的浏览器中。
  3. 每次客户发出 HTTP 请求时 , Servlet 容器可以从HttpServletRequest对象中读取Session ID,然后根据Session ID找到相应的HttpSession对象,从而获取客户的状态信息。

HttpSession接口

  1. getId()
    返回Session的ID
  2. invalidate()
    使当前的Session失效,Servlet容器会释放HttpSession对象占用的资源
  3. setAttribuate(String name, Object value)
    将一对name/value属性保存在HttpSession对象中
  4. getAttribute(String name) 根据
    name参数返回保存在HttpSession对象中的属性值
  5. isNew()
    判断是否是新创建的Session。如果是新创建的Session,返回true,否则返回false
  6. setMaxInactiveInterval()
    设定一个Session可以处于不活动状态的最大时间间隔,以秒为单位。如果超过这个时间,Session自动失效。如果设置为负数,表示不限制Session处于不活动状态的时间
    Session
    10秒内刷新
    Session
    10秒后刷新
    Session
    如果不写默认30分钟
    Session

Session的生命周期

  1. 当客户第一次访问Web应用中支持Session的某个网页时,就会开始一个新的Session。
  2. 接下来当客户浏览这个Web应用的不同网页时,始终处于同一个Session中。
  3. 默认情况下,JSP网页都是支持Session的,也可以通过以下语句显式声明支持Session:
    <%@ page session= “true”>
  4. 在以下情况中,Session将结束生命周期,Servlet容器会将Session所占用的资源释放掉:
    – 客户端关闭浏览器(真的这样吗?)
    – Session过期
    – 服务器端调用了HttpSession的invalidate()方法

如何做到再浏览器关闭时删除session

严格的讲,做不到这一点。可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.onclose来监视浏览器的关闭动作,然后向服务器发送一个请求来删除session。
但是对于浏览器崩溃或者强行杀死进程这些非常规手段仍然无能为力。
实际上在项目中我们也不会这么做,而是让服务器在Session过期时将其删除

那为什么我们关闭浏览器再打开后访问的session不一样了尼

因为我们的session是存储在浏览器cookie上的,随着浏览器进程的关闭该cookie也随之关闭,当再次请求时,服务器会重写发送一个新的sessionID给客户端,所以看起来就像是关闭浏览器session就关闭。一般来说都是客户端关闭浏览器后,服务器端的session过期导致自动关闭。

Session的过期

Session过期是指当Session开始后,在一段时间内客户没有和Web服务器交互,这个Session会失效,HttpSession的setMaxInactiveInterval()方法可以设置允许Session保持不活动状态的时间(以秒为单位),如果超过这一时间,Session就会失效。

Session的范例

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<% String username = "";

   if(!session.isNew()){
	   username = (String)session.getAttribute("username");
	   
	   if(null == username){
		   username = "";
	   }
   }

%>
<p> Session id: <%= session.getId() %></p>

<form action="mailCheck.jsp">
username: <input type="text" name="username" value="<%=username%>">
<input type="submit" value="submit">

</form>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%  String username = request.getParameter("username");
    
    session.setAttribute("username", username);
    
%>

<a href = "mailLogin.jsp">转向登录</a>
<br>
<a href = "mailLogout.jsp">注销</a>
<br>
<p>当前的用户为:<%=username %></p>
<br>
<p>您的邮箱由1000封邮件</p>

</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<% String username = (String)session.getAttribute("username");
   session.invalidate();
%>

<%= username %>再见
<br>
<a href="mailLogin.jsp">重新登录</a>

</body>
</html>

Session
Session
Session
Session

练习

  1. 问题:下面哪些说法是正确的?
    • 选项:
    (A) 对于每个要求访问maillogin.jsp的HTTP请求,Servlet容器都会创建一个HttpSession对象
    **(B)**每个HttpSession对象都有惟一的ID。
    ©JavaWeb应用程序必须负责为HttpSession分配惟一的ID

  2. 问题:如果不希望JSP网页支持Session,应该如何办?
    • 选项:
    (A) 调用HttpSession的invalidate()方法
    (B) <%@ page session= “false">

  3. 问题:以下这段代码是否有问题?

<%
session.invalidate();
String name=(String)session.getAttribute("username");
%>

• 答案: 抛出以下异常:
java.lang.IllegalStateException: getAttribute:
Session already invalidated
org.apache.catalina.session.StandardSession.getAttribute(StandardSession.java:972)

范例2(考虑安全问题)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>

<% String authority = request.getParameter("authority");
   String username = request.getParameter("username");
%>

<form action="${pageContext.request.contextPath}/UserLoginServlet" method="post">
username:<input type="text" name="username" value="<%= null == username?"":username %>"><br>
password:<input type="password" name="password"><br>

authority:
<select name="authority">
    <option value="1" <%= "1".equals(authority)?"selected='selected'":""%>>common user</option>
    <option value="2" <%= "2".equals(authority)?"selected='selected'":""%>>administrator</option>
</select>
<br>
<input type="submit" value="submit">
</form>

</body>
</html>
package learn.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import learn.bean.User;

public class UserLoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		User user = new User();
		HttpSession session = request.getSession();
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		String authority = request.getParameter("authority");

		if ("1".equals(authority)) {
			// 登录的是普通用户
			if ("zhangsan".equals(username) && "123".equals(password)) {
				// 将用户的信息放置到session当中

				user.setUsername(username);
				user.setPassword(password);
				user.setAuthority(authority);

				session.setAttribute("user", user);
				
				request.getRequestDispatcher("/session/index.jsp").forward(request, response);
				
			}
			else {
				response.sendRedirect("session/login.jsp?username=" + username + "&authority=" + authority);
			}
		} else if ("2".equals(authority)) {
			// 登录的是系统管理员
			if ("lisi".equals(username) && "456".equals(password)) {
				user.setUsername(username);
				user.setPassword(password);
				user.setAuthority(authority);

				session.setAttribute("user", user);
				request.getRequestDispatcher("/session/index.jsp").forward(request, response);
			}
			else {
				response.sendRedirect("session/login.jsp?username=" + username + "&authority=" + authority);
			}
		}
		// 登录失败
		else {
			response.sendRedirect("session/login.jsp?username=" + username + "&authority=" + authority);
		}
	}
}

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="learn.bean.User"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<base href="<%=basePath%>">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<% if(null == session.getAttribute("user")){
	response.sendRedirect("login.jsp");
	return;
   }
%>

<a href="QueryServlet">query</a><br>
<% if(((User)session.getAttribute("user")).getAuthority().equals("2")){%>
	<a href="UpdateServlet">update</a>
<%}%>


</body>
</html>
package learn.servlet;

import java.io.IOException;

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 QueryServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		HttpSession session = request.getSession();
		
		//用户未登录
		if(null == session.getAttribute("user")){
			response.sendRedirect("session/login.jsp");
			return;
		}
		
		System.out.println("成功");
	}
}

package learn.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import learn.bean.User;


public class UpdateServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        
		//用户未登录
		if(null == session.getAttribute("user")){
			response.sendRedirect("session/login.jsp");
			return;
		}
		
		User user = (User)session.getAttribute("user");
		//普通用户
		if("1".equals(user.getAuthority())){
			System.out.println("失败");
		}
		//管理员
		else {
			System.out.println("成功");
		}
	}


}

Session
Session
Session