Strut2 execAndWait拦截器+ JSON结果类型+ Dojo dijit.ProgressBar = AJAX进度条

时间:2010-11-01 21:18:40

标签: ajax json dojo struts2 progress-bar

我正在使用Dojo ProgressBar使用execAndWait拦截器在Struts2中显示一个长时间运行的进程。 execAndWait拦截器将操作放在每个返回等待结果的调用的值堆栈上。但是,当结果类型为JSON时,操作仅具有操作的默认值。

这是我的struts动作配置
(我试图通过万能卡结果名称,但那不起作用)
注意:我必须将我的JSON包装在textarea中,因为Dojo的iframe.send希望将它包装在textarea中。


<action name="upload" class="ProcessFileAction" method="upload">
  <interceptor-ref name="agfStack" />
  <interceptor-ref name="execAndWait">
    <param name="delay">1000</param>
    <param name="delaySleepInterval">500</param>
  </interceptor-ref>
  <result name="wait" type="json">
    <param name="noCache">true</param>
    <param name="contentType">text/html</param>
    <param name="wrapPrefix"><![CDATA[<html><body><textarea>]]></param>
    <param name="wrapSuffix"><![CDATA[</textarea></body></html>]]></param>
    <param name="includeProperties">percentComplete,processMessage,running</param>
  </result>
  <result name="success" type="json">
    <param name="noCache">true</param>
    <param name="contentType">text/html</param>
    <param name="wrapPrefix"><![CDATA[<html><body><textarea>]]></param>
    <param name="wrapSuffix"><![CDATA[</textarea></body></html>]]></param>
    <param name="includeProperties">percentComplete,processMessage,running</param>
  </result>
  <result name="error" type="json">
    <param name="noCache">true</param>
    <param name="contentType">text/html</param>
    <param name="wrapPrefix"><![CDATA[<html><body><textarea>]]></param>
    <param name="wrapSuffix"><![CDATA[</textarea></body></html>]]></param>
    <param name="includeProperties">percentComplete,processMessage,running</param>
  </result>
</action>

这是我的JSP
注意:我必须使用iFrame.send操作,因为我正在上传文件。因为我的struts结果对于每次连续调用的初始等待返回都是相同的,所以我也必须使用iframe.send进行AJAX调用(而不是xhrGet)。这是因为iframe.send期望JSON包装在文本区域中,而xhrGet则不包含。


<%@taglib uri="http://www.springframework.org/security/tags" prefix="security"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%>
<script type="text/javascript">
dojo.require("dojo.io.iframe");
dojo.require("dijit.ProgressBar");
dojo.require('dojox.timing');
var t = new dojox.timing.Timer(<tiles:getAsString name="refreshTime" />);
t.onTick = function() {
  dojo.io.iframe.send({
    url: '<s:url action="upload" namespace="/" />',
    method: "POST",
    handleAs: "json",
    load: function(response, ioArgs){
    if(response.running) {
      var progressPercent = response.percentComplete + "%";
      var reportText = response.processMessage;
      var uploadProgesssBar = dijit.byId("uploadProgress");
      if(uploadProgesssBar == null) {
        return;
      }
      uploadProgesssBar.update({progress:progressPercent, report:function() {return reportText;}});
    }
    else {
      showById("progressDialogButtonDiv");
      t.stop();
    }
  },
  error: function(response, ioArgs) {
    t.stop();
    var progressPercent = response.percentComplete + "%";
    var reportText = response.processMessage;
    var uploadProgesssBar = dijit.byId("uploadProgress");
    if(uploadProgesssBar == null) {
      return;
    }
    uploadProgesssBar.update({progress:progressPercent, report:function() {return reportText;}});
    showById("progressOkButton");
  }
});
};
function showProgressBar() {
  hideById("uploadForm");
  showById("progressBar");
}
function hideProgressBar() {
  hideById("progressBar");
  showById("uploadForm");
}
function submitAndShowProgress(submitForm) {
  dojo.io.iframe.send({
    form: submitForm,
    handleAs: "json",
    load: function(response, ioArgs) {
      submitForm.reset();
      var progressPercent = response.percentComplete + "%";
      var reportText = response.processMessage;
      if(response.running) {
        showProgressBar();
        var uploadProgesssBar = dijit.byId("uploadProgress");
        if(uploadProgesssBar == null) {
          return;
        }
        uploadProgesssBar.update({progress:progressPercent, report:function() {return reportText;}});
        t.start();
      }
      else {
        createAndShowAlertDialog(reportText, "");
      }
      return response;
    },
    error: function(response, ioArgs) {
      t.stop();
      hideProgressBar();
      createAndShowAlertDialog(response.processMessage, "An Error Occurred");
      return response;  
    }
  });
  return false;
}
</script>

<div id="progressBar" class="hidden loading">
<div dojoType="dijit.ProgressBar" style="width:400px" jsId="uploadProgress" id="uploadProgress" annotate="true"></div>
<div class="hidden actionButtons" id="progressOkButton">
<button style="position: relative; left: 42px;" dojoType="dijit.form.Button" onClick="hideProgressBar(); return false;">Ok</button>
</div>
</div>
<s:form action="upload" namespace="/" enctype="multipart/form-data" id="uploadForm" method="post" onsubmit="return submitAndShowProgress(this);">
<s:file name="file" id="file" label="File" />
<s:submit id="submit" name="submit">Upload</s:submit>
</s:form>

