一、Cookie

1. Cookie 的概述

Cookie 是服务器发送给客户端(浏览器)的一小段文本数据,客户端会将其保存起来,之后每次向该服务器发送请求时,都会携带该 Cookie。它的核心作用是在客户端存储少量状态数据(如用户偏好、登录状态标识)。

典型应用场景:

  • 记录用户上次访问时间。
  • 实现 “记住密码”“自动登录” 功能。
  • 跟踪用户行为(如电商网站的购物车)。

2. Cookie 的相关方法

在 Java Web 中,通过javax.servlet.http.Cookie类操作 Cookie,核心方法如下:

方法 说明
Cookie(String name, String value) 构造方法,创建 Cookie 对象(name 不能含空格、特殊字符)
void setMaxAge(int expiry) 设置 Cookie 的有效时间(单位:秒)
int getMaxAge() 获取 Cookie 的有效时间
void setPath(String uri) 设置 Cookie 的有效路径
String getPath() 获取 Cookie 的有效路径
void setValue(String newValue) 设置 Cookie 的值
String getValue() 获取 Cookie 的值
void setDomain(String pattern) 设置 Cookie 的有效域名(极少使用)

3. Cookie 的案例(记录上一次的访问时间)

需求:用户访问页面时,显示 “您上次访问的时间是:xxx”,并更新本次访问时间到 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;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

@WebServlet("/lastAccessTime")
public class LastAccessTimeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out = resp.getWriter();
        
        // 1. 获取所有Cookie,查找记录上次访问时间的Cookie
        Cookie[] cookies = req.getCookies();
        String lastTime = "您是第一次访问";
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("lastAccessTime".equals(cookie.getName())) {
                    lastTime = "您上次访问的时间是:" + cookie.getValue();
                    // 更新Cookie的值为本次访问时间
                    cookie.setValue(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                    cookie.setMaxAge(24 * 60 * 60); // 有效时间1天
                    resp.addCookie(cookie);
                    break;
                }
            }
        }
        
        // 2. 如果是第一次访问,创建Cookie并设置
        if (cookies == null || lastTime.equals("您是第一次访问")) {
            Cookie cookie = new Cookie("lastAccessTime", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
            cookie.setMaxAge(24 * 60 * 60);
            resp.addCookie(cookie);
        }
        
        out.write(lastTime);
    }
}

4. Cookie 的有效时间和有效路径

  • 有效时间:通过setMaxAge(int expiry)设置,单位为秒。

    • expiry > 0:Cookie 在客户端硬盘中保存,过期时间到后自动删除。
    • expiry = 0:立即删除客户端的 Cookie。
    • expiry < 0:Cookie 仅保存在浏览器内存中,关闭浏览器即删除(默认值)。
  • 有效路径:通过setPath(String uri)设置,只有请求路径匹配该路径的请求才会携带该 Cookie。示例:cookie.setPath("/user"); 表示只有访问/user开头的路径(如/user/login/user/info)时,才会携带该 Cookie。

5. Cookie 的编码问题

由于 Cookie 的namevalue不支持中文,若需存储中文,需先编码(如URLEncoder.encode),获取时再解码(如URLDecoder.decode)。

示例:

// 存储中文Cookie
String chineseValue = "中文内容";
String encodedValue = URLEncoder.encode(chineseValue, "UTF-8");
Cookie cookie = new Cookie("chineseCookie", encodedValue);
resp.addCookie(cookie);

// 获取并解码中文Cookie
Cookie[] cookies = req.getCookies();
if (cookies != null) {
    for (Cookie c : cookies) {
        if ("chineseCookie".equals(c.getName())) {
            String decodedValue = URLDecoder.decode(c.getValue(), "UTF-8");
            System.out.println("解码后的值:" + decodedValue);
        }
    }
}

二、Session

1. Session 的概述

Session 是服务器端的会话对象,用于存储用户的 “会话级” 数据(如登录状态、购物车信息)。每个用户(会话)对应一个唯一的 Session,服务器通过 **Cookie(JSESSIONID)** 识别不同用户的 Session。

Session 与 Cookie 的区别:

