how2j.cn

步骤 1 : 健身房的储物柜   
步骤 2 : 什么是Session   
步骤 3 : setSession.jsp   
步骤 4 : getSession.jsp   
步骤 5 : Session和Cookie的关系   
步骤 6 : Session 原理示意图   
步骤 7 : 如果没有cookie,session如何工作   
步骤 8 : session的有效期   

步骤 1 :

健身房的储物柜

edit
考虑这个场景:
李佳汜到健身房去练胸肌,首先领了钥匙,然后进了更衣间,把衣服,裤子,手机,钱包都放在盒子里面。

毛竞也到健身房,去练翘臀首先领了钥匙,然后 进了更衣间,把衣服,裤子,手机,《Java 21天从入门到精通》也放在了一个盒子里,但是这个盒子是和李佳汜的是不同的。

健身房,就相当于服务器,盒子,就是会话Session。

切换到我们常见的购物网站的场景
李佳汜登陆天猫之后,在购物车里看到的物品是蜡烛和皮鞭
毛竞登陆天猫之后,在购物车里看到的物品是手铐和《Java 21天从入门到精通》
Session对应的中文翻译是会话。
会话指的是从用户打开浏览器访问一个网站开始,无论在这个网站中访问了多少页面,点击了多少链接,都属于同一个会话。 直到该用户关闭浏览器为止,都属于同一个会话。

session.setAttribute("name", "teemo");

session对象保存数据的方式,有点像Map的键值对(key-value)
"name"是键,"teemo" 是值
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="javax.servlet.http.Cookie"%> <% session.setAttribute("name", "teemo"); %> <a href="getSession.jsp">跳转到获取session的页面</a>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8" import="javax.servlet.http.Cookie"%>

<%
   session.setAttribute("name", "teemo");
%>

<a href="getSession.jsp">跳转到获取session的页面</a>
session.getAttribute("name");

通过session,根据"name" 取出对应的名称
getSession.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="javax.servlet.http.Cookie"%> <% String name = (String)session.getAttribute("name"); %> session中的name: <%=name%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8" import="javax.servlet.http.Cookie"%>

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

session中的name: <%=name%>
步骤 5 :

Session和Cookie的关系

edit
回到健身房的储物柜这一段:

李佳汜和毛竞都有自己的盒子,那么他们怎么知道哪个盒子是自己的呢?
通过钥匙就能找到自己的盒子了。

盒子对应服务器上的Session。
钥匙对应浏览器上的Cookie。
步骤 6 :

Session 原理示意图

edit
Session 原理示意图
步骤 7 :

如果没有cookie,session如何工作

edit
如果浏览器把cookie功能关闭,那么服务端就无法获取jsessionid,每一次访问,都会生成一个新的session对象。

为了解决这个问题,可以使用

response.encodeURL("getSession.jsp")

response.encodeURL方法会把getSession.jsp这个url转换为

getSession.jsp;jsessionid=22424AEA86ADBE89F335EEB649D997A8

通过这个方式,提交jsessionid到服务器。 服务器根据这个jsessionid匹配到对应的session. 与session相关的功能,就可以正常工作了。
如果没有cookie,session如何工作
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="javax.servlet.http.Cookie"%> <% session.setAttribute("name", "teemo"); %> <a href="<%=response.encodeURL("getSession.jsp")%>">跳转到获取session的页面</a>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8" import="javax.servlet.http.Cookie"%>

<%
   session.setAttribute("name", "teemo");
%>

<a href="<%=response.encodeURL("getSession.jsp")%>">跳转到获取session的页面</a>
步骤 8 :

session的有效期

edit
比如登录一个网站,登录后,在短时间内,依然可以继续访问而不用重新登录。

但是较长时间不登录,依然会要求重新登录,这是因为服务端的session在一段时间不使用后,就失效了。

这个时间,在Tomcat默认配置下,是30分钟。

可以通过 d:/tomcat/conf/web.xml 中的session-config 配置进行调整
session的有效期


HOW2J公众号,关注后实时获知最新的教程和优惠活动,谢谢。


问答区域    
2024-08-04 关于 Session 和 Cookie 的理解
虚心求学

关于 J2EE-JSP-session 的提问



