【问题标题】:Execute JavaScript on client side within an non ajax call在非 ajax 调用中在客户端执行 JavaScript
【发布时间】:2015-03-11 16:37:50
【问题描述】:

在我的应用程序中,用户可以按下按钮来创建和下载文件。该过程需要一些时间,因此我想在此过程中阻止 UI,直到出现下载窗口。

我正在处理响应的操作方法基本上是这样的:

public void download() {
    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();
    // set content disposition etc.    
    XSSFWorkbook wb = getWorkbook();
    wb.write(externalContext.getResponseOutputStream());            
    facesContext.responseComplete();
}

在我的 JSF 视图中,我正在触发一个 blockUI 组件来禁用按钮,如下所示:

<p:commandButton value="Doanload" id="b" 
                 action="#{bean.doanload()}"
                 ajax="false" 
                 onclick="PF('crBui').show();"  />
<p:blockUI block=":trGrid" widgetVar="crBui" trigger="b">
     <p:graphicImage value="/images/loading.gif" alt="loading..."/>
</p:blockUI>

我尝试使用 PrimeFaces RequestContext 来执行一些 JavaScript 来隐藏 blockUI 组件,但这不起作用。 JavaScript 未执行:

    public void download() {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        ExternalContext externalContext = facesContext.getExternalContext();
        // set content disposition etc.    
        XSSFWorkbook wb = getWorkbook();
        wb.write(externalContext.getResponseOutputStream());    
        RequestContext.getCurrentInstance()
                      .execute("PF('crBui').hide();");        
        facesContext.responseComplete();
    }

如果我使用 ajax 调用而不是非 ajax 调用,则文件下载将不再起作用。

任何建议我如何归档我的功能?

【问题讨论】:

    标签: javascript ajax jsf-2 primefaces callback


    【解决方案1】:

    我最终使用了 PrimeFaces 'PrimeFaces.monitorDownload()'

    在我看来:

    <p:commandButton value="Doanload" id="b" 
                 action="#{bean.doanload()}"
                 ajax="false" 
                 onclick="PrimeFaces.monitorDownload(start, stop);"  />
    
    <script type="text/javascript">
        function start() {
            PF('crBui').show();
        }
        function stop() {
            PF('crBui').hide();
        }
    </script>
    

    让 DownloadMonitor 工作的主要技巧是在响应中简单地设置一个 Cookie:

    externalContext.addResponseCookie(
        org.primefaces.util.Constants.DOWNLOAD_COOKIE,
        "true",
        Collections.<String, Object>emptyMap()
    );
    

    这样,UI 元素会被阻止,直到出现 FileDownload 窗口,这正是我最终想要实现的目标。

    【讨论】:

    • 您的代码帮助我使用commandbuttonajax="false",但为什么我需要使用org.primefaces.util.Constants.DOWNLOAD_COOKIE
    【解决方案2】:

    您应该使用p:fileDownload 而不是尝试创建一些自制解决方案。展示中的修改示例:

    xhtml:

    <script type="text/javascript">
    function start() {
        PF('crBui').show();
    }
    
    function stop() {
        PF('crBui').hide();
    }
    </script>
    

    豆:

    import java.io.InputStream;
    import javax.faces.bean.ManagedBean;
    import javax.faces.context.FacesContext;
    import javax.servlet.ServletContext;
    
    import org.primefaces.model.DefaultStreamedContent;
    import org.primefaces.model.StreamedContent;
    
    @ManagedBean
    public class FileDownloadView {
    
        private StreamedContent file;
    
        public FileDownloadView() {       
            InputStream stream = <create your stream>
            file = new DefaultStreamedContent(stream, "<your mime-type>", "<your filename>");
        }
    
        public StreamedContent getFile() {
            return file;
        }
    }
    

    【讨论】:

    • 感谢您的回答,如果我只想从服务器下载文件,“p:fileDownload”组件确实是件好事。但就我而言,Apache POI 库有效这样我直接写入 OutputStream 但 StreamedContent 只需要一个 InputStream。我查看了 PrimeFaces 源代码,发现它的作用与我在代码中所做的几乎相同。所以在这里使用 PF 组件,我最终会将我的文件写入 ByteArrayOutputStream 并随后将其写入 ByteInputStream 只是一个字节一个字节......只是为了让 PF 组件
    • 再次将其逐字节写入 OutputSteam。对我来说听起来很难看。但现在我了解了 DownloadMonitor 的工作原理,现在我可以在不使用 p:fileDownload 的情况下使用它。所以再次感谢您指出 p:download 的可能性,这让我朝着正确的方向前进:)
    猜你喜欢
    • 2010-12-20
    • 1970-01-01
    • 1970-01-01
    • 2013-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多