1.会话
会话:用户点开浏览器,访问了多个web资源,之后关闭浏览器,这一整个过程我们称之为会话。也就是说,一次会话是指从用户打开浏览器到完成使用关闭浏览器。
会话分为有状态会话和无状态会话。
有状态会话:有状态Session则是一种将用户会话状态保存在持久化资源中的对象,例如数据库中。每次请求时,会从持久化资源中获取最新的会话状态,并将会话状态与客户端的Session对象进行关联。
无状态会话:无状态Session是一种不会持久保存用户会话状态的对象,每次请求结束都会重新创建一个Session对象,因此无状态Session的会话状态是临时的。
总而言之,有状态会话是指服务器会存储客户端的信息,以便下次客户端访问时识别。无状态会话不会存储客户端的信息。
2.保存会话的两种技术
保存会话主要有两种技术:cookie
和session
。保存会话的技术我们也称之为会话跟踪。(我们需要知道的是:Http是一种无状态的协议)
cookie
和session
的主要区别是:cookie
是被存放在客户端(即浏览器)中的,session
是存储在服务器之中的。
session和cookie常见的应用:我们在bilibili中登录了一次之后,在我们关闭了浏览器结束会话后,下次我们打开bilibili时,不需要再次登录。
关于Cookie
案例:通过cookie获取客户端上次开始会话的时间
为了方便我们的理解,我们接下来针对cookie做一个简单的案例
在此案例中我们将使用cookie完成客户端在访问服务器的时候,服务器将客户端上次访问的日期返回给客户端。
在此案例中,我们做的servlet需要完成的功能:
- 获取客户端传来的
cookie
- 如果客户端传来的
cookie
中有数据,那么获取cookie
中数据,将其输出;如果客户端传来的cookie
中没有数据,那么就提示用户是第一次访问。 - 将用户此次的访问时间封装到
cookie
当中 - 将
cookie
存放在response
之中返回给客户端
案例代码:
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.text.SimpleDateFormat;
import java.util.Date;
public class CookieDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置字符集
req.setCharacterEncoding("UTF-8");
// resp.setCharacterEncoding("UTF-8");
resp.setContentType("text/html;charset=UTF-8");
// 获取输出字符
PrintWriter out = resp.getWriter();
// 1.获取cookie
Cookie[] cookies = req.getCookies();
// 2.检查请求中的cookie中是否有数据
boolean hasCookie = false;
if (cookies != null){
for (Cookie cookie : cookies){
if ("loginTime".equals(cookie.getName())){
// cookie中如果有数据,那么就将数据输出
out.write("您上次访问的时间是:" + cookie.getValue());
hasCookie = true;
}
}
}
if (!hasCookie){
// cookie中没有数据那么就提示用户第一次访问
out.write("这是您第一次访问本网站!");
}
// 3.将用户此刻访问的时间田间到cookie之中
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy.MM.dd-HH:mm:ss");//需要注意cookie字符串中不可存放空格和一些特殊字符
String dateFormat = simpleDateFormat.format(date);
Cookie cookie1 = new Cookie("loginTime",dateFormat);
// 设置cookie的最大存在时间,注意单位是秒
cookie1.setMaxAge(24*60*60);
// 4.将cookie放入响应之中
resp.addCookie(cookie1);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
实现结果:
第一次访问:
非第一次访问:
在此次案例之中我们需要注意:cookie
中对它存放的字符有限制,其中的字符不可以有空格和方括号等一系列特殊字符。

