前言
虽然在默认情况下 HTTP 协议的客户端和服务器之间的这次通信, 和下次通信之间没有直接的联系,但是实际开发中, 我们很多时候是需要知道请求之间的关联关系的,例如登陆网站成功后, 第二次访问的时候服务器就能知道该请求是否是已经登陆过了。而上面的操作则是通过 cookie 和 session 来完成的。
cookie 和 session的作用
在很多网站中,你每次进行一些操作的时候,都需要判断你是否是登录状态,如果没有登陆的话就不能进行一些操作。当用户登录成功之后,服务器会在服务器这里生成一个 sessionId: session 类似这样的键值对的结构,然后存储在服务器本地,并且在响应的时候将这个 sessionId 给携带上,当浏览器接收到这个请求并且拿到这个 session 的时候就会将这个 sessionId 存储在cookie 中。下次向服务器发送请求的时候就会将这个 cookie 和请求数据包一起发送给服务器,当服务器拿到这个 cookie 中的 sessionId 的时候就会根据这个 sessionId 找到对应的 session 从而完成一系列的操作。
给大家举个例子:当我们第一次去某个医院的时候,医院会给根据你提供的身份证为我们开一个就诊卡,这个身份证就相当于我们的用户名和密码,这个就诊卡就相当于 cookie,并且与之对应的,通过这个就诊卡医生可以查询到你的病史、余额等等这些信息,当你去其他的科室看病的时候,就不再需要我们提供身份证了,而是就诊卡;而医院这边呢就会通过你提供的就诊卡,也就是 cookie,来获取到你的个人信息,也就是 session,这样你就能查看到该病人的一些相关信息。
HttpServletRequest和HttpServletResponse中与cookie和session相关的方法
HttpServletRequest 类中的相关方法
方法 | 描述 |
---|---|
HttpSession getSession() | 在服务器中获取会话. 参数如果为 true, 则当不存在会话时新建会话; 参数如果为 false, 则当不存在会话时返回 null |
Cookie[] getCookies() | 返回一个数组, 包含客户端发送该请求的所有的 Cookie 对象. 会自动把Cookie 中的格式解析成键值对 |
HttpServletResponse 类中的相关方法
方法 | 描述 |
---|---|
void addCookie(Cookie cookie) | 把指定的 cookie 添加到响应中 |
Cookie
每个 Cookie 对象就是一个键值对。
方法 | 描述 |
---|---|
String getName() | 该方法返回 cookie 的名称。名称在创建后不能改变。(这个值是 SetCooke 字段设置给浏览器的) |
String getValue() | 该方法获取与 cookie 关联的值 |
void setValue(String newValue) | 该方法设置与 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("/cookie")
public class cookie extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html; charset=utf8");Cookie[] cookies = req.getCookies();StringBuilder sb = new StringBuilder();for (int i = 0; i < cookies.length; i++) {String name = cookies[i].getName();String value = cookies[i].getValue();sb.append(name + ": " + value + "<br>");}resp.getWriter().write(sb.toString());}
}
HttpSession
HttpSession 对象中也包含很多的键值对,我们可以获取或者添加一些键值对。
方法 | 描述 |
---|---|
Object getAttribute(String name) | 该方法返回在该 session 会话中具有指定名称的对象,如果没有指定名称的对象,则返回 null |
void setAttribute(String name, Object value) | 该方法使用指定的名称绑定一个对象到该 session 会话 |
boolean isNew() | 判定当前是否是新创建出的会话 |
attribute 就是属性的意思。
这里我们先用 postman 发送一个 get 请求,让服务器添加一个 cookie,然后再用 postman 发送一个 post 请求查看我们的请求中是否有 cookie。
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
import java.io.IOException;class Message {public String name;public String gender;public Message(String name, String gender) {this.name = name;this.gender = gender;}@Overridepublic String toString() {return "Message{" +"name='" + name + '\'' +", gender='" + gender + '\'' +'}';}
}
@WebServlet("/test")
public class Test extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {Cookie cookie = new Cookie("name","zhangsan");resp.addCookie(cookie);resp.getWriter().write("ok");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.setContentType("text/html; charset=utf8");HttpSession httpSession = req.getSession(true);resp.getWriter().write(String.valueOf(httpSession.isNew()));Message message = new Message("zhangsan", "man");httpSession.setAttribute("cookie1", message);Message m = (Message)httpSession.getAttribute("cookie1");resp.getWriter().write(m.toString());}
}
这是post请求的数据包。
可以看到当我们发送 post 请求的时候,我们抓取到的请求数据包中是存在我们刚才get请求时创建的 cookie 的,不仅如此,cookie 中还有一个 jsession 这个键值对,这就是服务器在服务器本地生成的一对sessionId-session键值对之后返回给浏览器的sessionId,浏览器将这个 sessionId 给存储到了 cookie 中。
使用cookie和session实现一个简单的登录功能
当了解了cookie和session的基本使用,那么我们服务器就可以根据浏览器传来的cookie中的sessionId,得到对应的session对象,然后根据session对象中的相关属性来判断你这个账号的登录状态,如果你当前处于未登录的话,就提示你当前未登录,如果登录了的话,就显示出欢迎词。
使用form表单构造HTTP请求
我们这里的构造HTTP请求的界面很简单就是几个简单的输入框。
<!doctype html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport"content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>登录</title>
</head>
<body><form action="login" method="post"><input type="text" name="username"><input type="text" name="password"><input type="submit" value="登录"></form>
</body>
</html>
判断输入的账户密码是否正确
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 {@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.setCharacterEncoding("utf8");String username = req.getParameter("username");String password = req.getParameter("password");if (!"zhangsan".equals(username) || "123".equals(password)) {resp.setContentType("text/html; charset=utf8");resp.getWriter().write("对不起,您输入的用户名或者密码不正确");return;}HttpSession httpSession = req.getSession(true);httpSession.setAttribute("username", username);httpSession.setAttribute("loginTime", System.currentTimeMillis());resp.sendRedirect("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;@WebServlet("/index")
public class IndexServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {HttpSession httpSession = req.getSession(false);resp.setContentType("text/html; charset=utf8");if (httpSession == null) {resp.getWriter().write("对不起,您当前未登录");return;}String username = (String)httpSession.getAttribute("username");Long loginTime = (Long)httpSession.getAttribute("loginTime");String responBody = "欢迎你" + username + "上次登录时间为" + loginTime;resp.getWriter().write(responBody);}
}
效果展示