java - JSF RequestContext.execute 被评估两次

标签 java jsf primefaces

在我的 PrimeFaces 应用程序中,我正在生成一个文件供下载。生成开始,然后我进入等待循环,直到准备好。现在看来这个循环被启动了两次。代码如下:

JSF:

<p:commandButton id="downloadBtn" value="Download" disabled="#{bean.selectedRow == null}"
    onclick="blockUI()"
    actionListener="#{bean.generateFileAndDownloadWhenReady()}"/>

<script type="text/javascript">
  function downloadFileWhenReady(key) { 
    window.setTimeout(function () {
            checkForDownloadReady([{name:"key",value: key }]);                            
        }, 1000);
  }

  function doTheActualDownload(key) {
    // handle the download
  }
</script>

Java:

public void generateFileAndDownloadWhenReady() {
    key = kickoffFileGeneration();
    RequestContext.getCurrentInstance().execute("downloadFileWhenReady('" + key + "');");
}


public void checkForDownloadReady() {
    String key = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("key");
    STATUS status = FileCache.getFileStatus(key);

    if (status == STATUS.READY) {
        RequestContext.getCurrentInstance().execute("doTheActualDownload(" + key + ");");

    } else if (status == STATUS.FAILED) {
        logger.error("Failure creating file. Wail loop will end.");

    } else if (status == STATUS.OPEN){
        RequestContext.getCurrentInstance().execute("downloadFileWhenReady('" + key + "');");
    }
}

这是一个流程图,希望能够阐明逻辑流程: Flowchart

通过在generateFileAndDownloadWhenReady()中放置断点,我可以看到它只被调用一次,但downloadFileWhenReady()中的断点被调用两次。通过使用长循环延迟,我知道第二个调用不是来自循环。此外,对 kickoffFileGeneration() 的调用非常快——它为实际工作分出一个新线程。那么为什么它会被调用两次,我该如何阻止它呢?

[更新:2017 年 5 月 24 日]
我怀疑,作为一个 JSF 新手,我没有正确使用 actionListeners 和 remoteCommands。 @BalusC 有一些回复和文章,例如 thisthis ,这表明这可能是一个范围界定问题。

要回答为什么我不只是简单地从 commandButton actionListener 返回文件的问题,这是因为生成 .zip 文件可能需要几分钟的时间。因此,我通过分离工作线程来避免阻塞 UI,并且我还使用 <p:blockUI>娱乐用户的元素。

最佳答案

如果其他人遇到这个问题,我通过将 javascript 回调从 bean 移动到 commandButtononcomplete 属性来解决它。现在看起来像这样:

JSF:

<p:commandButton id="downloadBtn" value="Download" disabled="#{bean.selectedRow == null}"
       onclick="blockUI()" oncomplete="downloadFileWhenReady()"
       actionListener="#{bean.generateFile()}"/>

<p:remoteCommand name="checkForDownloadReady" actionListener="#{bean.checkForDownloadReady}"/>

<!-- Hidden button to contain the fileDownload element -->
<p:commandButton id="downloadFile" ajax="false" style="display:none"  onclick="releaseUI();">
    <p:fileDownload value="#{bean.file}" contentDisposition="attachment"/>
</p:commandButton>

<script type="text/javascript">
    function downloadFileWhenReady() {
        window.setTimeout(function () {checkForDownloadReady();}, 1000);
    }        
    function doTheActualDownload() {
        document.getElementById('the_form:downloadFile').click();
    }
    function blockUI() {
        PF('blocker').show();
    }
    function releaseUI() {
        PF('blocker').hide();
    }
</script>

Java:

private String key;

public void generateFile() {
    key = kickoffFileGeneration();  // spawns worker thread, creates file in FileCache
}

public void checkForDownloadReady() {
    STATUS status = FileCache.getFileStatus(key);

    if (status == STATUS.READY) {
        FileCache.setFileStatus(key, STATUS.HANDLED);
        RequestContext.getCurrentInstance().execute("doTheActualDownload()");

    } else if (status == STATUS.FAILED) {
        logger.error("Failure creating file. Wait loop will end.");

    } else if (status == STATUS.OPEN || status == STATUS.NEW){
        RequestContext.getCurrentInstance().execute("downloadFileWhenReady()");
    } 
}

关于java - JSF RequestContext.execute 被评估两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44142555/

相关文章:

jsf 用js渲染组件

Java-如何将数字字符串转换为字母数组

jsf - 组件 ID j_id? :name has already been found in the view

javascript - 如何使用 JSF 在输入文本中授权逗号和点

java - 如何在 JSF 页面中单击行时打开新页面?

java - 动态添加 Primefaces 组件

java - 使用多个订单标签对 xml 进行 XSLT 转换,创建相应的 XML

java - 如何在 Java 中将整数转换为 float ?

java - 如何修复越界错误?

java - Primefaces 4.0 的 XML 命名空间