从上面这个案例中我们可以知道cookie是客户端传给服务器的,在服务器处理完客户端请求之后,再由客户端传送给服务器。因此,在请求中只有获取cookie
的方法,在响应中只有设置cookie
的方法。
cookie是保存在客户端本地的。一般是保存在客户端本地的AppData 目录下。
关于cookie的一些需要知道的知识
- 一个
cookie
只能保存一个信息(只能有一对键值对) - 一个web站点可以向客户端发送多个
cookie
,一般来说客户端最多存放这个站点20个cookie
(这个根据浏览器来设置),当存放的cookie
超出浏览器限制,那么浏览器会将新的cookie
来替换掉最老的cookie
;有些浏览器会限制接受该站点的cookie
数量,一般是300个。 - Cookie的大小有限制,最大为4kb(也就是4096个字节)
关于删除cookie的方法
一般来说我们删除cookie的方法是创建一个和我们要删除的cookie同名的cookie,并且将它的生存周期设置为0,这么一来,新建的cookie就会替代我想要删除的cookie,而新建的cookie在刚替换完之后就会因为生存周期为0而被删除。
删除代码:
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;
public class CookieDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 我们删除名字为loginTime的cookie
Cookie cookie = new Cookie("loginTime","");
cookie.setMaxAge(0);//设置生存周期为0
resp.addCookie(cookie);//将cookie添加到响应之中
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
关于Session
关于Session:服务器会给每个用户(浏览器)创建一个Session对象,一个Session独占一个会话,浏览器没有关闭(会话没有结束),Session就会一直存在。
Session
和Cookie
目前来说,Cookie
我们可以把它理解为一个标记,服务器给客户端Cookie
作为标记,方便以后的操作中服务器进行辨别。Session
我们可以理解为一个数据结构,或者一个数据载体,它可以承载本次会话中需要用到的数据。
一般来说,Cookie
中会带有一个Session ID
,方便服务器根据传来的Cookie
来找到对应的Session
,以此来更加方便的辨认出用户。
Session
和Cookie
的关系我们可以通过一个案例来理解:
我们可以用银行卡的例子来更加方便我们来理解。
我们可以把Cookie
理解为银行卡,把客户端
理解为客户,把服务器
理解为银行,把Session
理解为此张银行卡在银行中的金额等信息。
当用户带着银行卡到银行中时,银行才可以通过银行卡来了解到这个用户的一些信息(比如信用情况,可以取出多少金额);同理,当客户端带着Cookie
来访问服务器
的时候,服务器
才可以根据Cookie
来得知客户端
的在本网站的一些基本信息。
Session
中常用的方法
1.在Session
中存储以及读取数据
关于Session
中存放数据,我们可以清楚Session
中不仅可以存放字符串(String
)类型的数据,同时也可以存放类(一般为实体类)。
Session
中存放String
类型的代码:
package com.kuang.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;
public class SessionDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 在此条Demo中我们将会获取Session并且在其中存贮一个字符串
// 1.解决乱码问题
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
// 2.获取Session
HttpSession session = req.getSession();
// 3.在Session中写入信息
session.setAttribute("name","一个写Bug的");
// 4.获取SessionID
String id = session.getId();
// 5.判断Session是否是新生成的
if (session.isNew()){
resp.getWriter().write("这个Session是新生成的,ID : " + id);
}else{
resp.getWriter().write("这个Session不是新生成的,ID : " + id);
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
在Session
中存放类:
新建一个实体类User
package com.kuang.pojo;
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
在Session
中存放此类
package com.kuang.servlet;
import com.kuang.pojo.User;
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 SessionDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 在本Demo中,我们将在Session中存储一个实体类
// 1.解决乱码问题
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
// 2.获取Session
HttpSession session = req.getSession();
// 3.创建实体类
User user = new User("一个写Bug的", 23);
// 4.将实体类存入Session
session.setAttribute("user",user);
// 5.提示用户已经完成
resp.getWriter().write("已经将user类存入Session");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
关于读取的Session
中的数据的方法也很简单,在我们获取Session
之后,只需要使用getAttribute
获取对应存储数据的名称即可。我们需要知道的是,Session之中存储的键值对类型是<String,Object>,也就是说在我们获取数据时,一般会同时将获取的数据进行一个类型转化。
package com.kuang.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;
public class SessionDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 本条Demo中,我们将获取Session中的数据并且将其输出
// 1.解决乱码问题
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
// 2.获取Session,并且获取Session里面的数据
HttpSession session = req.getSession();
String name = (String) session.getAttribute("name");
// 3.将获取的数据输出
resp.getWriter().write("获取到的数据为 : " + name);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
2.使Session失效
我们一般将Session
失效的方法用两种,一种是在代码中直接使用invalidate()
方法将Session失效,另外一种则是在web.xml
中设置Session
的过期时间。
使用invalidate()
方法:
package com.kuang.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;
public class SessionDemo05 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 用来使Session失效
// 1.获取Session
HttpSession session = req.getSession();
// 2.使Session中的数据失效
session.removeAttribute("name");
session.invalidate();
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
在web.xml中设置Session的过期时间:
<session-config>
<!-- 以分钟来设置Session的失效时间,单位为分钟,也就是说此处设置Session会在15分钟之后失效-->
<session-timeout>15</session-timeout>
</session-config>
Session的使用场景
- 保存用户的登录信息
- 购物车信息
- 在网站中会经常被使用到的信息,我们一般也会把它存储在Session之中
3.总结
我们现在已经学习了ServletContext
、Cookie
以及Session
这三个在网络应用中常见的存放数据的技术。关于这三个技术之间的关系,我们可以用一张图直观的表述: