
vaadin 6 不支持可靠捕获浏览器/标签页关闭事件,但可通过启用 `preserveonrefresh` 并重写 `ui.refresh()` 检测页面刷新;会话超时机制才是处理用户离线退出的推荐方案。
在 Vaadin 6(配合 Java 8 和 Spring)中,无法跨浏览器(包括 Firefox)100% 可靠地检测标签页关闭、浏览器退出或强制刷新(如 Ctrl+F5)。原因在于:当用户断网、进程被强杀、或浏览器异常终止时,前端 JavaScript 的 beforeunload 或 unload 事件根本不会触发,后端更无从感知。因此,任何依赖客户端主动上报“我即将离开”的设计都存在固有缺陷,不应作为业务关键逻辑(如事务回滚、状态锁定释放)的唯一依据。
✅ 唯一可信赖的机制是服务端会话生命周期管理:
Vaadin 6 基于 HTTP Session,默认超时时间(如 30 分钟)内无请求即自动失效。Spring 配置中可通过 web.xml 或 @Bean SessionRegistry 显式控制:
30
同时,建议在 UI 类中覆写 sessionExpired() 方法,实现会话清理逻辑:
public class MyUI extends UI {
@Override
protected void init(VaadinRequest request) {
// 初始化逻辑
}
@Override
public void refresh() {
// ✅ 此方法仅在用户点击刷新按钮(F5/Ctrl+R)且启用了 preserveOnRefresh 时被调用
// 注意:不适用于 Ctrl+F5 硬刷新、地址栏回车、或关闭标签页
super.refresh();
Notification.show("页面已刷新", Type.TRAY_NOTIFICATION);
// 可在此处重置临时状态、清空缓存视图等
}
@Override
public void sessionExpired() {
// ✅ 安全可靠的“用户已离开”钩子:会话超时或显式销毁时触发
// 推荐在此释放资源、更新用户在线状态、清理临时数据
super.sessionExpired();
getLogger().info("Session expired for user: " + getSession().getAttribute("username"));
}
}⚠️ 重要注意事项:
- refresh() 仅对普通刷新(preserveOnRefresh 默认开启)有效;硬刷新(Ctrl+F5)、导航到新 URL、关闭标签页均不会触发该方法;
- Page.getCurrent().getJavaScript() 注入 beforeunload 脚本在 Firefox 中受限(尤其启用了增强跟踪保护时),且无法区分刷新与关闭,不推荐用于关键业务;
- 若需近似“在线状态”,应结合心跳机制(如定时 UI.push() 或轻量 AJAX 请求)+ 会话超时双重保障;
- Vaadin 6 已停止维护,长期项目建议评估迁移至 Vaadin 24+(基于 Web Components + TypeScript,提供更健壮的客户端生命周期 API)。
总之,拥抱无状态设计:将关键状态持久化到数据库,依赖会话超时兜底,而非试图捕捉不可靠的前端退出事件。










