Session 与 Cookie
Laravel 的 session 驱动默认存文件,靠 Cookie 里的 session id 关联;Spring Boot 默认把 Session 数据存在内存里,靠
JSESSIONIDCookie 关联。概念几乎一样,重点理解「HttpSession」和两个注解。
Session:HttpSession
java
@RestController
public class SessionController {
@GetMapping("/login")
public String login(HttpSession session) {
session.setAttribute("user", "张三"); // 相当于 Laravel session(['user' => '张三'])
return "已登录";
}
@GetMapping("/me")
public Object me(HttpSession session) {
return session.getAttribute("user"); // 相当于 session('user')
}
@PostMapping("/logout")
public String logout(HttpSession session) {
session.invalidate(); // 清空会话
return "已退出";
}
}| Laravel | Spring Boot |
|---|---|
session(['key' => $value]) | session.setAttribute("key", value) |
session('key') | session.getAttribute("key") |
$request->session()->flush() | session.invalidate() |
session_id() | session.getId() |
用注解拿 Session
不用 HttpSession 参数也能取,用 @SessionAttribute 读、HttpSession 写:
java
@GetMapping("/me")
public Object me(@SessionAttribute(name = "user", required = false) String user) {
return user;
}TIP
@SessionAttribute 读不到且 required=false 时返回 null,不会抛异常。适合「可能未登录」的场景。
Cookie:读写
java
import jakarta.servlet.http.Cookie;
@PostMapping("/set-cookie")
public String setCookie(HttpServletResponse response) {
Cookie cookie = new Cookie("theme", "dark");
cookie.setMaxAge(7 * 24 * 3600); // 7 天,单位秒(Laravel 用分钟)
cookie.setPath("/");
response.addCookie(cookie);
return "已设置";
}
@GetMapping("/get-cookie")
public String getCookie(@CookieValue(name = "theme", defaultValue = "light") String theme) {
return theme;
}TIP
Laravel 的 Cookie 默认是加密的(中间件 EncryptCookies);Spring Boot 的 Cookie 默认不加密。敏感数据要么加密要么只放 session id。
Session 默认存在内存里(重点!)
Spring Boot 默认用「内存会话」,数据在 JVM 堆里:
- 重启应用 → 所有登录态丢失(Laravel 存文件也一样,但文件能持久)
- 多实例部署 → 负载均衡到另一台机器就丢了登录态
解决办法:
| 方案 | 场景 |
|---|---|
spring-boot-starter-data-redis + spring.session.store-type=redis | 多实例、需持久,最常用 |
spring.session.store-type=jdbc | 无 Redis 但有多库 |
| 换成 JWT 无状态方案 | 前后端分离的 API 首选(见 认证) |
用 Redis 存 Session,配置两步:
yaml
spring:
data:
redis:
host: localhost
port: 6379
session:
store-type: redis加上依赖:
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>其他代码一行都不用改,Session 自动落到 Redis。这就是 Spring Boot「抽象 + 自动配置」的威力。
类比 Laravel
Laravel 换 session 驱动改 .env 的 SESSION_DRIVER;Spring Boot 换依赖 + spring.session.store-type。都是「接口 + 多实现」,上层代码无感。
超时时间
yaml
server:
servlet:
session:
timeout: 30m # 30 分钟;默认 30m与 Laravel 的差异清单
| 维度 | Laravel | Spring Boot |
|---|---|---|
| Cookie 名 | laravel_session | JSESSIONID |
| 默认存储 | 文件(storage/framework/sessions) | 内存 |
| Cookie 加密 | 默认加密 | 不加密 |
| 有效期单位 | 分钟 | 秒 |
| 多实例 | 需改 Redis | 需改 Redis(spring.session.store-type) |
实践建议
- API 接口:优先考虑无状态方案(JWT / Token),别依赖 Session —— 前后端分离下 Session 反而麻烦
- 需要服务端会话(传统 MVC 页面):用 Redis 存 Session,避免重启丢登录态
- 别在 Session 里放大对象(整个用户实体),只放用户 ID 或轻量 DTO