站长比喻的已经很直观了,在这里我补充一些不一样的个人理解: 我认为 session 存的东西重要性和安全性 > Cookie,因为两者存放的位置不一样。 Cookie 字如其名:曲奇饼干,你吃掉一口,但是自己还留了一大块,可以理解为 用户本地存东西的方式, 而服务器可以理解为 零食店, Sesssion 则可以理解为 零食店(服务器) 的货架, 是服务器存储用户信息的容器。 Cookie 和 Session 的关系,以及 用户获取 session 的过程可以这么理解: 你吃了一口 cookie ,发现蛮不错的,吃完了想去超市买(从服务器拿东西), 商店的货架上,有各式各样的牌子,你吃的是哪个牌子的?找不到, 是不是得问超市店员,拿着你的 Cookie 给他看,他一个一个地比对,后来店员发现 咦!这个曲奇商品和你的曲奇饼干长得一模一样(id匹配),于是就拿出来给了你(当然要付钱)。。。 这个过程,就是服务器根据 Cookie 中留存的 id 信息, 找到对应的 session,返回给用户。 当你第一次访问服务器,并没有 session_id 信息,服务器会自动给你分配一个,并保存到用户本地。 相当于:你第一次去零食店,你手上没有饼干,店员拿了新品给你免费品尝(分配session id), 于是你开开心的拿了一个饼干回家,相当于 将 session_id 存到了本地的 Cookie 中,这个session_id, 就是 饼干的牌子,也就是 服务器 session 的唯一标识符,根据这个id可以找到用户的session。 当你第二次访问服务器,手上已经有了一个 session_id(本地Cookie中存在),服务器就不会再给你 分配 session key 了,而是根据你的 session Id 找到对应的 session 返回给你。 相当于,你下次、下下次去零食店,你手上已经有了饼干,店员想了想 你这小子又想白嫖!不会再给你 发免费饼干了。你赶紧解释说:误会了,我是来买东西的,于是你给店员看了你手上饼干的牌子(session_id), 让他根据这个牌子,找到货架拿出你要买的东西卖给你。 自然,饼干有保质期,商店货架上的东西也有保质期。也就是,Cookie 、 session 都有期限, 过期了自然就失效了。 下面是比较权威的百度资料: 会话是指客户端和服务器之间的一系列交互过程,从用户访问网站开始直到关闭浏览器。而 Cookie 是存储在用户计算机上的小型文本文件,用于跟踪和标识用户。 在服务器第一次分配 sessionid 时,服务器会生成一个唯一的 session 标识符,并将其发送给客户端。客户端接收到 sessionid 后,将其存储在本地的 Cookie 中。从本地获取 sessionid 到服务器后,服务器会尝试使用该 sessionid 找到对应的会话信息,并恢复用户之前保存的状态。随后,在用户第二次访问时,浏览器将包含该 sessionid 的 Cookie 发送给服务器以表明自己身份,并且服务端找到相应的 session 信息为用户提供持续性服务。 截图是整个过程,模拟 session id 的分配、session id 到 Cookie d的存储,session 的 获取,session 的加解密。 session_id 始终是对用户隐藏的,存放在session中,而 session_id 加密后的 session_key 是可以短暂的存留在 Cookie 中。 为了直观地模拟 session 创建、获取过程,选择自定义一个新的 session id,命名为 session_id,出于安全考虑, 一般会对这个 id 进行加密,而不是直接把 id 传输给用户。为了模拟加密的过程,我选择 进制转换 的方式以及伪码的方式加解密, 当然实际的加密方式更复杂,我只是简单地模拟。每一个过程,session_id 都是对用户隐藏的,仅 通过session_key 通讯。 模拟过程主要包括: 1. setSession:用户第一次访问服务器,没有存储 id ,系统自动分配一个session Id, 并通过加密的方式,返回给 用户 session_key(对 id 的加密)。 2. setCookie:将上一个过程分配的 session_key 保存在用户本地的 Cookie 中。 3. getCookie:尝试拿出 Cookie 中的 session_key,目的是为了下一步去服务器比较 session 的id。 4.getSession:由于步骤3 已经拿到了 session_key,因此可以尝试从服务器拿出 session, 服务器 接收到用户端传来的 session_key,对其解密为 session_id ,尝试比较 各个session属性的 id,如果匹配,则返回对应的sesstion 值,获取成功。反之,返回错误信息,获取失败。 5.当用户第二次访问服务器,此时已经存在 session_key (位于 Cookie中) ,因此不再继续分配 id, 而是直接 到 获取 Cookie 步骤,也就是到步骤3,无需setCookie。 6.当 session_key 过期,或者 session 会话过期,或者尝试通过错误的key来访问session, 服务器对其拦截,并返回 获取失败信息。 以上的过程,都对应者jsp文件,分别为:setSession -> setCookie -> getCookie -> getSession 详见代码,每个部分编辑为独立的jsp文件,然后放在 web 目录下,启动自己的 Tomcat, 浏览器 首先访问 http://127.0.0.1:xxx端口./xxx目录..../setSession.jsp 即可 以上是我的拙见,恳请各位批评指正。
加载中
<%--------------------1、 setSession.jsp  ----------------------%>

