会话
2023年11月15日大约 15 分钟约 2987 字
会话
介绍
会话可简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个 web 资源,然后关闭浏览器,整个过程称之为一个会话。
会话的两种技术
Cookie
Session
Cookie
介绍
- Cookie 是服务器在客户端保存用户的信息,比如登录名,浏览历史等, 就可以以 cookie方式保存。
- Cookie 信息就像是小甜饼(cookie 中文)一样,数据量并不大,服务器端在需要的时候可以从客户端/浏览器读取(http 协议)。
作用
- 保存上次登录时间等信息
- 保存用户名,密码, 在一定时间不用重新登录
- 网站的个性化,比如定制网站的服务,内容。
应用实例
创建Cookie
package com.lzw.cookie;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class CreateCookie extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.创建一个Cookie对象
//(1) username 该cookie的名字 是唯一的,可以理解为是key
//(2) lzw 是值
//(3) 可以创建多个Cookie
//(4) 这时Cookie在服务器端,还没有到浏览器
Cookie cookie = new Cookie("username", "lzw");
response.setContentType("text/html;charset=utf-8");
//2.将Cookie发送给浏览器,让浏览器将该Cookie保存
response.addCookie(cookie);
PrintWriter writer = response.getWriter();
writer.println("<h1>创建Cookie成功</h1>");
writer.flush();
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
读取指定Cookie
package com.lzw.cookie;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class ReadCookies extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 通过Request对象读取cookie信息
Cookie[] cookies = request.getCookies();
//2. 遍历cookie
if(cookies != null && cookies.length != 0){
for (Cookie cookie : cookies) {
System.out.println("cookie name= " +cookie.getName() + ", value=" + cookie.getValue());
}
}
//3. 给浏览器返回信息
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println("<h1>读取Cookie成功</h1>");
writer.flush();
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
//-------------------------
//返回指定名字的Cookie值
public static Cookie readCookieByName(String name, Cookie[] cookies){
//判断传入的参数是否正确
if(name == null || "".equals(name) || cookies == null || cookies.length == 0){
return null;
}
//遍历cookie
for (Cookie cookie : cookies) {
if(name.equals(cookie.getName())){
return cookie;
}
}
return null;
}
修改Cookie
package com.lzw.cookie;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class UpdateCookie extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//需求
/**
* 1. 需求 演示如何修改Cookie
* 1) 给定一个cookie的name, 找到该cookie, 如果找到, 则修改该cookie的值为 hsp-hi
* 2) 如果找不到指定的cookie , 则提示, 没有该cookie
*/
//1. 根据name 去查找 cookie
String cookieName = "username";
Cookie[] cookies = request.getCookies();
//如果我们直接创建了一个同名的cookie
Cookie userNameCookie = new Cookie("username", "hahaha");
Cookie cookie = CookieUtils.readCookieByName(cookieName, cookies);
if (null == cookie) {//在该浏览器没有email cookie
System.out.println("当前访问 服务端的 浏览器没有 该cookie");
} else {
cookie.setValue("lzw-hi");
}
//2. 遍历cookie
for (Cookie cookie1 : cookies) {
System.out.println("cookie name= " + cookie1.getName() + " value= " + cookie1.getValue());
}
//3. 给浏览器返回信息
response.setContentType("text/html;charset=utf-8");
if(cookie != null){
response.addCookie(cookie);
}
response.addCookie(userNameCookie);
PrintWriter writer = response.getWriter();
writer.println("<h1>更新完成</h1>");
writer.flush();
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
Cookie生命周期
介绍
Cookie 的生命周期指的是如何管理 Cookie 什么时候被销毁(删除)
setMaxAge()
● 正数,表示在指定的秒数后过期 ● 负数,表示浏览器关闭,Cookie 就会被删除(默认值是-1) ● 0,表示马上删除 Cookie
应用实例
package com.lzw.cookie;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class CookieLive extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//演示创建一个cookie , 生命周期为 60s
Cookie cookie = new Cookie("job", "java");
// 1. 从创建该cookie开始计时, 60秒后无效
// 2. 浏览器来根据创建的时间,计时到60s秒,就认为该cookie无效
// 3. 如果该cookie无效,那么浏览器在发出http请求时,就不在携带该cookie
cookie.setMaxAge(60);
//讲cookie保存到浏览器
response.addCookie(cookie);
//演示如何删除一个cookie, 比如删除username
//1 先得到username cookie
Cookie[] cookies = request.getCookies();
Cookie usernameCookie = CookieUtils.readCookieByName("username", cookies);
if(usernameCookie != null) {
//2. 将其生命周期设置为0
usernameCookie.setMaxAge(0);
//3. 重新保存该cookie, 因为你将其生命周期设置0, 就等价于让浏览器删除该cookie
//4. 说明:该cookie会被浏览器直接删除
// 返回一个Set-Cookie
// Set-Cookie: username=tom; Expires=Thu, 01-Jan-1970 00:00:10 GMT
response.addCookie(usernameCookie);//返回一个Set-Cookie: xxxxx => 一会抓包.
}else{
System.out.println("没有找到该cookie, 无法删除...");
}
/***********************
* 默认的会话级别的 Cookie [即浏览器关闭就销毁了]
* 前面我们讲课时,都是默认会话级别的生命周期
***********************/
Cookie cookie3 = new Cookie("dkey", "dkey_value");
/**
* public void setMaxAge(int expiry) {
* this.maxAge = expiry;
* }
* private int maxAge = -1; 默认就是-1
*/
//cookie.setMaxAge(-1);//设置存活时间
response.addCookie(cookie3);
// 给浏览器返回信息
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println("<h1>设置cookie生命周期</h1>");
writer.flush();
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
Cookie有效路径
规则
- Cookie 有效路径 Path 的设置
- Cookie 的 path 属性可以有效的过滤哪些 Cookie 可以发送给服务器。哪些不发。 path 属性是通过请求的地址来进行有效的过滤
- 规则如下:
cookie1.setPath = /工程路径
cookie2.setPath = /工程路径/aaa
请求地址: http://ip:端口/工程路径/资源
cookie1 会发给服务器
cookie2 不会发给服务器
请求地址: http://ip:端口/工程路径/aaa/资源
cookie1 会发给服务器
cookie2 会发给服务器
应用实例
package com.lzw.cookie;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
public class CookiePathServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 创建两个cookie
Cookie cookie = new Cookie("address", "bj");
Cookie cookie2 = new Cookie("salary", "20000");
//2. 设置不同有效路径
// request.getContextPath() => /cs
cookie.setPath(request.getContextPath());
// cookie2有效路径 /cs/aaa
cookie2.setPath(request.getContextPath() + "/aaa");
//如果我们没有设置cookie有效路径,默认就是 /工程路径
//3. 保存到浏览器
response.addCookie(cookie);
response.addCookie(cookie2);
//4. 给浏览器返回信息
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println("<h1>设置cookie有效路径成功</h1>");
writer.flush();
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
注意事项和细节
- 一个 Cookie 只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。
- 一个 WEB 站点可以给一个浏览器发送多个 Cookie,一个浏览器也可以存储多个 WEB 站点提供的 Cookie。
- cookie 的总数量没有限制,但是每个域名的 COOKIE 数量和每个 COOKIE 的大小是有限制的 (不同的浏览器限制不同, 知道即可) , Cookie 不适合存放数据量大的信息。
- 注意,删除 cookie 时,path 必须一致,否则不会删除
- Java servlet 中 cookie 中文乱码解决
package com.lzw.cookie;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.net.URLEncoder;
public class EncoderCookie extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//System.out.println("EncoderCookie 被调用");
//1. 创建cookie, 有中文
//1) 如果直接存放中文的cookie, 报错 Control character in cookie value or attribute.
//2) 解决方法,就是将中文 编程成 URL编码 英文: Encode=编码
//3) 编码后,再保存即可
String company = URLEncoder.encode("韩顺平教育", "utf-8");
//URLDecoder.decode(); 解码
Cookie cookie = new Cookie("company", company);
//2. 保存到浏览器
response.addCookie(cookie);
//3. 给浏览器返回信息
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println("<h1>设置中文cookie成功</h1>");
writer.flush();
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
Session
介绍
- Session 是服务器端技术,服务器在运行时为每一个用户的浏览器创建一个其独享的session 对象/集合
- 由于 session 为各个用户浏览器独享,所以用户在访问服务器的不同页面时,可以从各自的 session 中读取/添加数据, 从而完成相应任务
原理
- 当用户打开浏览器,访问某个网站, 操作 session 时,服务器就会在内存(在服务端)为该浏览器分配一个 session 对象,该 session 对象被这个浏览器独占, 如图


