4

我有一个命令按钮,它将调用一个函数来下载文件(标准的东西,如InputStreamBufferedOutputStream...)下载成功后,在函数结束时,我更改当前对象的一些值并将其保存到数据库中。所有这些都正常工作。现在,当文件下载完成时,页面的内容不会更新。我必须点击刷新才能看到更新的内容。请帮忙。以下是我的代码的基本结构

document:Managed Bean
getDrawings():方法返回绘图列表(实体类)
CheckedOutBy:实体的属性Drawing

<p:dataTable id="drawing_table" value="#{document.drawings}" var="item" >                            
    <p:column>
        <f:facet name="header">
              <h:outputText value="CheckedOutBy"/>
        </f:facet>
        <h:outputText value="#{item.checkedOutBy}"/>
        ...
</p:dataTable>
<p:commandButton ajax="false" action="#{document.Download}" value="Download" />

在我的托管 Bean 中

public void Download(){
    Drawing drawing = getCurrentDrawing();
    //Download drawing
    drawing.setCheckedOutBy("Some Text");
    sBean.merge(drawing);  //Update "Some Text" into CheckedOutBy field
}
4

4 回答 4

4

您基本上想让客户端触发两个请求。一个是检索下载,另一个是刷新新页面。它们不能在单个 HTTP 请求中完成。由于下载需要同步进行,并且无法从客户端连接完成下载,因此没有干净的 JSF/JS/Ajax 方法可以在下载完成时更新组件。

在 PrimeFaces 的帮助下,您最好的 JSF 赌注是<p:poll>

<h:outputText id="checkedOutBy" value="#{item.checkedOutBy}"/>
...
<p:poll id="poll" interval="5" update="checkedOutBy" />

或者<p:push>

<p:push onpublish="javaScriptFunctionWhichUpdatesCheckedOutBy" />  

轮询很容易,但我可以想象它会增加不必要的开销。同步下载开始时,您无法使用标准 JSF/PrimeFaces 组件启动它。但是您可以阻止它,让它对rendered属性进行自检。从技术上讲,推送是最好的解决方案,但更难上手。PrimeFaces 在用户指南的第 6 章中很好地解释了它的使用。

于 2010-08-13T02:03:47.017 回答
2

好吧,我决定接受上面 BalusC 的回答/建议,并决定在此处分享我的代码,以供可能“稍后”在这里停留的人使用。仅供参考,我的环境详细信息如下:

TomEE 1.6.0 SNAPSHOT (Tomcat 7.0.39)、PrimeFaces 3.5 (PrimeFaces Push)、Atmosphere 1.0.13 快照(1.0.12 是最新的稳定版本)

首先,我使用 p:fileDownload 和 p:commandLink。

<p:commandLink value="Download" ajax="false"
               actionListener="#{pf_ordersController.refreshDriverWorksheetsToDownload()}">
    <p:fileDownload value="#{driverWorksheet.file}"/>
</p:commandLink>

由于我有上面的 xhtml,并且由于 p:fileDownload 不允许执行 oncomplete="someJavaScript()",所以我决定使用 PrimeFaces Push 将消息推送到客户端,以触发解锁 UI 所需的 javascript,因为 UI每当我单击 commandLink 下载文件时都会被阻止,并且几个月来,我不知道如何解决这个问题。

由于我已经在使用 PrimeFaces Push,我不得不在客户端调整以下内容:

.js 文件;包含处理从服务器推送到客户端的消息的方法

function handlePushedMessage(msg) {
    /* refer to primefaces.js, growl widget,
     * search for: show, renderMessage, e.detail
     * 
     * sample msg below:
     * 
     * {"data":{"summary":"","detail":"displayLoadingImage(false)","severity":"Info","rendered":false}}
     */
    if (msg.detail.indexOf("displayLoadingImage(false)") != -1) {
        displayLoadingImage(false);
    }
    else {
        msg.severity = 'info';
        growl.show([msg]);
    }
}

索引.xhtml;包含 p:socket 组件(PrimeFaces Push);如果您正在实施 PrimeFaces Push 的 FacesMessage 示例,我推荐以下所有内容

<h:outputScript library="primefaces" name="push/push.js" target="head" />
<p:growl id="pushedNotifications" for="socketForNotifications"
         widgetVar="growl" globalOnly="false"
         life="30000" showDetail="true" showSummary="true" escape="false"/>
<p:socket id="socketForNotifications" onMessage="handlePushedMessage"
          widgetVar="socket"
          channel="/#{pf_usersController.userPushChannelId}" />

几个月(或一年左右)前,我发现有必要将以下内容添加到包装 p:fileDownload 的 commandLink 中,这将刷新服务器上的文件/流,因此您可以多次单击该文件您需要并一次又一次地下载文件,而无需通过键盘上的 F5/刷新键(或移动设备上的类似键)刷新页面

actionListener="#{pf_ordersController.refreshDriverWorksheetsToDownload()}"

每当最终用户单击 commandLink 以下载文件时,都会引用该 bean 方法,因此这是将消息从服​​务器“推送”到客户端、触发客户端上的 javascript 以解锁 UI 的完美场所。

下面是我的应用程序中完成工作的 bean 方法。:)

pf_ordersController.refreshDriverWorksheetsToDownload()

public String refreshDriverWorksheetsToDownload() {
    String returnValue = prepareDriverWorksheetPrompt("download", false);
    usersController.pushNotificationToUser("displayLoadingImage(false)");
    return returnValue;
}

usersController.pushNotificationToUser(); 我不得不添加这个,今晚。

public void pushNotificationToUser(String notification) {
    applicationScopeBean.pushNotificationToUser(notification, user);
}

applicationScopeBean.pushNotificationToUser(); 这已经存在,这个方法没有改变。

public void pushNotificationToUser(String msg, Users userPushingMessage) {
    for (SessionInfo session : sessions) {
        if (userPushingMessage != null &&
            session.getUser().getUserName().equals(userPushingMessage.getUserName()) &&
            session.getUser().getLastLoginDt().equals(userPushingMessage.getLastLoginDt())) {
            PushContext pushContext = PushContextFactory.getDefault().getPushContext();
            pushContext.push("/" + session.getPushChannelId(),
                             new FacesMessage(FacesMessage.SEVERITY_INFO, "", msg));
            break;
        }
    }
}
于 2013-04-09T08:38:43.943 回答
0

您可以使用组件的update属性p:commandButton来重新渲染您打算在下载后刷新的区域,在本例中为您的“drawing_table”。

<p:commandButton update="drawing_table" action="#{document.Download}" value="Download" />
于 2010-08-12T22:13:44.633 回答
-1

正如Balusc回答的那样,我们不能从一个请求中获得两次响应。

要在下载后刷新页面,最好在下载链接 ( p:commandbutton) onclick 标记中使用以下 java 脚本。

例子:

<p:commandButton ajax="false" icon="ui-icon-arrowstop-1-s" onclick="setTimeout('location.reload();', 1000);" action="#{managedBean.downloadMethod}" />

这将在 1 秒后自动刷新页面,同时在刷新之前,您将获得下载文件,根据您的下载响应时间,增加该脚本中的秒数。秒数不应小于下载响应时间。

于 2015-04-09T11:15:45.613 回答