如何在下载后刷新页面

时间:2010-08-12 20:47:58

标签: java jsf refresh primefaces

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

document:托管Bean
getDrawings():方法返回一个Drawing(实体类)列表 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 个答案:

答案 0 :(得分: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章中很好地解释了它的用法。

答案 1 :(得分:2)

好吧,我决定采用上面的BalusC的回答/建议,并决定在这里分享我的代码给那些可能会在这里停留的人,“以后”。仅供参考,我的环境详情如下:

TomEE 1.6.0 SNAPSHOT(Tomcat 7.0.39),PrimeFaces 3.5(PrimeFaces推送),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 ,因为只要我点击commandLink下载文件就阻止了UI,而且好几个月,我都不知道如何解决这个问题。

由于我已经在使用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]);
    }
}

的index.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;
        }
    }
}

答案 2 :(得分:0)

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

<p:commandButton update="drawing_table" action="#{document.Download}" value="Download" />

答案 3 :(得分:-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秒后自动刷新页面,同时即在刷新之前,您将获得下载文件,根据您的下载响应时间,增加该脚本中的秒数。 秒数不应低于下载响应时间。