<%@	page language="java" contentType="text/html;charset=UTF-8"
	pageEncoding="UTF-8" import="javax.servlet.http.Cookie,java.util.*"%>
	
	<%
	Cookie[]cookies = request.getCookies();
	boolean isExist = false;
		//首先判断是否已有 session_key
	if(null!=cookies){
		for(Cookie c:cookies){
			if(c.getName().equals("session_key")){
				isExist = true;
			}
		}
	}else{

		//模拟 分配 session_id 的过程
		int session_id = (int)(Math.ceil(Math.random()*1e6)+Math.ceil(Math.random()*1e8));
		
		//出于安全,一般传输给用户的信息需要加密
		//模拟 将 session_id 加密为 SecretID 的过程
		int encoding = (int)(Math.ceil(Math.random()*1e6)+Math.ceil(Math.random()*1e8));
		int bincode = (int)(Math.ceil(Math.random()*1e6)+Math.ceil(Math.random()*1e8));
	    String SecretID = Integer.toUnsignedString(encoding, 19)+"1e0c"+Integer.toUnsignedString(session_id, 14)+"1e0c"+Integer.toUnsignedString(encoding, 4);
		System.out.print("set session id="+session_id);

	    session.setAttribute(String.valueOf(session_id),"明天三点行动,接头暗号:鲲鹏");
	    response.addCookie(new Cookie("session_key",SecretID));
	}
	%>
	<%if(isExist){ %>
		<h3>已经分配过了 session_id 无需再分配</h3>
		<h4>Cookie 中已经保存有  session_key </h4>
		<a href="getCookie.jsp"> 直接拿 Cookie</a>
	<%} else{%>
	<h4>服务器已经自动分配了 session_id,并加密为 session_key</h4>
	<h3>将访问 session 的秘钥(session_key)存在本地的 cookie 中</h3>
	<a href="setCookie.jsp"> session_key 存本地</a>
	<%}%>

<%-------------------- 2、setCookie.jsp  ----------------------%>

<%@ page language="java" contentType="text/html;charset=UTF-8"
	pageEncoding="UTF-8" import="javax.servlet.http.Cookie"%>

	<h1>成功将session_key 保存到本地的 Cookie 中!</h1>
	<h4>尝试取出  Cookie 中存放的 session_key</h4>
	<a href="getCookie.jsp">取出 cookie </a>	

<%-------------------- 3、getCookie.jsp  ----------------------%>

<%@ page language="java" contentType="text/html;charset=UTF-8"
	pageEncoding="UTF-8" import="javax.servlet.http.Cookie"%>
	
<%
	Cookie[]cookies = request.getCookies();
	String key = null;
	if(null!=cookies){
		for(Cookie c:cookies){
			if(c.getName().equals("session_key")){
				key = c.getValue();
				response.getWriter().print("<h4>从 本地的 Cookie 中读取 session_key 为:</h4>");
				response.getWriter().print("<h3 style='color:green'>密钥 :"+key+"</h2>");
			}
		}
	}
%>
<h4>已经拿到了本地 cookies 中存的钥匙(session_key),可以尝试从 session 中取出存在服务器的秘密了</h4>
<a href="getSession.jsp" >取出  session </a>