特性 Cookie Session
存储位置 客户端浏览器 服务器内存(或持久化存储)
存储容量 小(一般 4KB 以内) 大(取决于服务器资源)
安全性 低(数据在客户端,易被篡改) 高(数据在服务器,客户端仅存 ID)
生命周期 可设置较长时间 默认 30 分钟(无操作则过期)

2. Session 的代码实现

示例:用 Session 存储用户登录状态。

// 登录Servlet
@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");
        
        // 假设此处是登录校验逻辑(略)
        if ("admin".equals(username) && "123456".equals(password)) {
            // 登录成功,将用户信息存入Session
            HttpSession session = req.getSession();
            session.setAttribute("user", username);
            resp.sendRedirect(req.getContextPath() + "/home");
        } else {
            resp.sendRedirect(req.getContextPath() + "/login.jsp");
        }
    }
}

// 首页Servlet
@WebServlet("/home")
public class HomeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=UTF-8");
        PrintWriter out = resp.getWriter();
        
        HttpSession session = req.getSession();
        String user = (String) session.getAttribute("user");
        if (user != null) {
            out.write("欢迎回来," + user + "!");
        } else {
            out.write("请先登录!");
            resp.sendRedirect(req.getContextPath() + "/login.jsp");
        }
    }
}

3. Session 的销毁和相关 API

  • Session 的销毁方式

    1. 服务器正常关闭(会序列化 Session 到磁盘,重启后恢复)。
    2. Session 超时(默认 30 分钟无操作,可在web.xml中配置<session-config><session-timeout>15</session-timeout></session-config>修改超时时间)。
    3. 手动调用session.invalidate()方法。
  • Session 相关 API

    HttpSession session = req.getSession(); // 获取Session,不存在则创建
    HttpSession session = req.getSession(false); // 获取Session,不存在则返回null
    session.setAttribute("key", "value"); // 存储属性
    Object value = session.getAttribute("key"); // 获取属性
    session.removeAttribute("key"); // 删除属性
    session.invalidate(); // 销毁Session
    String id = session.getId(); // 获取Session的唯一标识(JSESSIONID)
    

4. 综合案例(Session 和 Cookie 实现自动登录功能)

需求:用户登录时勾选 “自动登录”,则下次访问时无需手动登录,直接进入首页。

(1)登录 Servlet(处理自动登录逻辑)

@WebServlet("/autoLogin")
public class AutoLoginServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String autoLogin = req.getParameter("autoLogin");
        
        // 登录校验(略)
        if ("admin".equals(username) && "123456".equals(password)) {
            HttpSession session = req.getSession();
            session.setAttribute("user", username);
            
            // 如果勾选了自动登录,创建持久化Cookie
            if ("on".equals(autoLogin)) {
                Cookie cookie = new Cookie("autoLogin", username + "|" + password);
                cookie.setMaxAge(7 * 24 * 60 * 60); // 有效时间7天
                cookie.setPath("/"); // 所有路径都携带该Cookie
                resp.addCookie(cookie);
            }
            
            resp.sendRedirect(req.getContextPath() + "/home");
        } else {
            resp.sendRedirect(req.getContextPath() + "/login.jsp");
        }
    }
}

(2)过滤器(拦截请求,自动登录校验)

@WebFilter("/*")
public class AutoLoginFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        HttpSession session = req.getSession();
        
        // 如果Session中已有用户,直接放行
        if (session.getAttribute("user") != null) {
            chain.doFilter(request, response);
            return;
        }
        
        // 否则,检查Cookie中是否有自动登录信息
        Cookie[] cookies = req.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if ("autoLogin".equals(cookie.getName())) {
                    String[] info = cookie.getValue().split("\\|");
                    String username = info[0];
                    String password = info[1];
                    
                    // 模拟登录校验(实际应查数据库)
                    if ("admin".equals(username) && "123456".equals(password)) {
                        session.setAttribute("user", username);
                        break;
                    }
                }
            }
        }
        
        chain.doFilter(request, response);
    }
}

(3)登录页面(login.jsp)

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>自动登录演示</title>
</head>
<body>
    <form action="${pageContext.request.contextPath}/autoLogin" method="post">
        用户名:<input type="text" name="username"><br>
        密码:<input type="password" name="password"><br>
        自动登录:<input type="checkbox" name="autoLogin" value="on"><br>
        <input type="submit" value="登录">
    </form>
</body>
</html>

 

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