You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 16:37:25