web会话可简单理解为:用户开一个浏览器,访问某一个web网站,在这个网站点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话.
它是指浏览器和服务器之间的多次请求和响应:
也就是说,从浏览器访问服务器开始,可以多次访问服务器资源,到浏览器关闭为止这段时间
产生的多次请求和响应,合起来就叫做浏览器和服务器之间的一次会话。
例如:
1. 打开浏览器
2. 访问京东, 此时 与京东网站 产生了会话
3. 访问京东的具体商品页面; 或 其他页面; 或访问了其他网站, 此时,一直会与京东网站保持着会话连接
4. 关闭浏览器, 此时 与京东网站的会话结束;
重写打开浏览器,再次访问京东, 这就是第二次会话了
会话技术用来解决的客户端与服务器之间的通信问题,通过会话技术可以让每个用户的数据以会话对象的形式存储,方便以后访问web资源的时候使用。
举几个场景:
场景一:
A和B两个人在某购物网站登录账号后,A购物车添加了一个TinkPad键盘,
而B添加一本《JAVAWEB开发内幕》,这些商品信息都会被记录下来,
以便用户在结账的时候可以买到对应的商品。
场景二:
在论坛登陆的时候,很多时候会有⼀个⼩框框问你是否要⾃动登陆,当你下次登陆的时候就不⽤输⼊密码了。
场景三:
根据我以前浏览过的商品,猜我喜欢什么商品
在当下的市场开发中,传统项目的会话管理分为两类,分别是:客户端会话管理技术和服务端会话管理技术。
什么是客户端会话管理技术?
程序把每个用户的数据以某种形式写给用户各自的浏览器。当用户使用浏览器再访问服务器中的web资源时,
就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。我们采用Cookie技术实现。
什么是服务端会话管理技术?
用户使用浏览器访问服务器的时候,服务把用户的信息,以某种形式记录在服务器上,
这样在访问的时候就能保证用户各自使用各自在服务器中的数据。我们采用Session技术实现。
在客户端与服务器端交互的过程中,通常会产生一些数据, 为了保存会话过程中产生的数据,在Servlet技术中,提供了两个用于保存会话数据的对象,分别是Cookie和Session。
通过京东购物车案例, 了解会话技术 Cookie对象 和 Session对象
Cookie对象:
客户端浏览器的会话技术,它可以把服务器传递过来的一些数据记录在客户端浏览器中,
解决会话从什么时候开始,到什么时候结束。
Session对象:
服务器端的会话技术, 它可以把同一用户与服务器多次请求响应的一些数据记录在服务器Session域中,
实现该用户在本次会话中, 可随时获取Session域中的数据, 满足多次请求响应之间进行数据传递\访问使用.
1.Cookie是什么?
它是客户端浏览器的缓存文件,里面记录了客户浏览器访问网站的一些内容。
同时,也是HTTP协议请求和响应消息头的一部分(在HTTP协议课程中,我们提到过它)。
2.为什么需要会话技术记录这些内容呢?
我们网页的交互是通过HTTP协议,而HTTP协议是无状态的协议(数据提交后,浏览器和服务器连接就会关闭,再次交 互就得重新建立新的连接)。所以服务器是无法确认用户的信息,于是就给每个用户发一个通行证(Cookie),从而可 以通过此确认用户信息。
3.Cookie技术可以解决什么问题呢?
可以用来在浏览器存储交互数据,当下次访问服务器的时候会自动带着相应cookie给服务器,
从以此提高交互的效率!
4.谁来创建Cookie?它又保存在哪里?
Cookie是由服务器创建,然后发送给客户端浏览器,
最终可以保存到浏览器指定位置(前提浏览器支持)上的一段文本信息。
流程:
1.第一次访问服务器,正常访问服务器.
2.服务器接收到请求后,服务器端可以通过 set-cookie 响应头 响应一小段信息
3.客户端(浏览器)接收到,自动保存cookie信息到cookie存储区中(由浏览器软件保存该信息)
4.后续访问中,浏览器会从cookie存储区取出信息,并且在发送信息的时候,通过 cookie 请求头携带上
服务器端接收到请求后,可以从请求头中获取该小段cookie信息.
强调:
1.cookie就是一小段标识信息(键值对)!!!
2.cookie的内容保存在浏览器端!!!
服务器端创建Cookie对象
方法 | 返回值 | 描述 |
---|---|---|
public Cookie(String name, String value) | 构造方法创建Cookie对象 | 创建Cookie对象, 并指定Cookie中保存 的键值对信息 |
服务器端Response对象向浏览器发送Cookie
方法 | 返回值 | 描述 |
---|---|---|
addCookie(Cookie c) | void | 把方法参数指定Cookie对象c响应给客户端浏览器 |
服务器端Request对象获取浏览器发送的Cookie
方法 | 返回值 | 描述 |
---|---|---|
getCookies() | Cookie[] | 获取客户端发送的所有对象的数组,如果客户端浏览器没有发送Cookie返回null |
Cookie对象的方法
方法 | 参数 | 描述 |
---|---|---|
String getName() | 无 | 获取cookie 的名称(键)。名称在创建之后不得更改。 |
String getValue() | 无 | 获取cookie 的值 |
void setMaxAge(int s) | int | 浏览器中Cookie是有生存时间的,默认是当前会话. 浏览器关闭,会话结束 该方法用于指定 cookie 的最大生存时间(以秒为单位)的整数; 如果为负数,则表示不存储该 cookie;如果为 0,则删除该 cookie |
void setPath(String p) | String | 设置携带Cookie的路径 也就是说浏览器访问什么样的路径才会携带Cookie对象 |
void setDomain(String d) | String | 设置携带Cookie的域名(如:www.itheima.com) 也就是说浏览器访问什么样的域名才会携带Cookie对象 |
响应Cookie对象给浏览器
package com.itheima.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的servlet
*/
@WebServlet("/create")
public class CreateCookieServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("当浏览器访问到这个servlet的时候,我们就在这里构建一个cookie");
//如何构建cookie
Cookie cookie = new Cookie("username", "jack");
Cookie cookie1 = new Cookie("job", "小钻风");
System.out.println("构建出来之后 放到响应头中 就返回给了浏览器 完成了cookie的创建及保存");
response.addCookie(cookie);
response.addCookie(cookie1);
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("cookie已经创建好,你自己个在浏览器找吧!!");
}
}
ps:第一发起请求,浏览器请求中不带cookie,响应的时候 服务传递两个cookie在响应头中。浏览器中看到了cookie
获取客户端浏览器携带的Cookie数据
/*
浏览器访问服务器,以请求头的方式携带Cookie(可能是多个)
HttpServletRequest对象提供方法
public Cookie[] getCookies(): 获取浏览器携带的所有Cookie对象,如果没有携带Cookie返回null
*/
@WebServlet(urlPatterns = "/get")
public class GetCookieServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/**
* 获取客户端浏览器携带的Cookie数据
* request对象方法 getCookies()
*/
Cookie[] cookies = request.getCookies();
for (Cookie cookie : cookies){
//遍历数组,取出的是数组中的每个Cookie对象
//取出Cookie中的键
String key = cookie.getName();
//取出Cookie中的值
String value = cookie.getValue();
System.out.println(key+"==="+value);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
ps:再次访问的时候浏览器会带着cookie过去,这次服务器没有构建cookie所以响应中没有cookie,但是请求中有cookie.服务器可以解析出来两个cookie
设置生存时间
默认
/*
Cookie的生命周期
1.默认情况下: 一次会话有效,关闭浏览器,会话结束Cookie消失
2.设置Cookie的生命周期(存活时间)
Cookie中提供方法
public void setMaxAge(int s): 设置方法参数指定的s秒的生存时间
int s: 单位是秒
*/
@WebServlet(urlPatterns = "/life")
public class LifeCookieServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Cookie cookie = new Cookie("heima","java");
cookie.setPath(request.getContextPath());
//设置生存时间
cookie.setMaxAge(60);
response.addCookie(cookie);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
设置Cookie的携带路径
默认路径是 创建该cookie上一级路径。
只有跟这个cookie相同路径的servlet才能传递过来到。保证模块独立性。
这个cookie在整个项目中公用,设置为项目路径。
在Web开发中,Cookie是一种存储在客户端浏览器中的小数据片段,用于跟踪用户会话和存储用户偏好设置等信息。每个Cookie都有一个可选的Path属性,用于指定Cookie的作用域(即哪些Web页面可以访问该Cookie)。
Path属性是一个字符串,指定了Cookie的有效路径。默认情况下,如果未指定Path属性,则Cookie的有效路径为设置Cookie的页面路径。例如,如果在根目录下的index.html页面中设置了一个Cookie,则该Cookie的有效路径为"/",即整个网站可以访问该Cookie。如果在子目录下的页面中设置了一个Cookie,则该Cookie的有效路径为该子目录。
可以使用setPath()方法来设置Cookie的Path属性。例如,以下代码将创建一个名为"username"的Cookie,并将其Path属性设置为"/myapp":
Cookie cookie = new Cookie("username", "john");
cookie.setPath("/myapp");
response.addCookie(cookie);
在这种情况下,只有路径为"/myapp"或其子路径的页面才能访问该Cookie。如果在其他路径下的页面中尝试访问该Cookie,则无法访问。使用Path属性可以限制Cookie的作用域,从而增强Web应用程序的安全性和隐私性。
以上代码演示时,均需要打开浏览器调试模式,查看Cookie是否被创建,访问时是否携带了Cookie对象
1.为什么要使用Cookie和Session?
⽤户使⽤浏览器访问服务器的时候,服务器把可以为每个用户浏览器创建一个会话对象(session对象),
因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器所属的session中,
当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据
实现用户数据在会话中的共享。
2.什么是Session?
Session对象: 服务器端的会话技术, 它可以把同一用户与服务器多次请求响应的一些数据
记录在服务器Session域中, 实现该用户在本次会话中, 可随时获取Session域中的数据,
满足多次请求响应之间 进行数据传递\访问使用.
思考, 下面的购物车案例中, 使用ServletContext域 或 Request域 存储购物车商品信息 是否适合?
1.Session与Cookie是紧密相关的。
Session的使用要求用户浏览器必须支持Cookie,如果浏览器不支持使用Cookie,
或者设置为禁用Cookie,那么将不能使用Session。2.Session信息对客户来说,不同的用户, 使用不同的Session信息来记录。
当用户启用Session时,Tomcat引擎自动产生一个SessionID. 在新会话开始时,
服务器将SessionID当做cookie存储在用户的浏览器中。
1:Cookie是把用户的数据写给用户的浏览器。Session技术把用户的数据写到用户所属的session中。
2:Session⽐Cookie使⽤⽅便,Session可以解决Cookie解决不了的事情
【Session可以存储对象,Cookie只能存储字符串。】
3:Cookie存储在浏览器中,对客户端是可⻅的。信息容易泄露出去。
Session存储在服务器上,客户端是无法获取的。不存在敏感信息泄露问题。
cookie | session | |
---|---|---|
会话数据保存的位置 | 浏览器 | 服务器 |
数据的安全性 | 不安全 | 安全 |
存储数是否有限制 | 有 | 无 |
session的工作流程总结:
1.请求服务器,请求服务器端储存信息
2.服务器端接收请求,创建一个session对象和一个唯一id 一一映射放在session池中
3.将数据存储到session对象中 (session对象内部是map集合可以储存很多信息)
4.响应给客户端的时候,在响应头中带有一个jessionId的cookie 值是该session的唯一ID
5.客户端在之后的请求中,都自动携带该cookie,服务器端根据该cookie中唯一id,获取与之对应的session对象
综上所述:
1.session是一个域对象,只要在一个会话中就可以实现多个Servlet间数据共享。
2.每一个客户端都有自己唯一对应的session对象,故存放的数据也是私有的.别的客户端无法获取。
3:jsessionId 这个Cookie存活时间为会话结束,也就是关闭浏览器就没有了。
获取通过Request对象调用如下方法获取Session域对象
HttpSession接口,session对象是接口的实现类,实现类对象tomcat引擎创建 方法 request.getSession()获取session对象 作用域 : 一次会话有效,浏览器不关闭
方法 | 返回值 | 描述 |
---|---|---|
getSession() | HttpSession | 获取当前会话对应的Session对象,如果没有,则创建一个Session对象。 |
Session域对象存储数据
方法 | 返回值 | 描述 |
---|---|---|
setAttribute(String name, Object obj) | void | 向Session域中保存数据 |
getAttribute(String name) | Object | 从Session域中获取数据 |
removeAttribute(String name) | void | 从Session域中移除数据 |
Session域对象销毁
1.如果我们打开一个页面长时间不访问,默认会30分钟后进行销毁。
tomcat配置文件web.xml中有如下配置:
30
2.也可以立刻销毁 session.invalidate()。
3.还可以设置过期时间 session.setMaxInactiveInterval(秒);
4.关闭服务器。
方法 | 返回值 | 描述 |
---|---|---|
invalidate() | void | 使此会话无效,然后取消对任何绑定到它的对象的绑定。 销毁Session对象 |
setMaxInactiveInterval(int s) | void | 设置过期时间 |
获取Session域对象并存取数据
package com.itheima.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("/cun")
public class CunSessionServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("当浏览器第一访问 服务器的时候");
System.out.println("服务器可以 为当前浏览器构建一个session对象");
HttpSession session = request.getSession();
// 特点 如果浏览器没有 jsessionid 那么就是新建一个
// 如果有且在session池中找到了 该方法就是获取方法
//获取session 创建的新session 有一个id
System.out.println("查看session的id:"+session.getId());
//服务器会自己 偷偷把我们的 session的id 封装成 new Cookie("JSESSIONID",id值)
// 存到响应头中
//我还想 把一个数据存到session中 实现会话中的数据共享
session.setAttribute("goods","大金砖");//这个域 是会话域 只在这次会话中有效
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("一个新的session对象产生了,id是:"+session.getId()+
"
我们还往session存储了数据");
}
}
观察:响应有了 jsessionid 对 jsessioid
同一会话先访问/session1向域中存数据,再访问session2从Session域中取数据
package com.itheima.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("/qu")
public class QuSessionServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("当浏览器再次 服务器的时候");
System.out.println("如果还在这次会话中,getSession获取的session就是上一个session ");
HttpSession session = request.getSession();
// 特点 如果浏览器没有 jsessionid 那么就是新建一个
// 如果有且在session池中找到了 该方法就是获取方法
//获取session 创建的新session 有一个id
System.out.println("查看session的id:"+session.getId());
//从域中取数据
Object goods = session.getAttribute("goods");//这个域 是会话域 只在这次会话中有效
System.out.println("取出的物品是:"+goods);
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("再次访问服务器,是找到之前的session,sessionid是:"+session.getId()+
"
我们从session中取了数据"+goods);
}
}
观察 :取得时候,再次访问了看到了 大金块 说明数据实现了会话域共享,而且访问的时候带着令牌去访问的,所以可以获取之前存的数据。
但是浏览器以Cookie的形式保存Session对象的id,默认生命周期是一次会话有效
总结:
同一会话访问/cun,发现浏览器Cookie中保存的id和代码输出到控制台的id是相同的 接着访问/qu,发现控制台输出的id和前面一样, 说明/qu对应的Servlet中并没有创建新的Session对象
持久化Session对象(只需要持久化Session对应的id)
package com.itheima.session;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;
@WebServlet("/sessionlong")
public class SessionLongServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//想要持久化jessionid 怎么做呢
System.out.println("先获取我们session 如果有就获取 ,没有就新建");
HttpSession session = request.getSession();
System.out.println("当前session对象的id是:"+session.getId());
//我们 之前的jsession遵循默认规则 我们可以显性化
Cookie jsessionid = new Cookie("JSESSIONID", session.getId());
jsessionid.setMaxAge(60*10);
jsessionid.setPath(request.getContextPath());//设置路径为项目路径
//存到响应头
response.addCookie(jsessionid);
response.getWriter().write("see this session:"+session.getId());
}
}
总结
如果想 关闭浏览器再打开访问的session是同一个,只需我们修改jsessionid的存活时间即可。
作为面试题出现,开发不做。
session什么时候失效呢?
服务器关闭
从浏览器的角度,默认情况关闭浏览器,会话就结束。
服务器中默认 session是30分钟。
可以手动让session销毁 session.invalidate();
效果
分析
准备页面(直接放在/web根目录下)
index.html页面内容
研究cookie和session
欢迎来购物
买肉
买球
meat.html页面内容
Title
各种肉大甩卖,一律十块:
ball.html页面内容
Title
各种球大甩卖,一律八块
showCart.jsp页面内容
<%@ page contentType="text/html;charset=UTF-8" language="java" import="java.util.*" %>
显示购物车内容
你选择的结果是:
<%
Set cart = (Set) session.getAttribute("cart");
if (cart != null && cart.size() > 0) {
for (String s : cart) {
out.println(s);
}
}
%>
CartServlet类内容
@WebServlet("/cart")
public class CartServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 1:获取 页面提交 需要加入购物车的 商品
request.setCharacterEncoding("utf-8");
String[] goods = request.getParameterValues("goods");
//从域中获取一个购物车对象 其实就是商品列表信息
Set cart = (Set) request.getSession().getAttribute("cart");
// 判断
if (cart == null) {
//购物车是空的
cart = new HashSet<>();
if (goods != null && goods.length > 0) {
// 将数组中数据 收集到指定的 集合中
Collections.addAll(cart, goods);
}
} else {
// 往里面追加
if (goods != null & goods.length > 0) {
// 将数组中数据 收集到指定的 集合中
Collections.addAll(cart, goods);
}
}
//购物车完成了更新
// 存到session中
request.getSession().setAttribute("cart", cart);
//自己做个遍历
for (String s : cart) {
System.out.println(s);
}
response.setContentType("text/html;charset=utf-8");
response.getWriter().write("添加购物车成功!
跳回主页
查看购物车列表");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}