
本文介绍在不依赖第三方消息中间件的前提下,通过 Java EE 标准作用域(如 HttpSession)共享数据,并利用 ZK 的会话级事件队列(Session-scoped Event Queue)实现 Servlet 主动通知 ZK ViewModel 的完整方案。
本文介绍在不依赖第三方消息中间件的前提下,通过 java ee 标准作用域(如 httpsession)共享数据,并利用 zk 的会话级事件 queue 实现 servlet 主动通知 zk viewmodel 的完整方案。
在 ZK 框架的典型分层架构中,Servlet 层(如传统 HttpServlet 或 Spring MVC Controller)与 ZK 的 MVVM 层通常运行在不同执行上下文:Servlet 处于标准 Servlet 容器线程中,而 ZK ViewModel 运行在 ZK Desktop 环境下,受 Execution 生命周期约束。因此,不能直接使用 Desktop-scoped Event Queue(因其强依赖当前 ZK Execution 实例),但可借助 Session-scoped Event Queue 和 HTTP Session 共享机制 实现跨层通信。
✅ 方案一:被动式数据共享(推荐用于初始化/参数传递)
将业务数据存入 HttpSession,ZK ViewModel 在初始化时读取:
// 在 Servlet 中(例如 LoginServlet)
HttpSession session = request.getSession(true);
session.setAttribute("userProfile", new UserProfile("admin", "ROLE_ADMIN"));
response.sendRedirect("main.zul"); // 跳转至 ZK 页面
// 在 ZK ViewModel 中(使用 @NotifyChange 或 @Init)
public class MainViewModel {
private UserProfile userProfile;
@Init
public void init() {
HttpSession session = Sessions.getCurrent().getNativeSession();
this.userProfile = (UserProfile) session.getAttribute("userProfile");
session.removeAttribute("userProfile"); // 可选:消费后清理
}
// getter/setter...
}
⚠️ 注意:确保
Sessions.getCurrent()可用(即当前线程处于 ZK 请求上下文中),且 Session ID 已正确传递(如未禁用 Cookie 或 URL 重写)。
✅ 方案二:主动式事件通知(适用于异步触发 UI 响应)
当 Servlet 需在后台处理完成后“推”通知到前端 ViewModel(如上传完成、批处理结束),使用 Session-scoped Event Queue:
// 在 Servlet 中发送事件(无需 ZK Execution)
HttpSession session = request.getSession();
EventQueue<event> eq = EventQueues.lookup("sessionNotifyQueue", EventQueues.SESSION, true);
eq.publish(new Event("onDataReady", null, userProfile)); // 自定义事件名 + 数据载荷</event>
<!-- main.zul -->
<zk><window apply="org.zkoss.bind.BindComposer" viewmodel="@id('vm') @init('MainViewModel')"><label value="@load(vm.message)"></label>
<!-- 绑定会话级事件队列监听 -->
<attribute name="onDataReady"></attribute></window></zk>
// MainViewModel.java
public class MainViewModel {
private String message = "Waiting...";
@NotifyChange("message")
public void handleDataReady(Object data) {
if (data instanceof UserProfile) {
this.message = "Welcome, " + ((UserProfile)data).getName() + "!";
}
}
}
✅ 关键点:
EventQueues.SESSION作用域使事件队列与HttpSession绑定,ZK 会自动为同一会话中的所有 Desktop 绑定监听器,无需手动管理生命周期。
? 总结与最佳实践
- 优先使用 Session 属性共享静态/一次性数据:简单、可靠、无耦合;
- 需实时响应时选用 Session-scoped Event Queue:避免轮询,支持解耦式事件驱动;
-
禁用 Desktop-scoped Queue:Servlet 中无法获取
Desktop或Execution,强行调用将抛出IllegalStateException; -
注意线程安全:
HttpSession本身是线程安全的,但自定义对象(如UserProfile)若被多线程修改,需自行同步; - 清理资源:及时移除已消费的 session 属性,防止内存泄漏。
通过上述组合策略,即可在零外部依赖前提下,构建健壮、可维护的 Servlet ↔ ZK MVVM 协同通信链路。










