*TOC](Cookie 和 Session 的工作流程)
Cookie 是浏览器在本地持久化存储数据的一种机制
1.Cookie 的数据从哪里来?
服务器返回给浏览器的
2.Cookie 的数据的格式
Cookie 中是键值对结构的数据,并且这里的键值对都是程序员自己定义的
3.Cookie 有什么作用?
Cookie 可以在浏览器中存储一些"临时性数据",其中最典型的一种方式,就是用来存储"身份标识":sessionId,这里就涉及到Cookie 和session之间的联动了,Cookie 是浏览器存储数据(sessionId
),而session是服务器存储数据 ( 存储用户的详细信息,同时分配给用户一个sessionId(唯一值) ) ,后续再访问该网站的其他页面的时候,请求中就会自动带上刚才的sessionId,进一步的服务器就会知道当前是哪个用户在操作了
4.Cookie 到哪里去?
Cookie 的内容会在下次访问该网站的时候,自动的被带到HTTP请求中
5.Cookie 是怎么存的?
浏览器按照不同的"域名"分别存储Cookie ,域名和域名之间的Cookie 是不能互相干扰的,存储在硬盘上的,存储往往会有一个超时时间
方法 | 描述 |
---|---|
HttpSession getSession() | 在服务器中获取会话. 参数如果为 true, 则当不存在会话时新建会话; 参数如果为 false, 则当不存在会话时返回 null |
Cookie[]getCookies() | 返回一个数组, 包含客户端发送该请求的所有的 Cookie 对象. 会自动把Cookie 中的格式解析成键值对 |
getSession()方法,是最核心的api,效果有两方面:
1.如果当前用户没有session(会话),就会创建出session
2.如果已经有了session,就能够查询到这个session
方法 | 描述 |
---|---|
void addCookie(Cookie cookie) | 把指定的 cookie 添加到响应中. |
一个 HttpSession 对象里面包含多个键值对. 我们可以往 HttpSession 中存任何我们需要的信息
方法 | 描述 |
---|---|
Object getAttribute(Stringname) | 该方法返回在该 session 会话中具有指定名称的对象,如果没有指定名称的对象,则返回 null. |
void setAttribute(Stringname, Object value) | 该方法使用指定的名称绑定一个对象到该 session 会话 |
boolean isNew() | 判定当前是否是新创建出的会话 |
session存在的意义,也是为了让用户存储一些自定义的数据,此处的session更像是一个Map
session这个东西在服务器中是存在很多份的,每个用户都有一份自己的session,一个服务器会有多个用户,因此,服务器这边也会通过Map的方式来组织多个session
每个 Cookie 对象就是一个键值对
方法 | 描述 |
---|---|
String getName() | 该方法返回 cookie 的名称。名称在创建后不能改变。(这个值是 SetCooke 字段设置给浏览器的) |
String getValue() | 该方法获取与 cookie 关联的值 |
void setValue(StringnewValue) | 该方法设置与 cookie 关联的值。 |
HTTP 的 Cooke 字段中存储的实际上是多组键值对. 每个键值对在 Servlet 中都对应了一个 Cookie 对象. 通过
HttpServletRequest.getCookies() 获取到请求中的一系列 Cookie 键值对. 通过
HttpServletResponse.addCookie() 可以向响应中添加新的 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;
@WebServlet("/setCookie")
public class setCookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//期望通过这个doGet方法,把一个自定义的Cookie数据返回到浏览器这边
Cookie cookie = new Cookie("data","2023-09-23");
Cookie cookie1 = new Cookie("time","16:24");
resp.addCookie(cookie);
resp.addCookie(cookie1);
resp.getWriter().write("setCookie ok");
}
}
运行setCookie之后,代码中就会构造Cookie放到响应中,通过fiddler抓包工具可以看到本次请求的响应中,出现了
也就是由代码中的addCookie操作构造除了这两个响应的header
Set-Cookie: data=2023-09-23
Set-Cookie: time=16:24
此后,通过这两个响应头,就可以把cookie返回到浏览器中,我们就可以在浏览器中查看已经设置好了的Cookie属性了
后续再次发送get请求的时候,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;
@WebServlet("/getCookie")
public class getCookieServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取到这次请求中的Cookie
Cookie[]cookies = req.getCookies();
if (cookies!=null){
for (Cookie cookie:cookies){
System.out.println(cookie.getName()+":"+cookie.getValue());
}
}else{
System.out.println("当前请求中没有Cookie");
}
resp.getWriter().write("ok");
}
}
servlet也提供了session相关的支持
实现登录功能,不需要直接使用cookie api,直接使用session的api就可以了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<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>
此处先构造出一个html的页面,在用户点击提交按钮的时候,就会使用form表单构造出一个http请求,方法名是post,路径是login
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 {
//1.获取用户名和密码
String username = req.getParameter("username");
String password = req.getParameter("password");
if (username == null||password==null||username.equals("")||password.equals("")){
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("请求的参数不完整");
return;
}
//2.验证用户名密码是否正确
if (!username.equals("zhangsan")){
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("用户名错误!");
return;
}
if (!password.equals("88888888")){
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("密码错误!");
return;
}
//登录成功,此时就可以给这个用户创建会话了
//参数为true,不存在就会创建(登录时使用)
//参数为false,不存在就会返回一个null(后续跳转到其他页面,检查用户的登录状态的时候使用)
HttpSession session =req.getSession(true);
//在会话中,可以顺便保存自定义的数据,比如保存一个登陆的时间戳
//setAttribute后面的value是一个object,存任何数据都可以
session.setAttribute("username",username);
session.setAttribute("time",System.currentTimeMillis());
//4.让页面自动跳转到到网站主页
//此处约定跳转主页的路径是index(也使用servlet来生成一个动态页面)
resp.sendRedirect("index");
}
}
此处是关于登录的逻辑,并在登录成功后,通过重定向绑定一个新的页面的路径,新的路径为index
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;
//通过这个servlet来生成一个主页
@WebServlet("/index")
public class indexServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//先验证一下用户的登录状态,如果未登录,就要求用户要先登录
HttpSession session = req.getSession(false);
if (session==null){
//用户未登录
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("请先登录,再访问主页");
return;
}
//已经登录成功了
//取出之前的attribute
String username = (String) session.getAttribute("username");
Long time = (Long) session.getAttribute("time");
System.out.println("username="+username+"time="+time);
//根据这样的内容构造页面
resp.setContentType("text/html;charset=utf8");
resp.getWriter().write("欢迎您!"+username+"!上次登录时间:"+time);
}
}