- 这个 session 对象也可看做是一个容器/集合,session 对象默认存在时间为 30min(这是在tomcat/conf/web.xml),也可修改
如何理解Session
1.存储结构示意图

2.你可以把 session 看作是一容器类似 HashMap,有两列(K-V),每一行就是 session 的一个属性。
3.每个属性包含有两个部分,一个是该属性的名字(String),另外一个是它的值(Object)
Session底层实现机制


代码实现
package com.lzw.session;
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;
public class CreateSession extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 获取session, 同时也可能创建session
HttpSession session = request.getSession();
//2. 给session获取id
System.out.println("CreateSession 当前sessionid= " + session.getId());
//3. 给session存放数据
session.setAttribute("email", "zs@qq.com");
//4. 给浏览器发送一个回复
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println("<h1>创建/操作session成功...</h1>");
writer.flush();
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
package com.lzw.session;
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;
public class ReadSession extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 获取session, 如果没有session, 也会创建
HttpSession session = request.getSession();
//输出sessionId
System.out.println("ReadSession sessionid= " + session.getId());
//2. 读取属性
Object email = session.getAttribute("email");
if (email != null) {
System.out.println("session属性 email= " + (String) email);
} else {
System.out.println("session中没有 email属性 ");
}
//给浏览器回复一下
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println("<h1>读取session成功...</h1>");
writer.flush();
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
Session生命周期
介绍
- public void setMaxInactiveInterval(int interval) 设置 Session 的超时时间(以秒为单位),超过指定的时长,Session 就会被销毁。
- 值为正数的时候,设定 Session 的超时时长。
- 负数表示永不超时
- public int getMaxInactiveInterval()获取 Session 的超时时间
- public void invalidate() 让当前 Session 会话立即无效
- 如果没有调用 setMaxInactiveInterval() 来指定 Session 的生命时长,Tomcat 会以 Session默认时长为准,Session 默认的超时为 30 分钟, 可以在 tomcat 的 web.xml 设置

