【问题标题】:Associate async task's completion/progress monitor with session将异步任务的完成/进度监视器与会话相关联
【发布时间】:2018-09-07 00:11:12
【问题描述】:

我希望能够在 java 中执行异步任务,并能够保持与用户会话关联的完成(以及可能的进度)监视器。这可能吗?如果可以,该怎么做?

目前,该任务作为无状态会话 bean 方法同步实现,从 jax-rs 端点调用。

我查看了https://docs.oracle.com/javaee/7/tutorial/ejb-async001.htm,但AsyncResult 不可序列化,所以我想我无法将它添加到会话中。

【问题讨论】:

  • 我不清楚你的目标。您打算继续使用 jax-rs 还是不能以其他方式进行?我可以分享一个 Wildfly + JSF 的工作示例,它执行以下操作:客户端上传一个文件,该文件在后台处理,客户端可以在 outputText 中看到已处理的行数
  • 解决方案不需要绑定jax-rs。我想如果我可以将进度监视器保存到会话中,那么我使用什么作为端点并不重要。我希望用户能够随时访问该页面并查看其任务的进度(或至少是否已完成),但解决方案不应涉及添加数据库状态(仅限会话)。
  • 所以请尽可能分享代码。

标签: asynchronous java-8 wildfly wildfly-10 stateless-session-bean


【解决方案1】:

使用 Spring 注解 @Async,您可以使任何 bean/方法异步。 容器将创建一个新线程,方法将异步执行。您也可以将会话对象传递给此方法,完成后,您可以在会话对象中标记一个属性。 示例:- https://spring.io/guides/gs/async-method/

【讨论】:

  • 我想知道为什么这个答案会被更新和奖励。 Spring 是一项与 Wildfly 完全无关的技术。 JavaEE 和 Wildfly 具有 @Asynchronous 注解。那又怎样?
【解决方案2】:

JSF 示例,适用于 Wildfly:

1 在视图中 (xhtml) 我们有一个上传表单和进度表

<h:form>
    <div align="justify">
    <p:fileUpload style="width: auto" fileUploadListener="#{fileUploadCtrl.handleFileUpload}" mode="advanced" label="Please pick XLS file" update="messages" auto="true" sizeLimit="1000000" allowTypes="/(\.|\/)(xls|xlsx)$/" />
    <p:growl id="messages" showDetail="false" life="4000"/>
    </div>
</h:form>

 <h:form id="wholeform">
    <h:outputText id="statusot" value="#{fileUploadCtrl.message}" />
    <p:spacer width="10" height="10"/>
    <p:poll interval="1" listener="#{fileUploadCtrl.updateStatus}" update="wholeform" />
</h:form>

2在控制器中,这是一个托管bean,我们处理文件并每秒更新一次状态

@ManagedBean
@ViewScoped

public class FileUploadCtrl {

@EJB
private SomeBusinessLogicClass model;

@EJB
private ProgressTracker progress;

private Future<List<String>> asyncResult;
private int progressId = 0;
private String message;
private boolean busy = false;

public void handleFileUpload(FileUploadEvent event) {

    Set<String> ids = model.populate(event.getFile().getContents());

    progressId = progress.newIndex();
    asyncResult = model.process(ids);
    busy = true;

    FacesMessage message = new FacesMessage("Loaded " + ids.size() + " objects", "");
    FacesContext.getCurrentInstance().addMessage(null, message);
}

public void updateStatus() {

    if (!busy)
        return;

    try {

        if (asyncResult.isDone()) {
            List<String> r = asyncResult.get();
            message = "Job done";
            busy = false;
            progress.delIndex(progressId);
        } else {
            message = progress.getIndex(progressId)+"-th element in work";
        }

    } catch (Exception e) {
        System.out.println("updateStatus " + e.toString());
    }
}

3 所有业务逻辑都在像 SomeBusinessLogicClass 或许多其他的 EJB 中。我们还需要一个简单的进度管理器 EJB,我完全贴出来

@Singleton
public class ProgressTracker {

private Map<Integer,Integer> indexes = new HashMap<>();

public Map<Integer, Integer> getIndexes() {
    return indexes;
}

public void setIndexes(Map<Integer, Integer> indexes) {
    this.indexes = indexes;
}

public Integer newIndex() {
    Integer size = indexes.size();
    indexes.put(size,0);
    return size;
}

public void incIndex(final Integer index) {

    int old = indexes.get(index);
    old++;
    indexes.put(index,old);
}

public Integer getIndex(final Integer index) {
    return indexes.get(index);
}

public void delIndex(Integer index) {
    indexes.remove(index);
}

}

也许这个例子并不优雅,我几乎是前端的新手,但它工作得很好,总比没有好。

【讨论】:

  • 如果不明显,调用model中的业务方法(如model.process(ids); 应该用@Asynchronous注解来完成
猜你喜欢
  • 2013-02-21
  • 1970-01-01
  • 2017-05-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多