一句话描述“会话”:从你和你老师偶遇于某十字路口开始,到相互分离于该石子路口,你们之间的谈话内容(受训)可以称为一次会话!其中,你们都用个小本子记录下你们之间的谈话内容,你的记录为Cookie,你老师那里的记录为Session。
Table of Contents
本文主要内容:
- Cookie的相关操作(服务器发送客户端、从客户端接收)
- Session的相关操作(服务器创建、存取、持久化)
什么是会话管理
一次会话:打开浏览器 -> 访问一些服务器内容 -> 关闭浏览器
定义:
- 从打开一个浏览器访问某个站点,到关闭这个浏览器的整个过程,称为一次会话。
- 管理浏览器客户端 和 服务器端之间会话过程中产生的会话数据。
- 每一个请求者(或客户端、浏览器),对应一个会话(Session)对象。
为什么需要会话管理:
- HTTP是无意识、单向协议。
- 在一个会话结束后,HTTP协议本身并不能保存服务器端与客户端之间的通信内容。
- 理解:对于某个文件,我是根本不知道我以前有没有发过给你。如果服务器说我发过给你了,那证据就是Session;如果客户端说我发过给你了,那证据就是Cookie。
两大会话技术:
- Cookie技术:会话数据保存在浏览器客户端。
- Session技术:会话数据保存在服务器端。
Cookie技术
理解什么是Cookie:
- 小饼干,其实是一份小数据;
- 是服务器给客户端的,并且存储在客户端上的一份小数据;
应用场景:
- 自动登录;
- 浏览记录;
特性:
- Cookie数据类型只能保存非中文字符串类型的。
- 可以保存多个cookie,但是浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。
Cookie的主要内容(所需要学习的两个方面):
- 第一,服务器端怎样将一个Cookie发送到客户端
- 第二,服务器端怎样接收客户端携带的Cookie
服务器将Cookie发送到浏览器
核心:以响应头的形式发送给客户端。
- 构造Cookie对象
- Cookie(java.lang.String name, java.lang.String value)
- 设置cookie
- void setPath(java.lang.String uri):设置cookie的有效访问路径。有效路径指的是cookie的有效路径保存在哪里,那么浏览器在有效路径下访问服务器时就会带着cookie信息,否则不带cookie信息。
- void setMaxAge(int seconds):设置cookie的有效时间,单位为秒。
- 正整数:表示cookie数据保存浏览器的缓存目录(硬盘中),数值表示保存的时间。
- 负整数:表示cookie数据保存浏览器的内存中。浏览器关闭cookie就丢失了!!
- 零:表示删除同名的cookie数据
- 注意:如果不设置持久化时间,cookie会存储在浏览器的内存中,浏览器关闭后cookie信息销毁(会话级别的cookie),如果设置持久化时间,cookie信息会被持久化到浏览器的磁盘文件里。
- void setValue(java.lang.String newValue):设置cookie的值
- cookie.setPath(String path):设置访问那些资源时,要带着这个Cookie
- 如果不设置携带路径,那么该cookie信息会在访问产生该cookie的web资源所在的路径都携带cookie信息
- cookie.setPath("/MyWeb/cookieServlet"):代表访问MyWeb中的cookieServlet时才携带cookie信息
- cookie.setPath("/"):代表访问整个web项目都携带cookie信息
- 发送cookie到浏览器端保存(是HttpServletResponse类方法调用)
- void response.addCookie(Cookie cookie):发送cookie
- 服务器接收cookie(是HttpServletRequest类方法调用)
- Cookie[] request.getCookies():接收cookie
服务器接收浏览器携带Cookie的请求
Cookie信息是以请求头的方式发送到服务器端。
- 通过request获得所有的Cookie:
- Cookie[] cookies = request.getCookies();
- 遍历Cookie数组,通过Cookie的名称获得我们想要的Cookie
for(Cookie cookie : cookies) {
if(cookie.getName().equal(cookieName)){
String cookieValue = cookie.getValue();
}
}
Google Chrome中查看Cookie
地址栏输入:chrome://settings/content/cookies è 点击“查看所有Cookie和网站数据”;
在地址栏左边的小锁上,点击,显示相关信息:
案例-显示用户上次访问的时间
编程思路:
- 第一次访问:
- 获取当前时间,显示到浏览器中
- 创建Cookie对象,并把时间对象存储于Cookie中(取名为newest)
- 把Cookie发送到浏览器中
- 第n次访问
- 获取Cookie中的数据(取出newest),得到上次的访问时间
- 显示上次的访问时间
- 获取当前时间,并把当前时间对象作为更新Cookie(重新存储于newest)
- 把更新后的Cookie发送到浏览器保存
例子-显示用户上次访问的时间
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
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(
urlPatterns= {"/cookie"},
name="CookieUsage"
)
public class CookieUsage extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
/*注意,上一句代码中有空格,Tomcat会抛异常:
"An invalid character [32] was present in the Cookie value"
但不影响程序的正常执行
*/
String currentTime = sdf.format(new Date());
//从请求中获取Cookie
Cookie[] cookies = req.getCookies();
String lastTime = null; //最后访问时间
//第n次访问
if(cookies!=null) {
for(Cookie ele:cookies) {
if(ele.getName().equals("lastTime")) { //检查Cookie的KEY是否等于"lastTime"
lastTime = ele.getValue();//上次访问的时间
//1.把上次显示时间显示到浏览器
resp.getWriter().write("欢迎回来,你上次访问的时间为:"+lastTime+",当前时间为:"+currentTime);
//2.更新cookie
ele.setValue(currentTime);
ele.setMaxAge(1*30*24*60*60);
//3.把更新后的cookie发送到浏览器
resp.addCookie(ele);
break;
}
}
}
//第1次访问:浏览器端没有Cookie,上次访问的时间也为空,则表明是第一次访问
if(cookies==null || lastTime==null) {
//1.显示时间到浏览器
resp.getWriter().write("你是首次访问本站,当前时间为:"+currentTime);
//2.创建Cookie对象
Cookie cookie = new Cookie("lastTime", currentTime);
cookie.setMaxAge(1*30*24*60*60);//保存一个月,参数的单位是秒;
cookie.setPath(req.getContextPath()+"/");
//3.把Cookie发送到浏览器
resp.addCookie(cookie);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
//访问:http://localhost:8080/K-Servlet/cookie
//刷新即可查看效果
Session技术
Session技术的诞生是为了解决Cookie的局限:
- Cookie只能存字符串类型。不能保存对象
- 只能存非中文。
- 1个Cookie的容量不超过4KB。如果要保存非字符串,超过4kb内容,只能使用session技术!
Session技术核心:
- 会话数据保存在服务器端。(内存中)
- 会为每个客户端都创建一块内存空间存储客户的数据,但客户端需要每次都携带一个标识ID去服务器中寻找属于自己的内存空间。
- 所以说Session的实现是基于Cookie,Session需要借助于Cookie存储客户的唯一性标识JSESSIONID。
Session的主要内容(所需要学习的三个方面):
- 怎样获得属于本客户端的session对象(内存区域);
- 怎样向session中存取数据(session也是一个域对象);
- session对象的生命周期;
获得属于本客户端的session对象
创建或得到session对象(HttpSerssion是接口,没有构造方法):
HttpSession session = request.getSession(boolean create)
- 由于HttpSession是接口,故其返回或创建是用HttpServletRequest类下的方法;
- 功能:创建属于该客户端(会话)的私有的session区域
- 特性:
- 方法内部会判断 该客户端是否在服务器端已经存在session
- 如果该客户端在此服务器不存在session 那么就会创建一个新的session对象
- 如果该客户端在此服务器已经存在session 获得已经存在的该session返回
向session中存取数据
保存会话数据到session对象(域对象):
- void setAttribute(java.lang.String name, java.lang.Object value):保存数据,键值对的形式
- java.lang.Object getAttribute(java.lang.String name):获取数据,取其键
- void removeAttribute(java.lang.String name):清除数据,取其键
向session中存放数据
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 HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/* request.getSession()方法
* 功能:创建属于该客户端(会话)的私有的session区域
* 特性:
* 方法内部会判断 该客户端是否在服务器端已经存在session
* 如果该客户端在此服务器不存在session 那么就会创建一个新的session对象
* 如果该客户端在此服务器已经存在session 获得已经存在的该session返回
*/
HttpSession session = request.getSession();
//向该session域对象中放置数据
session.setAttribute("name", "jerry");
String id = session.getId();//该session对象的编号id
System.out.println("session的JSESSIONID: " + id);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
向session中拿取数据
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 HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/* request.getSession()方法
* 功能:创建属于该客户端(会话)的私有的session区域
* 特性:
* 方法内部会判断 该客户端是否在服务器端已经存在session
* 如果该客户端在此服务器不存在session 那么就会创建一个新的session对象
* 如果该客户端在此服务器已经存在session 获得已经存在的该session返回
*/
HttpSession session = request.getSession();
//拿到session域对象中的数据
String attr = (String)session.getAttribute("name");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
session对象的生命周期
session对象的生命周期方法:
- void setMaxInactiveInterval(int interval):设置session的有效时间
- void invalidate():销毁session对象
session作用范围:
- 默认在一次会话中,也就是说在,一次会话中任何资源公用一个session对象
- 面试题:浏览器关闭,session就销毁了? 不对
Session对象的生命周期:
- 创建:当客户端第一次访问服务器时,也即第一次执行request.getSession()时创建;
- 使用:
- 将SessionID存入Cookie中;
- 客户端再次请求时,request中将会含有sessionID和其他请求;
- 将request中的SessionID和服务器的Session比较,看是否为同一ID;
- 销毁:
- 服务器(非正常)关闭时,因为session是存储在内存(RAM)中的;
- session过期/失效(默认30分钟);
- 手动销毁,调用invalidate()方法;
问题:时间的起算点 从何时开始计算30分钟?
- 从不操作服务器端的资源开始计时
- 可以在该个工程的web.xml中进行配置,在<web-app>标签下直接添加:
- <session-config>
- <session-timeout>30</session-timeout> 单位分钟
- </session-config>