会话
基本使用
获取 Session
java
@RestController
public class SessionController {
@GetMapping("/set")
public String setSession(HttpServletRequest request) {
HttpSession session = request.getSession(); // 类比 session_start()
session.setAttribute("user_id", 123); // 类比 $_SESSION['user_id'] = 123
return "set";
}
@GetMapping("/get")
public String getSession(HttpServletRequest request) {
HttpSession session = request.getSession(false); // 不存在的 session 返回 null
if (session != null) {
Integer userId = (Integer) session.getAttribute("user_id");
// ⬆ 需要强制类型转换(Java 静态类型)
return "user_id: " + userId;
}
return "no session";
}
@GetMapping("/clear")
public String clearSession(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate(); // 类比 session_destroy()
}
return "cleared";
}
}通过 @SessionAttribute 注入
java
@RestController
public class CartController {
@GetMapping("/cart")
public String cart(@SessionAttribute(name = "cart", required = false) List<Item> cart) {
// 直接从 Session 中取 cart 属性,不存在则返回 null
if (cart == null) {
return "cart is empty";
}
return "cart has " + cart.size() + " items";
}
}⚠️ Session 存储配置
默认 Session 存储在 Tomcat 内存中。
yaml
# application.yml
server:
servlet:
session:
timeout: 30m # 超时时间,类比 SESSION_LIFETIME
cookie:
name: MYAPP_SESSION # 类比 session_name()
http-only: true
secure: false生产环境注意:默认的 Tomcat 内存 Session 有两个大问题:
- 应用重启后 Session 丢失(类比 PHP-FPM 重启后内存 Session 丢失)
- 多实例部署时 Session 不同步(需要粘性会话或外部存储)
解决方案:用 Redis 存储 Session(需添加
spring-session-data-redis依赖):yamlspring: session: store-type: redis # 类比 Laravel SESSION_DRIVER=redis加完依赖和配置后,代码完全不需要改动,Spring Session 自动替换底层存储。
⚠️ 重要差异
1. PHP 中 session_start() 之后可以读写任意数据,Java 的 Session 也类似,但取值时要强转类型
php
// PHP:随便放,随便取
$_SESSION['count'] = 0;
$_SESSION['user'] = User::find(1);
$count = $_SESSION['count'];java
// Java:放时是 Object,取时要强转
session.setAttribute("count", 0);
session.setAttribute("user", userService.findById(1));
int count = (int) session.getAttribute("count"); // 强转
User user = (User) session.getAttribute("user");这是静态类型导致的结果——
getAttribute()的返回类型是Object,编译器不知道具体是什么类型,需要开发者告诉它。
2. 并发安全问题
php
// PHP:每个请求独立进程,不用担心
$_SESSION['count'] = ($_SESSION['count'] ?? 0) + 1;java
// Java:多线程共享 session,存在并发问题
Integer count = (Integer) session.getAttribute("count");
if (count == null) count = 0;
session.setAttribute("count", count + 1); // 并发情况会丢数据如果在 Session 中做累加这类操作,需要加同步锁:
javasynchronized (session.getId().intern()) { Integer count = (Integer) session.getAttribute("count"); session.setAttribute("count", (count == null ? 0 : count) + 1); }更推荐的做法是避免在 Session 中存可变数据,把状态放到数据库或 Redis 中。
3. 没有全局的 session() 辅助函数
PHP 有
session()/Session::get(),Java 没有类似的静态方法。Session 只能通过方法参数注入获取:javapublic String foo(HttpSession session) { ... }或通过
@SessionAttribute注解。
4. Session ID 的获取方式
javaString sessionId = request.getSession().getId(); // 类比 PHP 的 session_id()