Cookie:
1. Cookie 的定义
- Cookie 是存储在用户浏览器中的小块数据,通常由服务器发送并存储,以便在用户浏览器和服务器之间保持会话状态。
- 每次用户发送请求时,浏览器都会自动附带相应的 Cookie,允许服务器辨识用户。
2. Cookie 的用途
- 保持会话状态:用于存储用户登录状态或购物车等会话信息。
- 个性化设置:保存用户的偏好设置,比如语言选择、字体大小等。
- 跟踪用户行为:例如分析用户访问网站的行为,以进行个性化推荐。
3. Cookie 的分类
- 会话 Cookie(Session Cookie):在浏览器关闭后失效,通常用于临时数据存储。
- 持久 Cookie(Persistent Cookie):设置了过期时间,在过期前即使关闭浏览器也不会被删除。
默认情况下 Cookie 的有效期是一次会话范围内,我们可以通过 Cookie 的 setMaxAge() 方法让 Cookie 持久化保存到浏览器上。cookie.setMaxAge(int expiry) 参数单位是秒,表示 cookie 的持久化时间,如果设置参数为 0 ,表示将 浏览器中保存的该cookie 删除。
session:
HttpSession的概述:
HttpSession是一种保留更多信息在服务端的一种技术
,
服务器会为每一个客户端开辟一块内存空
间,即session对象.。客户端在发送请求时,都可以使用自己的session。这样服务端就可以通过
session来记录某个客户端的状态了。
- 服务端在为客户端创建session时,会同时将session对象的id,即JSESSIONID以Cookie的形式放入响 应对象;
- 后端创建完session后,客户端会收到一个特殊的Cookie,叫做JSESSIONID;
- 客户端下一次请求时携带JSESSIONID,后端收到后,根据JSESSIONID找到对应的session对象;
- 通过该机制,服务端通过session就可以存储一些专门针对某个客户端的信息了;
- session也是域对象(后续详细讲解);
应用场景:
- 记录用户的登录状态: 用户登录后,将用户的账号等敏感信息存入session;
- 记录用户操作的历史: 如记录用户的访问痕迹,用户的购物车信息等临时性的信息;
测试:
注意!!!
生成web项目后,一定要删去index.jsp;原因:里面有内置的session对象,会干扰
servlet1:
package servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/servlet1")
public class servlet1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 接收请求中的username参数
String username = req.getParameter("username");
// 获得session对象
HttpSession session = req.getSession();
// 改变session的失效时间
session.setMaxInactiveInterval(120);
System.out.println(session.getId());
System.out.println(session.isNew());
//判断请求中有没有一个特殊的cookie JSESSIONID 值*****
//1有
//根据 JSESSIONID找对应的session对象
// 找到了
// 返回之前的session
// 没有找到
// 创建一个新的session返回,并且向response对象中存放一个SESSIONID 的cookie
// 2 没有
// 创建一个新的session返回,并且向response对象中存放一个SESSIONID 的cookie
// 将username存入session
session.setAttribute("username",username);
// 客户端响应信息
resp.setContentType("text/html;charset = UTF-8");
resp.getWriter().write("成功");
}
}
servlet2:
package servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/servlet1")
public class servlet1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 接收请求中的username参数
String username = req.getParameter("username");
// 获得session对象
HttpSession session = req.getSession();
// 改变session的失效时间
session.setMaxInactiveInterval(120);
System.out.println(session.getId());
System.out.println(session.isNew());
//判断请求中有没有一个特殊的cookie JSESSIONID 值*****
//1有
//根据 JSESSIONID找对应的session对象
// 找到了
// 返回之前的session
// 没有找到
// 创建一个新的session返回,并且向response对象中存放一个SESSIONID 的cookie
// 2 没有
// 创建一个新的session返回,并且向response对象中存放一个SESSIONID 的cookie
// 将username存入session
session.setAttribute("username",username);
// 客户端响应信息
resp.setContentType("text/html;charset = UTF-8");
resp.getWriter().write("成功");
}
}
getSession方法的处理逻辑:
-
初次请求:
- 浏览器向服务器发起第一次请求(请求报文)。
- 服务器端处理该请求,创建一个新的Session,并将Session的ID(如
JSESSIONID
)保存在Cookie中,作为响应的一部分(响应报文),发送给浏览器。
-
浏览器存储Cookie:
- 浏览器接收到服务器的响应,将Cookie中的
JSESSIONID
存储下来。
- 浏览器接收到服务器的响应,将Cookie中的
-
再次请求:
- 当浏览器再次发起请求时,会自动携带之前存储的Cookie(包含
JSESSIONID
)。 - 服务器接收到请求后,读取该Cookie中的Session ID(如
JSESSIONID
),找到与之对应的Session,获取其中存储的键值对数据,处理请求。
- 当浏览器再次发起请求时,会自动携带之前存储的Cookie(包含
-
响应返回:
- 服务器处理完请求后,再次返回响应报文,浏览器接收并继续进行后续的操作。
总结:
- 每次请求时,浏览器都会携带上次存储的Cookie来标识当前用户的会话。
- 服务器通过读取Cookie中的
JSESSIONID
,找到对应的Session,进而保持会话数据的连续性。
HttpSession时效性:
为什么要设置session的时效?
- 用户量很大之后,Session对象相应的也要创建很多。如果一味创建不释放,那么服务器端的内存 迟早要被耗尽;
- 客户端关闭行为无法被服务端直接侦测,或者客户端较长时间不操作也经常出现,类似这些的情 况,就需要对session的时限进行设置了(例如很久没登录过的哔哩哔哩要重新登录)
默认的 session 最大闲置时间 ( 两次使用同一个 session 中的间隔时间 ) 在 Tomcat/conf/web.xml 配置为 30分钟。
如何看TomCat里面设置的session时效呢?
注意!!!!
这里不再是30s了,在Tomcat的配置文件中,<session-timeout>
的单位是分钟。因此,在图中设置的<session-timeout>30</session-timeout>
表示Session超时时间为30分钟,服务器将自动使该Session失效。
如何自己设置时间?
我们可以自己在当前项目的web.xml对最大闲置时间进行重新设定。
也可以通过HttpSession的API 对最大闲置时间进行设定。
三大域对象:
域对象:一些用于存储数据和传递数据的对象。传递数据不同的范围,我们称之为不同的域。不
同的域对象代表不同的域,共享数据的范围也不同
web
项目中,我们一定要熟练使用的域对象分别是 :请求域、会话域、应用域;
- 请求域对象是HttpServletRequest ,传递数据的范围是一次请求之内及请求转发;
- 会话域对象是HttpSession,传递数据的范围是一次会话之内,可以跨多个请求;
- 应用域对象是ServletContext,传递数据的范围是本应用之内,可以跨多个会话;
1. 请求域(Request Scope)
- 对象:
HttpServletRequest
- 作用范围: 仅限于一次HTTP请求。在同一个请求过程中,数据可以在Servlet、JSP或其他组件之间共享。
获取不到数据的情况:
- 请求已经结束: 请求域中的数据只在当前请求有效。一旦请求结束(如重定向、返回响应给客户端后),请求对象会销毁,数据将不可访问。(当然可以进行请求转发,可以获取数据)
- 跨请求: 如果想在一次请求中设置数据,然后在下一次请求中获取(如重定向或从不同的页面发起请求),由于请求已经变化,无法获取之前的请求域数据。
2. 会话域(Session Scope)
- 对象:
HttpSession
- 作用范围: 作用于一个用户会话期间。只要用户会话没有过期或销毁,数据可以在多个请求之间共享。
获取不到数据的情况:
- Session过期或销毁: 如果用户长时间没有操作(超过了Session的超时时间,默认30分钟),Session会被服务器销毁,之后再尝试访问会话域中的数据将获取不到。
- Session手动销毁: 通过调用
session.invalidate()
,会立即销毁会话,所有的会话域数据将被清除。 - 新建Session: 如果在一个新的请求中,用户没有携带之前的Session(如关闭浏览器后再访问),服务器会创建一个新的Session,之前的会话域数据将获取不到。又比如两个浏览器不能共享数据,清空浏览器的历史记录
3. 应用域(Application Scope)
- 对象:
ServletContext
- 作用范围: 作用于整个Web应用程序的生命周期。数据可以在整个应用程序范围内(跨用户和跨请求)共享,直到服务器停止或Web应用重新部署。
获取不到数据的情况:
- 应用程序重启或重新部署: 服务器重启或Web应用重新部署时,应用域中的数据将会被销毁,再次访问时获取不到原有的数据。
- 数据未设置: 如果程序没有显式地通过
ServletContext
设置数据,访问时自然获取不到。 - 应用域数据手动移除: 如果调用
removeAttribute()
方法手动移除了某个数据项,也会导致后续无法获取该数据。
测试 API:
servletA:
package servlet;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/servletA")
public class servletA extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 向请求域存放数据
req.setAttribute("request","requestMessage");
// 向会话域存放数据
HttpSession session = req.getSession();
session.setAttribute("session","sessionMessage");
// 向应用域存放数据
ServletContext servletContext = session.getServletContext();
servletContext.setAttribute("application","applicationMessage");
// 获取请求域
String reqMse = (String) req.getAttribute("request");
System.out.println("请求域" + reqMse);
// // 请求转发
// req.getRequestDispatcher("/servletB").forward(req,resp);
}
}
servletB:
package servlet;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/servletB")
public class servletB extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求域的数据
String reqMse = (String) req.getAttribute("request");
System.out.println("请求域" + reqMse);
// 获取会话域的数据 换一个浏览器就获取不到数据了
HttpSession session = req.getSession();
String SessionMse = (String) session.getAttribute("session");
System.out.println("会话域" + SessionMse);
// 获取应用域的数据
ServletContext servletContext = session.getServletContext();
String AppMse = (String) servletContext.getAttribute("application");
System.out.println("应用域" + AppMse);
}
}