【问题标题】:How to stack messages with PrimeFaces messages component?如何使用 PrimeFaces 消息组件堆叠消息?
【发布时间】:2013-11-20 03:57:49
【问题描述】:

我有一个关于 p:messages 组件的问题。

首先,这是我的配置:

  • PrimeFaces:4.0.3(精英版)
  • JSF:MyFaces 2.0.2
  • 服务器:WebSphere 8.5.0.2

然后,我的代码:

test.xhtml

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:f="http://java.sun.com/jsf/core"
   xmlns:h="http://java.sun.com/jsf/html"
   xmlns:ui="http://java.sun.com/jsf/facelets"
   xmlns:p="http://primefaces.org/ui"
   xmlns:fn="http://java.sun.com/jsp/jstl/functions">

<h:head>
   <f:facet name="first">
       <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
   </f:facet>
   <meta http-equiv="cache-control" content="no-store,no-cache" />
   <meta http-equiv="pragma" content="no-cache" />
   <meta http-equiv="expires" content="0" />
</h:head>

<h:body>

   <div id="content">     
       <h:form id="form1"> 
           <p:tooltip/>
           <p:messages id="messages" showDetail="true" />
           <p:remoteCommand async="true" autoRun="true" process="@this" partialSubmit="true" action="#{testBean.checkA}" />
           <p:remoteCommand async="true" autoRun="true" process="@this" partialSubmit="true" action="#{testBean.checkB}" />
       </h:form>  
   </div>

</h:body>

</html>

Test.java

import java.io.Serializable;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;

import org.primefaces.context.RequestContext;

@ManagedBean(name="testBean")
@ViewScoped
public class Test implements Serializable {
    private static final long serialVersionUID = -1L;

    public void checkA() {
       try {
         Thread.sleep(2000);
       } catch (InterruptedException e) {
         e.printStackTrace();
       }
       FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO,"Message 1", null));
       RequestContext.getCurrentInstance().update("form1:messages");
    }  

    public void checkB() {
        FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_WARN,"Message 2", null));
        RequestContext.getCurrentInstance().update("form1:messages");
   } 
}

这段代码的作用非常简单。当页面加载时,会进行两次 AJAX 调用(checkA 和 checkB)。我在 checkA 中放了一个 Thread.sleep(2000) 用于测试目的,因为我希望它在 checkB 之后完成。方法完成后,它会向 UI 发回一条消息。

当我加载页面时,我看到了两个 AJAX 调用。 CheckB 将首先完成,所以我会在我的页面上看到“消息 2”。但是一旦 checkA 完成,该消息就会被“消息 1”替换。我想做的是追加“消息 1”到“消息 2”,这样用户就会在屏幕上看到两条消息。有没有办法做到这一点,还是组件的限制?

其次,正如您在我的代码中看到的那样,我必须调用 RequestContext.getCurrentInstance().update("form1:messages"); 才能看到我的 p:messages 正在更新。如果我删除这行代码并将autoUpdate="true"添加到组件中,它不起作用...

要考虑的一件事,很遗憾,我无法更改服务器的配置,因为我不管理它,而且上面已经有几十个其他应用程序。

提前感谢您的帮助!

【问题讨论】:

  • 问题写得很好,遵循SSCCE 标准。 +1

标签: ajax jsf primefaces messages


【解决方案1】:

您在这里遇到的问题是 FacesMessages 是Request Scoped。当您执行两个 ajax 请求时,当您到达第二个请求的末尾时,第一条消息此时不可用。

您正在使用@ViewScoped bean,它在您离开视图本身之前一直保持活动状态,因此解决方法应该是有一种堆栈/队列来存储要显示的消息。当您认为最后一个请求已完成时,只需将所有消息添加到 FacesContext 并清除堆栈即可。

其他选择是以相同的方法执行所有操作,然后显示您想要的消息。由于执行一个请求而不是两个请求,您会减少网络流量,但如果您想render specific parts of the page before other ones,您的选择似乎很有趣。

关于您的更新问题,请记住您可以直接在页面中指定要更新的表单部分。尝试将update="messages" 添加到您的p:remoteCommand 标签中。关于autoUpdate 不起作用,可能您的remoteCommandpartialSubmit 属性可能会给您带来问题。从Primefaces docs查看该属性的定义:

partialSubmit: 启用属于部分的值的序列化 仅处理过的组件。

【讨论】:

  • 在我的真实页面中,我进行了 3 个 AJAX 调用,因为我需要调用 3 个 Web 服务并且我不希望用户等待它们完成。这 3 个 WS 只返回一个状态(图标),因此我在获得一个 WS 的结果后立即更新页面上的这 3 个图标中的每一个。这就是为什么我更喜欢保留所有的 AJAX 调用而不是只保留一个。你排队的想法很有趣。
  • 在 bean 中保留一个队列允许您选择您想要在每个时刻显示的内容。您可以将它们全部显示在最后一个请求中,也可以在每个请求完成时显示它们中的每一个,自行控制缓冲区。
  • 我尝试了拥有多个消息组件的选项,但它不适用于我的布局。我在我的应用程序中使用模板进行布局,并希望我的所有消息只显示在一个消息组件中。
  • 拥有多个消息组件并不能解决您的问题。您必须在模板页面中添加p:messages 标记,并使用autoUpdate=true。还可以尝试从 remoteCommand 标签中删除 partialSubmitasync 属性。
  • 我已经设法创建了一个简单的 Vector,用作我的消息的缓冲区,它工作得很好。感谢您的帮助!
【解决方案2】:

您可以使用多个p:message 组件:

<p:message id="message1"
    for="message1ValidatorCall" />
<h:inputHidden id="message1ValidatorCall" value="message1ValidatorCall">
    <f:validator validatorId="myValidator" />
</h:inputHidden>

<p:message id="message2"
    for="message2ValidatorCall" />
<h:inputHidden id="message2ValidatorCall" value="message2ValidatorCall">
    <f:validator validatorId="mySecondValidator" />
</h:inputHidden>

如果你想检查或验证某事,你应该考虑faces validators

@FacesValidator("myValidator")
public class MyValidator implements Validator {
    @Override
    public void validate(FacesContext facesContext, UIComponent uiComponent, Object o) throws ValidatorException {
    //validator logic
    }
}

【讨论】:

  • 是的,我正在考虑在页面上有多个消息组件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多