📢博客主页:🏀敲代码的布莱恩特🏀
📢欢迎点赞 👍 收藏 ⭐留言 📝 欢迎讨论!👏
📢本文由 【敲代码的布莱恩特】 原创,首发于 CSDN🙉🙉🙉
📢由于博主是在学小白一枚,难免会有错误,有任何问题欢迎评论区留言指出,感激不尽!✨
📖精品专栏(不定时更新)【JavaSE】 【Java数据结构】【LeetCode】
【Web】Cookie 和 Session
回顾 Cookie
HTTP 协议自身是属于 “无状态
” 协议.
“无状态” 的含义指的是:
默认情况下 HTTP 协议的客户端和服务器之间的这次通信, 和下次通信之间没有直接的联系.
但是实际开发中, 我们很多时候是需要知道请求之间的关联关系的.
例如登陆网站成功后, 第二次访问的时候服务器就能知道该请求是否是已经登陆过了.
通过set-cookie返回给浏览器储存在Cookie字段中的东西就好比服务器给客户端的一个令牌
用于身份确认和标识
此时在服务器
这边就需要记录令牌信息
, 以及令牌对应的用户信息, 这个就是 Session 机制所做的工作.
理解会话机制 (Session)
服务器同一时刻收到的请求是很多的. 服务器需要清除的区分清楚每个请求是从属于哪个用户, 就需要在服务器这边记录每个用户令牌以及用户的信息的对应关系.
就像去医院看病,就诊卡就是一张 “令牌”. 要想让这个令牌能够生效, 就需要医院这边通过系统记录每个就诊卡和患者信息之间的关联关系.
会话的本质就是一个 “哈希表
”, 存储了一些键值对结构. key 就是令牌的 ID
(token/sessionId), value 就是用户信息
(用户信息可以根据需求灵活设计).
sessionId
是由服务器生成的一个 “唯一性字符串”, 从 session 机制的角度来看, 这个唯一性字符串称为 “sessionId”. 但是站在整个登录流程中看待, 也可以把这个唯一性字符串称为 “token”. sessionId 和 token 就可以理解成是同一个东西的不同叫法(不同视角的叫法)
Servlet 的 Session 默认是保存在内存中的.
如果重启服务器则 Session 数据就会丢失.
Cookie 和 Session 的区别
- Cookie 是
客户端
的机制. Session 是服务器端
的机制. - Cookie 和 Session 经常会在一起配合使用. 但是不是必须配合.
- 完全可以用 Cookie 来保存一些数据在客户端. 这些数据不一定是用户身份信息, 也不一定是
token / sessionId - Session 中的 token / sessionId 也不需要非得通过 Cookie / Set-Cookie 传递.
核心方法
HttpServletRequest 类中的相关方法
方法 | 描述 |
---|---|
HttpSession getSession() | 在服务器中获取会话. 参数如果为 true, 则当不存在会话时新建会话; 参数如果为 false, 则当不存在会话时返回 null |
Cookie[ ] getCookies() | 返回一个数组, 包含客户端发送该请求的所有的 Cookie 对象. 会自动把Cookie 中的格式解析成键值对. |
HttpServletResponse 类中的相关方法
方法 | 描述 |
---|---|
void addCookie(Cookie cookie) | 把指定的 cookie 添加到响应中. |
HttpSession 类中的相关方法
一个 HttpSession 对象里面
包含多个键值对
. 我们可以往 HttpSession 中存任何我们需要的信息
.
方法 | 描述 |
---|---|
Object getAttribute(Stringname) | 该方法返回在该 session 会话中具有指定名称的对象,如果没有指定名称的对象,则返回 null. |
void setAttribute(Stringname, Object value) | 该方法使用指定的名称绑定一个对象到该 session 会话boolean isNew() 判定当前是否是新创建出的会话 |
Cookie 类中的相关方法
每个 Cookie 对象就是一个键值对.
方法 | 描述 |
---|---|
String getName() | 该方法返回 cookie 的名称。名称在创建后不能改变。(这个值是 SetCooke 字段设置给浏览器的) |
String getValue() | 该方法获取与 cookie 关联的值 |
void setValue(StringnewValue) | 该方法设置与 cookie 关联的值。 |
- HTTP 的 Cooke 字段中存储的实际上是多组键值对. 每个键值对在 Servlet 中都对应了一个Cookie 对象.
- 通过 HttpServletRequest.getCookies() 获取到请求中的一系列 Cookie 键值对.
- 通过 HttpServletResponse.addCookie() 可以向响应中添加新的 Cookie 键值对.
代码示例: 实现用户登陆
实现简单的用户登陆逻辑
这个代码中主要是通过 HttpSession 类
完成. 并不需要我们手动操作 Cookie 对象.
1.实现一个登陆页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登陆</title>
</head>
<body>
<form action="login" method="POST">
<input type="text" name="username">
<input type="password" name="password">
<input type="submit" value="提交">
</form>
</body>
</html>
2.实现一个Servlet用于处理登陆请求
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("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");
// 1. 获取到用户提交的用户名和密码
String username = req.getParameter("username");
String password = req.getParameter("password");
// 2. 判定用户名密码是否正确
if (!username.equals("kobe") || !password.equals("824")) {
// 登陆失败
resp.getWriter().write("登陆失败");
return;
}
// 登陆成功
System.out.println("登陆成功");
// 设置 Session
HttpSession session = req.getSession(true);
session.setAttribute("username", "Kobe Bryant");
session.setAttribute("loginCount", "");
resp.sendRedirect("index");
}
}
3.再实现一个IndexServlet来表示重定向之后的主页
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("/index")
public class IndexServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setContentType("text/html; charset=utf-8");
// 1. 判定当前用户是否已经登陆
HttpSession session = req.getSession(false);
if (session == null) {
// 用户没有登陆, 重定向到 login.html
resp.sendRedirect("login.html");
return;
}
// 2. 如果已经登陆, 则从 Session 中取出访问次数数据
String userName = (String)session.getAttribute("username");
String countString = (String)session.getAttribute("loginCount");
int loginCount = Integer.parseInt(countString);
loginCount += 1;
session.setAttribute("loginCount", loginCount + "");
// 3. 展示到页面上.
StringBuilder html = new StringBuilder();
html.append(String.format("<div>用户名: %s</div>", userName));
html.append(String.format("<div>loginCount: %d</div>", loginCount));
resp.getWriter().write(html.toString());
}
}