一. 会话
1. 什么是会话?
(1) 会话可简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个
过程称之为一个会话。
(2) 一次会话:打开浏览器 -> 访问一些服务器内容 -> 关闭浏览器
2. 会话过程中要解决的一些问题
每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自会产生一些数据,服务器要想办法为每个用户
保存这些数据。
(1) 模拟登陆场景
① 过程:打开浏览器 -> 浏览到登陆页面 -> 输入用户名和密码 -> 访问到用户主页(显示用户名)
修改密码(输入原密码)
修改收货地址
.......
②存在的问题:在此处登录会话过程中产生的数据(用户会话数据)如何保存下来呢?
(2) 模拟购物场景
①过程:
打开浏览器 -> 浏览商品列表 -> 加入购物车(把商品信息保存下来) -> 关闭浏览器
打开浏览器 -> 直接进入购物车 -> 查看到上次加入购物车的商品 -> 下订单 -> 支付
②存在的问题:在购物会话过程中,如何保存商品信息?
3. 会话管理:
会话管理就是管理浏览器客户端和服务器端之间会话过程中产生的会话数据。
4. 保存会话数据的两种技术:
(1) Cookie技术:会话数据保存在浏览器客户端。
(2) Session技术:会话数据保存在服务器端。
二. Cookie技术
1. 什么是Cookie技术?
Cookie是客户端技术,服务器把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去
访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。
2. Cookie技术核心
Cookie类:用于存储会话数据。代码要在服务器端完成,服务器是运行这些代码的,我们在服务器只是把cookie
创建出来,但是服务器并不保存数据,而是把cookie数据发送到浏览器端去保存。而代码要交给服务器运行,那
么这个代码可以写到Servlet中去,Servlet可以通过浏览器访问运行。
javax.servlet.http.Cookie类用于创建一个Cookie,response接口也中定义了一个addCookie方法,它用于在其
响应头中增加一个相应的Set-Cookie头字段。 同样,request接口中也定义了一个getCookies方法,它用于获取
客户端提交的Cookie。
(1) 构造Cookie对象
Cookie(java.lang.String name, java.lang.String value); ----我们需要通过名字来获取对应的值。
(2) 设置cookie
① void setPath(java.lang.String uri); ----设置cookie的有效访问路径
② void setMaxAge(int expiry); ----设置cookie的有效时间
③ void setValue(java.lang.String newValue); ----设置cookie的值
(3) 发送cookie到浏览器端保存
void response.addCookie(Cookie cookie); ----发送cookie
(4) 浏览器是可以把cookie再发送回来的,服务器接收cookie
Cookie[] request.getCookies(); ----接收cookie
3. Cookie原理
(1) 服务器创建cookie对象,把会话数据存储到cookie对象中。
new Cookie("name","value");
(2) 服务器发送cookie信息到浏览器
response.addCookie(cookie);
举例: set-cookie: name=eric (隐藏发送了一个set-cookie名称的响应头)
(3) 浏览器得到服务器发送的cookie,然后保存在浏览器端。
(4) 浏览器在下次访问服务器时,会带着cookie信息
举例:cookie: name=eric (隐藏带着一个叫cookie名称的请求头)
(5) 服务器接收到浏览器带来的cookie信息
request.getCookies();
4. Cookie的细节
(1) void setPath(java.lang.String uri):设置cookie的有效访问路径。有效路径指的是cookie的有效路径保存在
哪里,那么浏览器在有效路径下访问服务器时就会带着cookie信息,否则不带cookie信息。
(2) void setMaxAge(int expiry):设置cookie的有效时间。
① 正整数:表示cookie数据保存浏览器的缓存目录(硬盘中),数值表示保存的时间。
② 负整数:表示cookie数据保存浏览器的内存中。浏览器关闭cookie就丢失了!!
③ 零:表示删除同名的cookie数据。
(3) 一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。
(4) 一个WEB站点可以给一个WEB浏览器发送多个Cookie,一个WEB浏览器也可以存储多个WEB站点提供的
Cookie。
(5) 如果创建了一个cookie,并将它发送到浏览器,默认情况下它是一个会话级别的cookie(即存储在浏览器的
内存中),用户退出浏览器之后即被删除。若希望浏览器将该cookie存储在磁盘上,则需要使用maxAge,并给
出一个以秒为单位的时间。将最大时效设为0则是命令浏览器删除该cookie。
(6) 注意,删除cookie时,path必须一致,否则不会删除。
(7) Cookie数据类型只能保存非中文字符串类型的。可以保存多个cookie,但是浏览器一般只允许存放300个
Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。
5. Cookie的实例
(1) 实例一:发送与接收Cookie
@WebServlet("/CookieDemo1")
public class CookieDemo1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.创建Cookie对象
Cookie cookie = new Cookie("name", "value");
Cookie cookie1 = new Cookie("email", "eric@qq.com");
// 2.把cookie数据发送到浏览器(cookie数据也需要通过响应才能发送出去)
// 但是cookie数据要跟在响应的哪一部分呢?可以通过响应头(set-cookie名称)发送。
// response.setHeader("set-cookie",cookie.getName()+"="+cookie.getValue());
// 推荐使用这种方式,可以避免手动发送cookie信息
response.addCookie(cookie);
response.addCookie(cookie1);
// 3.接收浏览器发送的cookie信息
/*
* String name = request.getHeader("cookie"); System.out.println(name);
*/
Cookie[] cookies = request.getCookies();
// 注意:要判断是否为空,如果不判断,可能空指针
if (cookies != null) {
// 遍历
for (Cookie c : cookies) {
String name = c.getName();
String value = c.getValue();
System.out.println(name + "=" + value);
}
} else {
System.out.println("没有接收到cookie数据");
}
}
}
运行结果如下图所示:
(2) 实例二:设置Cookie的有效路径
@WebServlet("/CookieDemo2")
public class CookieDemo2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.创建Cookie对象
Cookie cookie = new Cookie("name", "eric");
Cookie cookie1 = new Cookie("email", "eric@qq.com");
/*
* (1)设置cookie的有效路径,默认情况下,有效路径在当前web应用下/day11
*/
cookie.setPath("/day11");
cookie1.setPath("/day12");
// 2.把cookie数据发送到浏览器(cookie数据也需要通过响应才能发送出去)
// 但是cookie数据要跟在响应的哪一部分呢?可以通过响应头(set-cookie名称)发送。
// response.setHeader("set-cookie",
// cookie.getName()+"="+cookie.getValue());
// 推荐使用这种方式,可以避免手动发送cookie信息
response.addCookie(cookie);
response.addCookie(cookie1);
// 3.接收浏览器发送的cookie信息
/*
* String name = request.getHeader("cookie"); System.out.println(name);
*/
Cookie[] cookies = request.getCookies();
// 注意:要判断是否为空,如果不判断,可能空指针
if (cookies != null) {
// 遍历
for (Cookie c : cookies) {
String name = c.getName();
String value = c.getValue();
System.out.println(name + "=" + value);
}
} else {
System.out.println("没有接收到cookie数据");
}
}
}
(3) 实例三:设置Cookie的有效时间
/*
* 设置Cookie的有效时间
*/
@WebServlet("/CookieDemo3")
public class CookieDemo3 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.创建Cookie对象
Cookie cookie = new Cookie("name", "eric");
/*
* (2) 设置Cookie的有效时间
*/
//cookie.setMaxAge(20);//20秒,意味着Cookie是20秒之后过期。从最后不调用Cookie开始计算。
cookie.setMaxAge(-1);//cookie会保存在浏览器内存(会话Cookie)。
// 2.把cookie数据发送到浏览器(cookie数据也需要通过响应才能发送出去)
// 但是cookie数据要跟在响应的哪一部分呢?可以通过响应头(set-cookie名称)发送。
// response.setHeader("set-cookie",
// cookie.getName()+"="+cookie.getValue());
// 推荐使用这种方式,可以避免手动发送cookie信息
response.addCookie(cookie);
// 3.接收浏览器发送的cookie信息
/*
* String name = request.getHeader("cookie"); System.out.println(name);
*/
Cookie[] cookies = request.getCookies();
// 注意:要判断是否为空,如果不判断,可能空指针
if (cookies != null) {
// 遍历
for (Cookie c : cookies) {
String name = c.getName();
String value = c.getValue();
System.out.println(name + "=" + value);
}
} else {
System.out.println("没有接收到cookie数据");
}
}
}
(4) 实例四:删除Cookie
@WebServlet("/DeleteCookie")
public class DeleteCookie extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Cookie cookie = new Cookie("name", "xxx");
cookie.setMaxAge(0);// 删除同名的Cookie
response.addCookie(cookie);
System.out.println("删除成功");
}
}
三. Session技术
1. 引入
(1) Cookie的局限:
① Cookie只能存字符串类型,不能保存对象;
② 只能存非中文的数据;
③ 1个Cookie的容量不超过4KB;
(2) 注意:Cookie是保存在浏览器(客户端)中,所以它是可以被浏览器清除的。如果要保存非字符串,超过4kb内
容,只能使用session技术!!
2. 什么是Session技术?
(1) Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的
session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各
自的session中,当用户再去访问服务器中的其它web资源时,其它web资源再从用户各自的session中取出数据
为用户服务。
(2) 在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一
个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的
session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服
务。
(3) Session对象由服务器创建,开发人员可以调用request对象的getSession方法得到session对象。
3. Session和Cookie的主要区别
(1) Cookie是把用户的数据写给用户的浏览器。
(2)Session技术把用户的数据写到用户独占的session中。
4. Session技术核心
HttpSession类:用于保存会话数据。
(1) 创建或得到session对象
① HttpSession getSession()
② HttpSession getSession(boolean create)
(2) 设置session对象
① void setMaxInactiveInterval(int interval):设置session的有效时间
② void invalidate():销毁session对象
③ java.lang.String getId():得到session编号
(3) 保存会话数据到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):清除数据
5. Session原理
注意:虽然代码相同,但是不同的浏览器得到的都是各自的数据。
(1) 问题:
在每一种情况下它得到的对象可能不一样,但是代码是一模一样的,却可以拿出不一样的对象,为什么会出现这
种情况?服务器怎么能够识别不同的浏览者?
(2) 注意:
在域对象中保存了数据,要想再把这个数据取出来,取决于是否是同一个对象。它的前提是在哪个session域对象
保存数据,就必须从哪个域对象取出!
(3) 分析:
可能是浏览器发了一个标记,每创建一个session对象,就会给session对象s1分配一个唯一的标记,这个标记在
执行完代码后会返回给浏览器。再用新窗口访问时,是带着s001的这个标记去服务器查询的,在服务器中找到与
它对应的s1对象。
① 浏览器1:(给s1分配一个唯一的标记:s001,把s001发送给浏览器)
创建session对象,保存会话数据
HttpSession session = request.getSession(); --保存会话数据 s1
② 浏览器1的新窗口:(带着s001的标记到服务器查询,s001->s1,返回s1)
得到session对象的会话数据
HttpSession session = request.getSession(); --可以取出 s1
③ 新的浏览器1:(没有带s001,不能返回s1)
得到session对象的会话数据
HttpSession session = request.getSession(); --不可以取出 s2
④ 浏览器2:(没有带s001,不能返回s1)
得到session对象的会话数据
HttpSession session = request.getSession(); --不可以取出 s3
6. 代码解读(伪代码)
HttpSession session = request.getSession();
(1) 第一次访问创建session对象,给session对象分配一个唯一的ID,是JSESSIONID;
new HttpSession();
(2) 把JSESSIONID作为Cookie的值发送给浏览器保存;
Cookie cookie = new Cookie("JSESSIONID", sessionID);
response.addCookie(cookie);
(3) 第二次访问的时候,浏览器带着JSESSIONID的cookie访问服务器;
(4) 服务器得到JSESSIONID,在服务器的内存中搜索是否存在对应编号的session对象;
if(找到){
return map.get(sessionID);
}
Map<String,HttpSession>
<"s001", s1>
<"s001",s2>
(5) 如果找到对应编号的session对象,直接返回该对象;
(6) 如果找不到对应编号的session对象,创建新的session对象,继续走1的流程;
结论:通过JSESSION的cookie值在服务器找session对象!
7. Session细节
(1) java.lang.String getId():得到session编号;
(2) 两个getSession方法:
其中带参数的里面是一个布尔值,Session session = getSession(boolean flag);
① getSession(true) / getSession():创建或得到session对象。如果没有匹配的session编号,自动创
建新的session对象。
② getSession(false):得到session对象。如果没有匹配的session编号,返回null。
(3) void setMaxInactiveInterval(int interval) : 设置session的有效时间。
注意:关闭浏览器后session对象是没有销毁的,关了浏览器不可能会影响到服务器,session是保存在服务器端
的。
(4) session对象销毁时间:
① 默认情况30分钟后服务器自动回收;
② 修改session回收时间;
③ 全局修改session有效时间;
④ 手动销毁session对象;
void invalidate():销毁session对象。
(5) 如何避免浏览器的JSESSIONID的cookie随着浏览器关闭而丢失的问题?
8. Session实例
(1) 实例一:保存会话数据到Session域对象和从Session域对象中取出会话数据。
/*
* 保存会话数据到session域对象
*/
@WebServlet("/SessionDemo1")
public class SessionDemo1 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.创建session对象
HttpSession session = request.getSession();
// 2.保存会话数据
session.setAttribute("name", "rose");
System.out.println("保存成功");
}
}
/*
* 从session域对象中取出会话数据。
*/
@WebServlet("/SessionDemo2")
public class SessionDemo2 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.得到session对象
HttpSession session = request.getSession();
// 2.取出数据
String name = (String) session.getAttribute("name");
System.out.println("name=" + name);
}
}
运行结果如下图所示:
从结果中可以看出,如果我们先访问SessionDemo2,取出的数据是name=null,因为我们还没有存数据,只有
先访问SessionDemo1后把数据存入Session对象中,那么才能取出数据。
(2) 实例二:避免cookie随着浏览器的关闭而丢失。
@WebServlet("/SessionDemo3")
public class SessionDemo3 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.创建session对象
HttpSession session = request.getSession();
/*
* 得到session编号
*/
System.out.println("id=" + session.getId());
// 2.保存会话数据
session.setAttribute("name", "rose");
/*
* 手动发送一个硬盘保存的cookie数据给浏览器,这样就可以避免cookie随着浏览器的关闭而丢失的问题。
*/
Cookie c = new Cookie("JSESSIONID", session.getId());
c.setMaxAge(60 * 60);
response.addCookie(c);
}
}
@WebServlet("/SessionDemo4")
public class SessionDemo4 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1.得到session对象
HttpSession session = request.getSession();
/*
* 得到session编号
*/
System.out.println("id=" + session.getId());
// 2.取出数据
String name = (String) session.getAttribute("name");
System.out.println("name=" + name);
}
}
运行结果如下图所示:
通过运行结果可以发现:当我们关闭浏览器,再访问SessionDemo4的时候仍然可以取出数据。
(3) 实例三:销毁Session对象。
/*
* 销毁session对象
*/
@WebServlet("/DeleteSession")
public class DeleteSession extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession(false);// 如果里面传入false,那么必须判定它不为空
if (session != null) {
session.invalidate();// 手动销毁
}
System.out.println("销毁成功");
}
}