HTTP 是一种"无状态"协议,所以客户端每次请求页面的时候,web服务器都不会保存之前的记录,但是web应用都会有维持关系的需求,所以就需要有Session作为媒介进行关系维护。
维持Session的三种方式
- Cookies
一个 Web 服务器可以分配一个唯一的 session 会话 ID 作为每个 Web 客户端的 cookie,对于客户端的后续请求可以使用接收到的 cookie 来识别。
android项目可以考虑用Cookies,我原来就用过。
- hidden类型的表单
一个 Web 服务器可以发送一个隐藏的 HTML 表单字段,以及一个唯一的 session 会话 ID
<input type="hidden" name="sessionid" value="12345">
,当表单被提交时,指定的名称和值会被自动包含在 GET 或 POST 数据中。每次当 Web 浏览器发送回请求时,session_id 值可以用于保持不同的 Web 浏览器的跟踪。
但是点击常规的超文本链接(<a href=''>
)不会导致表单提交,因此隐藏的表单字段也不支持常规的 session 会话跟踪。
- URL 重写
在每个 URL 末尾追加一些额外的数据来标识 session 会话,服务器会把该 session 会话标识符与已存储的有关 session 会话的数据相关联。
例如,wiki/6Zeo5bqX5ZCO5Y-w566h55CG57O757uf5o6l5Y-j/20142171?t=1504509668660
,session 会话标识符被附加为t=1504509668660
,标识符可被 Web 服务器访问以识别客户端。
我们公司是前后端分离的,后台一般用Spring,前端就是用的这种方式,这种方式会给每个页面都分配一个sessionId。
HttpSession 对象
Servlet 提供HttpSession接口,该接口提供了一种跨多个页面请求或访问网站时识别用户以及存储有关用户信息的方式
Servlet 容器使用这个接口来创建一个HTTP协议 客户端和服务器之间的session会话。会话持续一个指定的时间段,跨多个连接或页面请求
调用 HttpServletRequest 的getSession()方法可以获取 HttpSession 对象
HttpSession session = request.getSession();
方法 | 描述 |
---|---|
public Object getAttribute(String name) | 返回在该 session 会话中具有指定名称的对象,如果没有指定名称的对象,则返回 null。 |
public Enumeration getAttributeNames() | 返回 String 对象的枚举,String 对象包含所有绑定到该 session 会话的对象的名称。 |
public long getCreationTime() | 返回该 session 会话被创建的时间,以毫秒为单位。 |
public String getId() | 返回一个包含分配给该 session 会话的唯一标识符的字符串。 |
public long getLastAccessedTime() | 返回客户端最后一次发送与该 session 会话相关的请求的时间,以毫秒为单位。 |
public int getMaxInactiveInterval() | 返回 Servlet 容器在客户端访问时保持 session 会话打开的最大时间间隔,以秒为单位。 |
public void invalidate() | 指示该 session 会话无效,并解除绑定到它上面的任何对象。 |
public boolean isNew() | 如果客户端还不知道该 session 会话,或者如果客户选择不参入该 session 会话,则该方法返回 true。 |
public void removeAttribute(String name) | 将从该 session 会话移除指定名称的对象。 |
public void setAttribute(String name, Object value) | 使用指定的名称绑定一个对象到该 session 会话。 |
public void setMaxInactiveInterval(int interval) | 在 Servlet 容器指示该 session 会话无效之前,指定客户端请求之间的时间,以秒为单位。 |
Session示例
package com.jty.servlet;
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 java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by TaoYuan on 2017/9/4 0004.
*/
public class TestSession extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//如果不存在则创建
HttpSession session = req.getSession(true);
//创建时间
String createTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(session.getCreationTime()));
//最后会话时间
String lastAccessTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(session.getLastAccessedTime()));
String title = "Test Session";
Integer visitCount = 0;//访问次数
String visitCountKey = "visitCount";//访问次数 key
String userIDKey = "userID";//用户id key
String userID = "TaoYuan";//用户id
// 检查网页上是否有新的访问者
if (session.isNew()){
session.setAttribute(userIDKey, userID);
} else {
visitCount = (Integer)session.getAttribute(visitCountKey);
visitCount = visitCount + 1;
userID = (String)session.getAttribute(userIDKey);
}
session.setAttribute(visitCountKey, visitCount);
// 设置响应内容类型
resp.setContentType("text/html;charset=UTF-8");
PrintWriter out = resp.getWriter();
String docType = "<!DOCTYPE html>\n";
out.println(docType +
"<html>\n" +
"<head><title>" + title + "</title></head>\n" +
"<body bgcolor=\"#f0f0f0\">\n" +
"<h1 align=\"center\">" + title + "</h1>\n" +
"<h2 align=\"center\">Session 信息</h2>\n" +
"<table border=\"1\" align=\"center\">\n" +
"<tr bgcolor=\"#949494\">\n" +
" <th>Session 信息</th><th>值</th></tr>\n" +
"<tr>\n" +
" <td>id</td>\n" +
" <td>" + session.getId() + "</td></tr>\n" +
"<tr>\n" +
" <td>创建时间</td>\n" +
" <td>" + createTime +
" </td></tr>\n" +
"<tr>\n" +
" <td>最后访问时间</td>\n" +
" <td>" + lastAccessTime +
" </td></tr>\n" +
"<tr>\n" +
" <td>用户 ID</td>\n" +
" <td>" + userID +
" </td></tr>\n" +
"<tr>\n" +
" <td>访问统计:</td>\n" +
" <td>" + visitCount + "</td></tr>\n" +
"</table>\n" +
"</body></html>");
}
}
删除Session
当您完成了一个用户的 session 会话数据,您有以下几种选择:
- 移除一个特定的属性: 您可以调用 public void removeAttribute(String name) 方法来删除与特定的键相关联的值。
- 删除整个 session 会话: 您可以调用 public void invalidate() 方法来丢弃整个 session 会话。
- 设置 session 会话过期时间: 您可以调用 public void setMaxInactiveInterval(int interval) 方法来单独设置 session 会话超时。
- 注销用户: 如果使用的是支持 servlet 2.4 的服务器,您可以调用 logout 来注销 Web 服务器的客户端,并把属于所有用户的所有 session 会话设置为无效。
- web.xml 配置: 如果您使用的是 Tomcat,除了上述方法,您还可以在 web.xml 文件中配置 session 会话超时,如下所示:
<session-config>
<session-timeout>15</session-timeout>
</session-config>
- TIP:
- Tomcat 中默认的 30 分钟超时时间。
- getMaxInactiveInterval() 方法会返回 session 会话的超时时间,以秒为单位。
- 如果在 web.xml 中配置 session 会话超时时间为 15 分钟,那么 getMaxInactiveInterval() 会返回 900。