提示:以下是本篇文章正文内容,下面案例可供参考
HTTP 协议自身是属于 “无状态” 协议.
ps:“无状态” 的含义指的是: 默认情况下 HTTP 协议的客户端和服务器之间的这次通信,
和下次通信之间没有直接的联系.
但是实际开发中, 我们很多时候是需要知道请求之间的关联关系的
ps:例如登陆网站成功后, 第二次访问的时候服务器就能知道该请求是否是已经登陆过了.
图中的 “令牌” 通常就存储在 Cookie 字段中
ps:回忆之前的例子:
服务器同一时刻收到的请求是很多的. 服务器需要清除的区分清楚每个请求是从属于哪个用户, 就需要在
服务器这边记录每个用户令牌以及用户的信息的对应关系.
ps:在上面的例子中, 就诊卡就是一张 “令牌”. 要想让这个令牌能够生效, 就需要医院这边通过系统记录每个就诊卡和患者信息之间的关联关系.
会话的本质就是一个 “哈希表”, 存储了一些键值对结构. key 就是令牌的 ID(token/sessionId), value 就
是用户信息(用户信息可以根据需求灵活设计)
ps:sessionId 是由服务器生成的一个 “唯一性字符串”, 从 session 机制的角度来看, 这个唯一性字符串
称为 “sessionId”. 但是站在整个登录流程中看待, 也可以把这个唯一性字符串称为 “token”.
sessionId 和 token 就可以理解成是同一个东西的不同叫法(不同视角的叫法).
当用户登陆的时候, 服务器在 Session 中新增一个新记录, 并把 sessionId / token 返回给客户端.
(例如通过 HTTP 响应中的 Set-Cookie 字段返回).
客户端后续再给服务器发送请求的时候, 需要在请求中带上 sessionId/ token.
(例如通过 HTTP 请求中的 Cookie 字段带上).
服务器收到请求之后, 根据请求中的 sessionId / token 在 Session 信息中获取到对应的用户信息,
再进行后续操作.
ps:Servlet 的 Session 默认是保存在内存中的. 如果重启服务器则 Session 数据就会丢失.
HTTP 的 Cooke 字段中存储的是多组键值对. 每个键值对在 Servlet 中都对应了一个 Cookie 对象.
通过 HttpServletRequest.getCookies() 获取到请求中的一系列 Cookie 键值对.
通过 HttpServletResponse.addCookie() 可以向响应中添加新的 Cookie 键值对.
我们这里约定一下前后端交互接口
ps:针对前后端交互接口,有很多种约定方式,你确定其中一种即可
代码如下:
启动服务器
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;
/**
* Created with IntelliJ IDEA.
* Description:
* User: 25397
* Date: 2022-07-08
* Time: 15:00
*/
@WebServlet("/login")
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//处理用户请求
String username=req.getParameter("username");
String password=req.getParameter("password");
//判断用户名或密码是否正确
//一般来说这个判断操作需要放到数据库存取的
//我们这里为了简单,就直接在代码里写死了,假设有效用户名和密码是“zhangsan”,“123”
if("zhangsan".equals(username)&&"123".equals(password)){
//为什么不写username.equals("zhangsan")?
//一旦用户不输入用户名直接点登录,那就是null.equals,会出现空指针异常
//登录成功
//创建会话,并保存必要的身份信息
//会话里可以保存任意指定的用户信息,比如我们这里可以实现一个简单的功能,记录用户访问主页的次数
HttpSession httpSession= req.getSession(true);
//往会话中存储键值对(必要信息)
httpSession.setAttribute("username",username);
//初始情况下,把登录次数count设为0
httpSession.setAttribute("count",0);
//setAttribute的第二个参数是Object,int不是Object但是Integer是
//在上面的httpSession.setAttribute("count",0);代码中会触发Java中的自动装箱机制,自动把0转成Integer
//我们存的是Integer,所以在后续的IndexServlet中也是用Integer来取
resp.sendRedirect("index");//跳转到index页面
}else{
//登录失败
resp.getWriter().write("login failed");
}
}
}
页面服务器
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;
/**
* Created with IntelliJ IDEA.
* Description:
* User: 25397
* Date: 2022-07-08
* Time: 15:23
*/
@WebServlet("/index")
public class IndexServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//返回一个主页(简单的html片段)
//此处需要得到用户名(从HttpSession片段中可得)
HttpSession session=req.getSession(false);
//此处getSession的参数必须是false,前面在登录过程中,已经创建过会话了,此处是要直接获取之前的会话
String username=(String) session.getAttribute("username");
//除了用户名外,还从会话中取出count
Integer count=(Integer)session.getAttribute("count");
count+=1;
//把自增后的值再写回到会话中
session.setAttribute("count",count);
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("欢迎你"
+username+"这是第"+count+"次访问"+""
);
}
}
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<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>