<%-------------------- 4、getSession.jsp  ----------------------%>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="javax.servlet.http.Cookie"%>
    <%
    //取出 cookie 中存放的 session_key
    Cookie[]cookies = request.getCookies();
	String id = null;
	if(null!=cookies){
		for(Cookie c:cookies){
			if(c.getName().equals("session_key")){
				//模拟 从 cookie 中获取 session_key 的过程
				String key = c.getValue();
				
				//模拟将 session_key 解密为 session_id 的过程
			    String[]encode = key.split("1e0c");
				id = String.valueOf(Integer.parseInt(encode[1],14));
				
				response.getWriter().print("<h4>从 本地的 Cookie 中读取 session_key 为:</h4>");
				response.getWriter().print("<h3 style='color:green'>密钥 :"+key+"</h2>");
			}
		}
	}
	
	//通过 session_key 取出密文
	String secret = (String)session.getAttribute(id);
	System.out.println("session_id:"+id);
	System.out.println("secret:"+secret);
	if(id!=null&&secret!=null&&!secret.trim().equals("")) {
		response.getWriter().print("<h4>将 session_key 解密后:</h4>");
		response.getWriter().print("<h3 style='color:green'>session_id :"+id+"</h2>");
		response.getWriter().print("<h4>通过 session_key 取出存在  session 的秘密为:</h4>");
		response.getWriter().print("<h3 style='color:green'>密文 :"+secret+"</h2>");
	}
	else
		response.getWriter().printf("<h2 style='color:red'>session_key 错误或过期,无法拿到数据</h2>[error] - ");

     		
    %>

							


3 个答案

虚心求学
答案时间:2024-08-04
完整项目见 网站:https://www.npmjs.com/package/gxdao 安装: cnpm install gxdao@1.1.1 或者: npm install gxdao@1.1.1
cnpm install gxdao@1.1.1

虚心求学
答案时间:2024-08-04
第一张图片有个小错误,session_key 不是通过 post、get 等方式传输,就直接通过 Cookie进行传输和存储。 setSession 设定属性前面的判断条件写错了,直接写成了 else。 代码如下: if(null!=cookies){ for(Cookie c:cookies){ if(c.getName().equals("session_key")){ isExist = true; } } } //else //这里 改成 isExist 的判断条件,错写成 else 了 if(!isExist) {

虚心求学
答案时间:2024-08-04
setSession 判断 session_id 是否存在的地方写错了。 if(null!=cookies){ for(Cookie c:cookies){ if(c.getName().equals("session_key")){ isExist = true; } } } //else //这里 改成 isExist 的判断条件,错写成 else 了 if(!isExist) {



回答已经提交成功,正在审核。 请于 我的回答 处查看回答记录,谢谢
答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到





2021-12-09 蜡烛皮鞭和手铐是啥意思?
大哈哥哥

关于 J2EE-JSP-session 的提问
蜡烛皮鞭和手铐是啥意思?




3 个答案

chen_jiayuan
答案时间:2024-03-01
你别说,你还真别说

四方1
答案时间:2023-07-28
如果你只关注到了这个,而没有关注到《Java 21天从入门到精通》,你就永远无法成为Java高手

G1g4lo
答案时间:2022-02-02
离谱???



回答已经提交成功,正在审核。 请于 我的回答 处查看回答记录,谢谢
答案 或者 代码至少填写一项, 如果是自己有问题,请重新提问,否则站长有可能看不到




2021-04-06 那是不是如果知道了别人的jsessionid的话,会很危险
2020-10-25 站长暗示学java的都是受,举报了(滑稽)
2020-10-18 session的为什么要有getattribute()?


提问太多,页面渲染太慢,为了加快渲染速度,本页最多只显示几条提问。还有 21 条以前的提问,请 点击查看

提问之前请登陆
提问已经提交成功,正在审核。 请于 我的提问 处查看提问记录,谢谢
关于 J2EE-JSP-session 的提问

尽量提供截图代码异常信息,有助于分析和解决问题。 也可进本站QQ群交流: 578362961
提问尽量提供完整的代码,环境描述,越是有利于问题的重现,您的问题越能更快得到解答。
对教程中代码有疑问,请提供是哪个步骤,哪一行有疑问,这样便于快速定位问题,提高问题得到解答的速度
在已经存在的几千个提问里,有相当大的比例,是因为使用了和站长不同版本的开发环境导致的,比如 jdk, eclpise, idea, mysql,tomcat 等等软件的版本不一致。
请使用和站长一样的版本,可以节约自己大量的学习时间。 站长把教学中用的软件版本整理了,都统一放在了这里, 方便大家下载: https://how2j.cn/k/helloworld/helloworld-version/1718.html

上传截图