这是我的行动:
(修剪)


public class ProcessFileAction implements LongRunning {
  String processMessage = "Uploading...";
  Integer percentComplete = 0;
  Boolean running = true;

  private FileProcessor fileProcessor;
  private File file;
  private String fileContentType;
  private String fileFileName;

  public String upload() throws Exception {
    setProcessMessage("Processing File...");
    setPercentComplete(10);
    try {
      if(!getFile().exists()) {
        getFile().createNewFile();
      }
      File processedFile = getFileProcessor().process(getFile(), this);
    } catch(Exception e) {
      e.printStackTrace();
      setProcessMessage("An error occurred while processing your file.");
      setPercentComplete(100);
      setRunning(false);
      return ERROR;
    }
    setProcessMessage("Process Complete!");
    setPercentComplete(100);
    setRunning(false);
    return SUCCESS;
  }
...
}
public interface LongRunning {
    public void setProcessMessage(String processMessage);
    public String getProcessMessage();
    public void setPercentComplete(Integer percentComplete);
    public Integer getPercentComplete();
    public void setRunning(boolean running);
    public boolean isRunning();
}

我将查看JSON结果类型的代码和ExecAndWait拦截器以获取更多线索。

1 个答案:

答案 0 :(得分:0)

在查看JSONResult后,我发现了问题。

在JSON上设置“root”对象时,它会在值堆栈中查找值。如果没有,它会查看ActionInvocations操作(不与ExecAndWait Intercepror一起使用)。


public void execute(ActionInvocation invocation) throws Exception {
...
    String json;
    Object rootObject;
    if (this.enableSMD) {
      // generate SMD
      rootObject = this.writeSMD(invocation);
    } else {
      // generate JSON
      if (this.root != null) {
        ValueStack stack = invocation.getStack();
        rootObject = stack.findValue(this.root);
      } else {
        rootObject = invocation.getAction();
      }
    }
...
}

因此,我创建了一个LongRunningImpl类来保存LongRunning信息


public class LongRunningImpl implements LongRunning {
  private Integer percentComplete = 0;
  private String processMessage = "Uploading file...";
  private boolean running = true;
...
}

我在行动中使用了这个对象:


public class ProcessFileAction {
  LongRunning longRunning;

  private FileProcessor fileProcessor;
  private File file;
  private String fileContentType;
  private String fileFileName;

  public String upload() throws Exception {
    getLongRunning().setProcessMessage("Processing File...");
    getLongRunning().setPercentComplete(10);
    try {
      if(!getFile().exists()) {
        getFile().createNewFile();
      }
      File processedFile = getFileProcessor().process(getFile(), getLongRunning());
    } catch(Exception e) {
      e.printStackTrace();
      getLongRunning().setProcessMessage("An error occurred while processing your file.");
      getLongRunning().setPercentComplete(100);
      getLongRunning().setRunning(false);
      return ERROR;
    }
    getLongRunning().setProcessMessage("Process Complete!");
    getLongRunning().setPercentComplete(100);
    getLongRunning().setRunning(false);
    return SUCCESS;
  }
...
}

然后在我的结果上设置一个根对象:


<action name="upload" class="ProcessFileAction" method="upload">
  <interceptor-ref name="agfStack" />
  <interceptor-ref name="execAndWait">
    <param name="delay">1000</param>
    <param name="delaySleepInterval">500</param>
  </interceptor-ref>
  <result name="wait" type="json">
    <param name="noCache">true</param>
    <param name="contentType">text/html</param>
    <param name="wrapPrefix"><![CDATA[<html><body><textarea>]]></param>
    <param name="wrapSuffix"><![CDATA[</textarea></body></html>]]></param>
    <param name="root">longRunning</param>
    <param name="includeProperties">percentComplete,processMessage,running</param>
  </result>
  <result name="success" type="json">
    <param name="noCache">true</param>
    <param name="contentType">text/html</param>
    <param name="wrapPrefix"><![CDATA[<html><body><textarea>]]></param>
    <param name="wrapSuffix"><![CDATA[</textarea></body></html>]]></param>
    <param name="root">longRunning</param>
    <param name="includeProperties">percentComplete,processMessage,running</param>
  </result>
  <result name="error" type="json">
    <param name="noCache">true</param>
    <param name="contentType">text/html</param>
    <param name="wrapPrefix"><![CDATA[<html><body><textarea>]]></param>
    <param name="wrapSuffix"><![CDATA[</textarea></body></html>]]></param>
    <param name="root">longRunning</param>
    <param name="includeProperties">percentComplete,processMessage,running</param>
  </result>
</action>

现在一切正常!我可能会将此列为Struts2的缺陷,但我不确定它是如何被接收的。我认为JSON Result对象应该在默认返回ActionInvocation上的操作之前检查值堆栈上的操作。