文章目录
会话跟踪技术
1、相关基础概念
-
什么是会话?
会话就是浏览器和Web服务器建立连接和断开连接的过程。当用户打开浏览器,访问web服务器的资源,会话建立,直到有一方断开连接,会话结束。在一次会话中可以包含多次请求和响应。
举例说明:当我们用浏览器访问京东,在进入京东官网(即浏览器和京东的服务器建立连接,会话开始),我们可以在官网点击各种超链接访问各种商品的详细信息(即进行多次请求和响应,会话中),然后我们看累了,直接叉掉京东页面(即浏览器和京东服务器断开连接,会话结束)。以上过程就称之为一次会话。
-
什么是会话跟踪?
会话跟踪是一种实现一次会话中多次请求-响应之间数据共享的技术,主要是为了解决HTTP无状态的缺点,服务器需要识别多次请求是否来自于同一浏览器(这个识别过程就是会话跟踪),以便实现一次会话中多次请求-响应之间的数据共享。
举例说明:在进入京东官网(即浏览器和京东的服务器建立连接,会话开始),当我们看到心怡的商品时,我们就会点击加入购物车,然后浏览器就会显示加入成功的提示(进行第一次请求-响应),然后我们就准备点击购物车进行支付(进行第二次请求-响应),就会显示第一次请求-响应时的商品信息,这个过程就需要两次请求-响应间的数据共享,而数据共享就需要使用会话跟踪技术。
-
如何实现会话跟踪技术?
- 方式一:客户端会话跟踪技术
Cookie
- 方式二:服务端会话跟踪技术
Session
- 方式一:客户端会话跟踪技术
2、Cookie
Cookie是一种客户端会话技术,将数据保存到客户端,以后客户端每次请求都会携带Cookie数据进行访问。Servlet API 提供了一个
javax.servlet.http.Cookie
类,该类包含了所有的Cookie相关操作的API,及其Cookie的各个属性
2.1 Cookie的基本使用
对于后端程序员而言,关于Coolie的操作,主要包含两种类型的操作,一是从服务端发送Coolie对象到客户端,二是从服务端获取来自客户端的Coolie对象
2.1.1 发送Cookie
发送Cookie主要包含两步:
-
Step1:创建Cookie对象,并设置数据
Cookie cookie = new Cookie("key","value");
-
Step2:使用Response对象的
addCookie
方法进行发送response.addCookie(cookie);
示例:
任务:在Servlet中生成Cookie对象并存入数据,然后将数据发送给浏览器
-
Step1:使用Maven导入项目依赖
pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <!--========================项目信息================================--> <!--Maven版本信息--> <modelVersion>4.0.0</modelVersion> <!--项目坐标--> <groupId>com.hhxy</groupId> <artifactId>day10_CoolieAndSession</artifactId> <version>1.0-SNAPSHOT</version> <!--项目打包方式--> <packaging>war</packaging> <!--项目依赖的JDK版本--> <properties> <maven.compiler.source>16</maven.compiler.source> <maven.compiler.target>16</maven.compiler.target> </properties> <!--==============================================================--> <!--=============================项目依赖==========================--> <!--项目依赖的jar包--> <dependencies> <!--servlet依赖的jar包--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> </dependencies> <!--项目依赖的插件--> <build> <!--tomcat7插件--> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> <!-- <path></path>--> </configuration> </plugin> </plugins> </build> </project>
-
Step2:编写Servlet
ASerlvet:发送Cookie
package com.hhxy.cookie; 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; import java.io.IOException; /** * 发送Cookie */ @WebServlet("/AServlet") public class AServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doGet(request, response); } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //1、创建Cookie对象,并设置值 Cookie cookie = new Cookie("username","zhangsan"); //2、发送Cookie对象 response.addCookie(cookie); } }
-
Step3:到浏览器中查看Cookie数据
设置 → 隐私设置和安全性 → C o o k i e 及其他网站数据 → 查看所有 C o o k i e 和网站数据 设置\rightarrow{隐私设置和安全性}\rightarrow{Cookie及其他网站数据}\rightarrow{查看所有Cookie和网站数据} 设置→隐私设置和安全性→Cookie及其他网站数据→查看所有Cookie和网站数据
2.1.2 获取Cookie
获取Cookie主要包含三步:
-
Step1:使用Request对象的
getCookies
方法获取Cookie数组Cookie[] cookies = request.getCookies();
-
Step2:遍历Cookie数组
for (Cookie cookie : cookies) //或者: for (int i=0;i<cookies.length;i++)
-
Step3:获取Cookie对象的数据
//获取name cookie.getName(); //获取值 cookie.getValue();
拓展:在EL表达始终获取Cookie对象中的数据
${cookie.key.value}
示例:
获取Cookie的依赖和发送Cookie的依赖是一样的,不在赘述
BServlet:获取Cookie
package com.hhxy.web;
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;
import java.io.IOException;
/**
* 获取Cookie
*/
@WebServlet("/BServlet")
public class BServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1、获取Cookie数组
Cookie[] cookies = request.getCookies();
//2、遍历Cookie数组
for (Cookie cookie : cookies) {
//3、获取Cookie对象中的数据
String name = cookie.getName();
if(name.equals("username")){//筛选出我想要的Cookie对象
String value = cookie.getValue();
System.out.println(name+":"+value);
}
}
}
}
访问结果:
注意:
1)首先要先运行Aservlet,让浏览器中存在Cookie,否则会报错,比如当我们将浏览器中的Cookie删除后,使用BServlet进行访问,直接报错:
2)其次Cookie只能共享同一次会话的数据,无法跨会话共享数据。也就是说只能在同一个模块下Servlet共享数据
3)Cookie只能发送字符串类型的数据,非字符转类型的需要进行转换
4)Cookie发送中文数据会乱码。乱码原因可以参考 Request&Reponse对象详解 中1.4.3节
2.2 Cookie原理
Cookie技术的实现是基于HTTP协议的,数据的传递和发送都是键值对的形式。
在一次会话中,当我们使用浏览器访问AServlet时,Tomcat接收到请求就会自动调用doXXX1方法,将Cookie数据响应到浏览器,而Tomcat在响应过程中,会对我们的Cookie数据进行封装,将数据存在响应头:set-cookie
中,然后传递给浏览器,浏览器接收到响应数据后,会将这个Cookie数据存储在本地一个Cookie仓库中;当我们再次使用浏览器访问BServlet时,BServlet接收到请求就会获取来自请求数据中的Cookie(这个Cookie是第一次请求-响应的),此时的请求数据被浏览器进行了封装,存在请求头:cookie
:中。示意图:
2.3 Cookie存活时间
默认情况,服务端发送到浏览器的Cookie数据并不会永久存储,当浏览器关闭时,Cookie数据会被自动释放
思维拓展🚝🚆:浏览器在访问AServlet后,重启Tomcat后再次访问BServlet能够获取到原来的数据?
setMaxAge
:用于设置Cookie数据在浏览器的存储时间
setMaxAge(int seconds)
seconds的取值情况:
- 正数:将Cookie写入浏览器所在电脑的硬盘,持久化存储。到时间自动删除,时间单位是秒
- 负数:默认值,Cookie在当前浏览器内存中,当浏览器关闭,则Cookie被销毁
- 零:删除对应Cookie
@WebServlet("/AServlet")
public class AServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 创建Cookie对象
Cookie cookie = new Cookie("username","zs");
//设置存活时间 ,1周 7天
cookie.setMaxAge(60*60*24*7);//阅读性高,但是性能不高
//cookie.setMaxAge(604800);//阅读性不高,但是性能高
//2. 发送Cookie,response
response.addCookie(cookie);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
思维拓展答案:BServlet是肯定能获取的,因为Cookie数据是存储在浏览器中,只要浏览器不重启就没事(亲测有效😄)
2.4 Cookie存储中文
Cookie不能直接存储中文,如需存储需要进行转码!同时想要获取转码后的Cookie数据,还需要进行对应的解码!
示例:
AServlet:向浏览器发送Cookie
package com.hhxy.cookie;
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;
import java.io.IOException;
import java.net.URLEncoder;
/**
* 发送Cookie
*/
@WebServlet("/AServlet")
public class AServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//0、将要存储的中文进行URL编码
String name = "张三";
String encode = URLEncoder.encode(name, "UTF-8");
//测试:
System.out.println(encode);//输出:%E5%BC%A0%E4%B8%89
//1、创建Coolie对象,并设置值
Cookie cookie = new Cookie("username",encode);
//2、发送Coolie对象
response.addCookie(cookie);
}
}
BServlet:获取来自浏览器的Cookie
package com.hhxy.cookie;
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;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
/**
* 获取Cookie
*/
@WebServlet("/BServlet")
public class BServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1、获取Cookie数组
Cookie[] cookies = request.getCookies();
//2、遍历Cookie数组
for (int i=0;i<cookies.length;i++) {
//3、获取Cookie对象中的数据
String name = cookies[i].getName();
if(name.equals("username")){
String value = cookies[i].getValue();
//ULR解码
String encode = URLDecoder.decode(value, "UTF-8");
System.out.println(name+":"+encode);//username:张三
}
}
}
}
当我们直接使用Cookie发送中文数据时:
3、Session
Session是一种服务端会话跟踪技术,能够将数据保存到服务端。
3.1 Session的基本使用
Session是一个域对象,他继承HttpSession类,和Reuqest域对象不同的是,他的域的范围是一次会话(一个模块下),而Request域对象的范围仅仅是一次请求-响应之间(需要请求转发)。
-
getSession
:获取Session对象:HttpSession session = request.getSession();
-
setAttribute
:存储数据到Session的域中:void setAttribute(String name, Object o)
-
getAttribute
:根据 key,获取值Object getAttribute(String name)
-
removeAttribute
:根据 key,删除该键值对void removeAttribute(String name)
-
getId
:获取Session的id号int getId()
备注:Session的id号是Web服务器创建的,当浏览器发送请求,服务器执行
getSession
未发现请求数据有Session的Id号就会自动创建一个,然后通过响应数据发送给浏览器,浏览器就将这个SessionId存储在本地的Cookie库中 -
isNew
:判断当前Session是否是最新的Sessionboolean isNew()
-
true:Session是最新的
-
false:Sessino不是最新的(SessionID已经通过浏览器发送给服务器,服务器访问过了)
-
-
getMaxInactiveInterval
:获取Session的非激活时间2间隔(默认是1800s)int getMaxInactiveInterval()
示例:
SessionDemo1:将数据存到Session域中
package com.hhxy.session;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/SessionDemo1")
public class SessionDemo1 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1、获取Session对象
HttpSession session = request.getSession();
//2、将数据存到Session域中
session.setAttribute("username","张三");
}
}
SessionDemo2:获取存储在Session域中的对象
package com.hhxy.session;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/SessionDemo2")
public class SessionDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1、获取Session对象
HttpSession session = request.getSession();
//2、获取Session域中的数据
Object username = session.getAttribute("username");//张三
System.out.println("username"+username);
}
}
3.2 Session原理
Session的实现是基于Cookie的。
在一次会话中,当用户使用浏览器访问SessionDemo1时,Tomcat接收到来自浏览器的请求,Tomcat自动运行doXXX1方法生成Session对象,然后将数据存储到Session域中,方法执行后,Tocmat会自动生成一个响应头信息:set-cookie
(该信息是Session对象的唯一标识),然后响应到浏览器上,浏览器接收到该数据会将其存储在本地的Cookie库中;当浏览器再次访问SessionDemo2时,浏览器会自动将存在本地Cookie库中的信息封装到请求头中cookie
中,Tocmat接收到该数据,根据cookie中的id号进行查询,看内存中是否存在等于该id号的Session对象,如果存在就直接调用(这样就能获取到前面存储在Session域中的数据了),不存在就重新创建。
示意图:
3.3 Session的钝化和活化
前面我们在使用Cookie实现会话跟踪技术时,是将信息存储浏览器中的,服务器的重启不会影响到Cookie中的信息;而现在我们在使用Session时,第一次浏览器访问SessionDemo1后信息会存储在Session域中,那么我们在正常重启Tomcat后,访问SessionDemo2信息是否因为Session对象的销毁而造成无法获取呢?(简言之:服务器重启后,Session中的数据是否还在?)
答案是【SessionDemo2仍然能够成功获取到SessionDemo1存储在Session中的数据!】
- 钝化:当Tomcat正常关闭时,Tocmat会先将Session数据写入硬盘的文件中(存在
SESSIONS.ser
中),然后再销毁Session对象 - 活化:当Tomcat再次启动时,Tomcat会自动将
SESSIONS.ser
文件中的数据加载新创建的Session对象中(这个Session对象已经不是原来的Session了,只是存储的数据是一样的,JSESSIONID
的值也是一样)
当我们使用Ctrl+C
进行关闭:
SESSIONS.ser
文件按可以在该目录下查看项目目录\target\tomcat\work\Tomcat\localhost\项目名称\SESSIONS.ser
,如图:
然后使用mvn tomcat7:run
重新启动Tomcat后,SESSIONS.ser
文件被加载成Session对象后自动消失
3.4 Session的存活时间
-
默认情况下,Session对象只会存在30分钟,这三十分钟没有对Session进行操作(这是在Tomcat的web.xml中写死的)
-
手动销毁Session对象:
session.invalidate();
-
设置Session对象的存活时间:
在web.xml中配置:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <session-config> <session-timeout>100</session-timeout> </session-config> </web-app>
总结
Cookie和Session的比较:
-
安全性:Session存储的数据更安全。Session对象的数据是存储在服务端,而Cookie的数据存储在客户端,客户端的数据容易被窃取和截获,存在很多不安全的因素,客户端的数据容易被窃取和截获,存在很多不安全的因素
-
便利性:Session存储数据更方便。Cookie只能存储字符串数据,而Session可以存储任何Object类型的数据,并且Cookie存储中文数据时要进行转码,接收时要进行解码,否则会乱码,而Session能直接传中文数据
-
存储时间:默认存储时间不同。Cookie和Session存储的数据都会因为浏览器重启而丢失,都不会因为服务器的重启而导致数据丢失,但在浏览器不重启的时候,Cookie默认是长期保存在浏览器中,而Session默认在服务器中保存30分钟
-
存储容量:Session的存储容量大于Cookie。Cookie最大只能存3KB,而Session无大小限制