PrimeFaces异步任务完成后如何通过消息通知用户?
异步任务完成后JSF用户消息通知方案
因为FacesContext是与当前HTTP请求线程绑定的,后台异步线程没有对应的请求上下文,所以直接在MyCallback#completed里获取会返回null。下面是两种实用的实现方案:
方案一:会话存储+前端轮询
核心思路是把异步完成的消息暂存在用户会话中,前端页面定时通过AJAX请求检查并显示消息,适合所有JSF版本。
1. 后台回调存储消息
@Inject private HttpSession session; public void completed(Result result) { // 从会话获取待通知消息列表,不存在则创建 List<String> pendingNotifications = (List<String>) session.getAttribute("pendingNotifications"); if (pendingNotifications == null) { pendingNotifications = new ArrayList<>(); session.setAttribute("pendingNotifications", pendingNotifications); } pendingNotifications.add("异步任务已完成:" + result.getStatus()); }
2. 前端全局轮询配置
在所有页面共用的模板页面中添加轮询逻辑,比如每隔30秒检查一次:
<h:form id="notificationForm"> <h:outputScript> // 定时发起AJAX请求检查消息 setInterval(() => { jsf.ajax.request('#{request.contextPath}/checkNotifications.xhtml', null, { execute: '@none', render: 'notificationForm:messages', oncomplete: () => {} }); }, 30000); </h:outputScript> <h:messages id="messages" globalOnly="true" styleClass="alert alert-info" /> </h:form>
3. 消息检查接口
创建checkNotifications.xhtml页面及对应的请求作用域Bean,负责读取会话消息并添加到FacesContext:
@Named @RequestScoped public class NotificationChecker { @Inject private HttpSession session; @Inject private FacesContext facesContext; public void check() { List<String> pendingNotifications = (List<String>) session.getAttribute("pendingNotifications"); if (pendingNotifications != null && !pendingNotifications.isEmpty()) { pendingNotifications.forEach(msg -> facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, msg, null)) ); pendingNotifications.clear(); } } }
checkNotifications.xhtml内容:
<f:view> <f:event type="preRenderView" listener="#{notificationChecker.check}" /> </f:view>
方案二:WebSocket实时推送
如果使用JSF 2.3+或容器支持WebSocket(比如Tomcat 8+),可以通过长连接直接推送消息给用户,体验更实时。
1. WebSocket端点配置
@ServerEndpoint(value = "/notification/{userId}", encoders = {NotificationEncoder.class}) public class NotificationEndpoint { private static final Map<String, Session> userSessions = new ConcurrentHashMap<>(); @OnOpen public void onOpen(Session session, @PathParam("userId") String userId) { userSessions.put(userId, session); } @OnClose public void onClose(Session session, @PathParam("userId") String userId) { userSessions.remove(userId); } // 静态方法供异步任务调用推送消息 public static void sendNotification(String userId, String content) { Session session = userSessions.get(userId); if (session != null && session.isOpen()) { try { session.getBasicRemote().sendObject(new NotificationMessage(content)); } catch (IOException | EncodeException e) { // 处理推送异常 } } } }
2. 异步回调触发推送
public void completed(Result result) { String userId = "#{user.id}"; // 从会话或安全上下文获取用户唯一标识 NotificationEndpoint.sendNotification(userId, "异步任务已完成:" + result.getStatus()); }
3. 前端监听WebSocket消息
在全局模板中添加WebSocket连接和消息监听:
<h:outputScript> const userId = '#{user.id}'; const ws = new WebSocket(`ws://${window.location.host}#{request.contextPath}/notification/${userId}`); ws.onmessage = (event) => { const message = JSON.parse(event.data); // 用JSF内置消息组件显示 jsf.addMessage(null, {summary: message.content, severity: 'info'}); // 可选:触发浏览器系统通知 if (Notification.permission === 'granted') { new Notification('任务完成通知', {body: message.content}); } }; // 提前请求浏览器通知权限 if (Notification.permission !== 'denied') { Notification.requestPermission(); } </h:outputScript>
内容的提问来源于stack exchange,提问作者raho
相关产品推荐
相关产品推荐