- Session 的生命周期指的是 :客户端/浏览器两次请求最大间隔时长,而不是累积时长。即当客户端访问了自己的 session,session 的生命周期将从 0 开始重新计算。(指的是同一个会话两次请求之间的间隔时间)
- 底层: Tomcat 用一个线程来轮询会话状态,如果某个会话的空闲时间超过设定的最大值,则将该会话销毁
应用实例
package com.lzw.session;
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;
public class CreateSession2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("CreateSession2 被调用");
//创建Session
HttpSession session = request.getSession();
System.out.println("CreateSession2 sid= " + session.getId());
//设置生命周期
session.setMaxInactiveInterval(30);//30秒
session.setAttribute("u","jack");
//回复下浏览器
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println("<h1>创建session成功, 设置生命周期30s</h1>");
writer.flush();
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
package com.lzw.session;
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;
public class ReadSession2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 获取到session
HttpSession session = request.getSession();
System.out.println("ReadSession2 sid= " + session.getId());
//2. 读取session的属性
Object u = session.getAttribute("u");
if (u != null) {
System.out.println("读取到session属性 u= " + (String) u);
} else {
System.out.println("读取不到session属性 u 说明原来的session被销毁");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
package com.lzw.session;
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;
public class DeleteSession extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//演示如何删除session
HttpSession session = request.getSession();
session.invalidate();
//如果你要删除session的某个属性
//session.removeAttribute("xxx");
//回复一下浏览器
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.println("<h1>删除session成功</h1>");
writer.flush();
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}