【问题标题】:How to refresh a page after download下载后如何刷新页面
【发布时间】:2011-03-29 03:56:36
【问题描述】:

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

document:托管 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
}

【问题讨论】:

    标签: java jsf refresh primefaces


    【解决方案1】:

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

    在 PrimeFaces 的帮助下,您最好的 JSF 赌注是 &lt;p:poll&gt;

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

    &lt;p:push&gt;

    <p:push onpublish="javaScriptFunctionWhichUpdatesCheckedOutBy" />  
    

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

    【讨论】:

    • 感谢您的意见。我现在正在读这一章。如果我有更多问题,我会回复你。感谢您编辑我的帖子,从h:commandButton 切换到p:commandButton。我原来是p:commandButton,但我担心很多人看不懂,因为primefaces标签只有38等级。
    • 这不是评级,这只是迄今为止标记问题的数量。只要你在上面标记jsf,它就会被合适的人发现;)
    • 我还是有点模糊。我的p:commmandButton 也变成了这个&lt;p:commandButton ajax="false" action="#{document.Download}" actionListener=”#{document.update}” value="Download" /&gt;。我的实体 Drawing 有一个布尔值 checked 属性,它基本上告诉我用户选择了哪个 drawing。所以它可能是多张图纸选择下载。因此,我在服务器上的update 方法,我对push 下的浏览器没有一个清晰的概念。你觉得我应该把checkedOutBy的一整栏都放下,还是想办法找出哪一个需要更新,然后推送一下
    • 发送一个分隔/格式化的字符串,您可以在 JS 代码中进一步处理。 JSON 格式可能非常适合这里。
    • 目前,据 primefaces 论坛的人说,我认为 Glassfish 不支持推送。我想民意调查是我唯一的选择。你介意详细说明你之前说的话吗:You cannot start it using standard JSF/PrimeFaces components when the synchronous download starts. But you can stop it to let it do a self-check on the rendered attribute.
    【解决方案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 ,因为每当我点击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]);
        }
    }
    

    索引.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;
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 这是因为ajax="false"(这是获取文件下载所必需的)。
      【解决方案4】:

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

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

      示例:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-27
        • 2014-09-06
        • 1970-01-01
        • 2018-09-30
        • 2017-10-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多