杰瑞科技汇

Java session如何正确赋值?

什么是 Session?

Session(会话)是一种在服务器端维护用户状态的机制,当用户访问一个网站时,服务器会为该用户创建一个唯一的 Session ID,并将其通过 Cookie 发送到客户端浏览器,之后,用户每次发送请求时,浏览器都会带上这个 Session ID,服务器通过这个 ID 就能找到对应的 Session 对象,从而获取或存储与该用户相关的数据。

一个简单的比喻:

  • Session ID:就像一张餐厅的桌号牌(A3 桌)。
  • Session 对象:就是那张 A3 桌,服务员(服务器)可以在桌上放菜单(数据)、水杯(数据)等。
  • 用户:就是坐在 A3 桌的顾客。
  • Cookie:就是顾客离开时带走的桌号牌,下次来时出示,服务员就知道他该回 A3 桌了。

如何给 Session 赋值?(代码示例)

在 Java Web 开发中,最常用的技术栈是 ServletSpring MVC,下面分别介绍在这两种框架中如何给 Session 赋值。

在原生 Servlet 中赋值

在 Servlet 中,我们可以通过 HttpServletRequest 对象来获取和操作 Session。

步骤:

  1. 通过 request.getSession() 方法获取 HttpSession 对象。这是最关键的一步
    • 如果该用户的 Session 已经存在,则返回现有的 Session 对象。
    • 如果该用户的 Session 不存在,则会创建一个新的 Session 对象。
  2. 获取到 HttpSession 对象后,调用其 setAttribute(String name, Object value) 方法来存入数据。

示例代码:

假设有一个登录的 Servlet,用户登录成功后,我们将用户信息存入 Session。

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 request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 获取用户提交的登录信息
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        // 2. 模拟业务逻辑验证(实际项目中这里会查询数据库)
        if ("admin".equals(username) && "123456".equals(password)) {
            // 登录成功,将用户信息存入 Session
            // 关键步骤:获取 Session 对象
            HttpSession session = request.getSession();
            // 3. 给 Session 赋值(存入数据)
            // 参数1: 属性名 (String)
            // 参数2: 属性值 (Object)
            session.setAttribute("user", username); // 存入用户名
            session.setAttribute("loginTime", System.currentTimeMillis()); // 存入登录时间戳
            // 可以存入一个自定义的 User 对象
            // User user = new User(username, "admin@example.com");
            // session.setAttribute("currentUser", user);
            System.out.println("用户 " + username + " 登录成功,数据已存入 Session。");
            // 重定向到主页
            response.sendRedirect("welcome.jsp");
        } else {
            // 登录失败,返回登录页面
            response.sendRedirect("login.jsp?error=1");
        }
    }
}

在 Spring MVC 中赋值

Spring MVC 提供了更简洁、更强大的方式来操作 Session。

通过 HttpSession 参数注入

在 Controller 方法中,可以直接将 HttpSession 作为参数传入,Spring 会自动为你注入。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpSession;
@Controller
public class LoginController {
    @PostMapping("/login")
    public String login(@RequestParam String username,
                        @RequestParam String password,
                        HttpSession session) {
        // 模拟登录验证
        if ("admin".equals(username) && "123456".equals(password)) {
            // 直接使用 session 对象进行赋值,和 Servlet 中一样
            session.setAttribute("user", username);
            session.setAttribute("loginTime", System.currentTimeMillis());
            System.out.println("用户 " + username + " 在 Spring MVC 中登录成功。");
            // 登录成功后,跳转到主页视图
            return "redirect:/welcome"; // 使用 "redirect:" 前缀进行重定向
        } else {
            // 登录失败,返回登录页面
            return "login"; // 返回逻辑视图名,对应 login.jsp
        }
    }
}

使用 @SessionAttributes 注解(推荐用于复杂场景)

这个注解可以将 Model 中的数据自动同步到 Session 中,它适用于需要将多个数据存入 Session,并且希望这些数据在多个请求之间保持的场景。

工作原理:

  1. 在 Controller 类上使用 @SessionAttributes 注解,指定哪些属性名需要存入 Session。
  2. 在 Controller 方法中,向 ModelModelMap 添加数据。
  3. 当方法执行完毕后,Spring 会检查 Model 中的数据,如果其属性名在 @SessionAttributes 的列表中,就会自动将其存入 Session。

示例代码:

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
// 告诉 Spring,将名为 "user" 和 "cart" 的属性存入 Session
@SessionAttributes({"user", "cart"})
@Controller
public class ShoppingCartController {
    // 添加商品到购物车
    @PostMapping("/addToCart")
    public String addToCart(@RequestParam String item, Model model) {
        // 1. 从 Session 中获取购物车(如果不存在,会创建一个空的 Map)
        // 注意:这里直接从 Model 中获取,Spring 会负责从 Session 中同步
        Map<String, Integer> cart = (Map<String, Integer>) model.getAttribute("cart");
        if (cart == null) {
            cart = new HashMap<>();
        }
        // 2. 更新购物车数据
        cart.put(item, cart.getOrDefault(item, 0) + 1);
        // 3. 将更新后的购物车放回 Model
        // Spring 会检测到 "cart" 在 @SessionAttributes 列表中,自动将其存入 Session
        model.addAttribute("cart", cart);
        // 模拟一个登录用户并存入 Session
        model.addAttribute("user", "JohnDoe");
        return "cart"; // 返回购物车页面
    }
    // 查看购物车
    @GetMapping("/cart")
    public String viewCart(Model model) {
        // 可以直接从 Model 中获取 "cart" 和 "user"
        // 因为它们已经被 @SessionAttributes 自动存入 Session 了
        Map<String, Integer> cart = (Map<String, Integer>) model.getAttribute("cart");
        String user = (String) model.getAttribute("user");
        System.out.println("当前用户: " + user);
        System.out.println("购物车内容: " + cart);
        return "cart";
    }
}

从 Session 中获取值

赋值之后,自然也需要知道如何获取。

Servlet 中获取

HttpSession session = request.getSession();
String username = (String) session.getAttribute("user");
Long loginTime = (Long) session.getAttribute("loginTime");
if (username != null) {
    System.out.println("从 Session 中获取到用户: " + username);
}

Spring MVC 中获取

@GetMapping("/welcome")
public String welcome(HttpSession session, Model model) {
    // 方法1:直接通过 HttpSession 获取
    String username1 = (String) session.getAttribute("user");
    // 方法2:通过 Model 获取(当使用 @SessionAttributes 时更方便)
    // Spring 会自动将 Session 中的数据注入到 Model 中
    String username2 = (String) model.getAttribute("user");
    return "welcome";
}

最佳实践和注意事项

  1. 只存必要的数据:Session 存储在服务器内存中,会消耗服务器资源,不要将大对象(如整个 List、文件流等)存入 Session。
  2. 使用 POJO (Plain Old Java Object):推荐将相关的数据封装在一个 Java 对象(如 User, Cart)中,然后将这个对象存入 Session,而不是存散乱的多个属性,这样更易于管理和维护。
  3. 处理 Session 过期:Session 有一个生命周期(由 web.xml 中的 session-timeout 配置,默认 30 分钟),在获取 Session 数据时,一定要进行 非空判断,避免因 Session 过期导致的 NullPointerException
  4. 及时清理:当用户退出登录时,应该主动清除 Session 中的数据,以释放资源并保护用户隐私。
    // 在登出时清除 Session
    session.invalidate(); // 销毁整个 Session
    // 或者
    session.removeAttribute("user"); // 只移除特定属性
  5. 线程安全:一个 HttpSession 对象在同一个用户的多个请求之间是共享的,Session 中存储的对象会被多个线程并发修改(在异步处理中),你需要确保该对象是线程安全的,或者对修改操作进行同步。
  6. 安全性:Session ID 通过 Cookie 传输,确保你的应用配置了 HttpOnlySecure 属性,以防止 Session ID 被窃取(如跨站脚本攻击 XSS)。
操作 Servlet Spring MVC (推荐)
获取 Session request.getSession() 在 Controller 方法中直接添加 HttpSession session 参数
赋值 session.setAttribute("key", value) session.setAttribute("key", value) 或使用 @SessionAttributes + model.addAttribute()
取值 session.getAttribute("key") session.getAttribute("key") 或直接从 Model 中获取(当使用 @SessionAttributes 时)
清除 session.invalidate()session.removeAttribute() 同左

对于现代 Java Web 开发,Spring MVC 是主流选择,在简单的单次请求场景下,直接注入 HttpSession 即可,在需要跨多个 Controller 方法共享数据时,使用 @SessionAttributes 注解是更优雅、更结构化的方式。

分享:
扫描分享到社交APP
上一篇
下一篇