Wicket调用冗长的操作并通过ajax进行更新

时间:2013-03-11 11:15:10

标签: java web-applications web osgi wicket

基于这个SO question,我已经了解到Wicket将后续的AJAX请求排队。现在我的页面上有几个AJAX请求,我想再添加一个产生冗长操作的页面。

public void populateItem(final Item item) {
  final MyObject object = (MyObject) item.getModelObject();
  // ... a couple of fields
  Label statusLabel = new Label("status", new AbstractReadOnlyModel() {
    @Override
    public Object getObject() {
      return someService.doSomeLengthyOperation();
    }
  });
  statusLabel.add(new AjaxSelfUpdatingTimerBehavior(Duration.seconds(5)));
  item.add(statusLabel)
}

一旦这个Ajax请求触发,它可能需要一分钟才能完成执行。这里的问题是someService.doSomeLengthyOperation()将会执行n times the number of rows,这意味着我将排队n times two-minutes。现在,正如我所提到的,Wicket将后续的AJAX请求排队。

我需要number-of-rows * minutes-it-take-to-finish-the-operation加载页面或做其他需要AJAX的东西

new AjaxButton("ajax-button"){
  @Override
  protected void onSubmit(AjaxRequestTarget target, Form form) {
    //.. this won't be executed until all the statusLabels have finished invoking getObject()
  }
}

我想避免创建一个公开我的服务并且必须编写自己的AJAX调用的Web服务。我有什么选择? (使用Wicket 1.5 / Pax-Wicket)

2 个答案:

答案 0 :(得分:3)

最简单的方法是让初始Ajax请求快速返回(没有任何结果)并向目标组件添加AjaxSelfUpdatingTimerBehavior。如果有结果,此行为将检查间隔(例如每10秒左右)。如果有结果,它应该更新组件并删除它自己。

这样,您可以在单独的任务中执行操作,而不会阻止Ajax调用。

为了详细说明,我创建了一个可运行的quickstart,它可以像你所描述的那样发出5个Ajax调用,每个调用运行10秒到1分钟之间的随机时间。与此同时,还有一个带有计数器的响应式AjaxLink。

主要思想是将实际的Ajax调用与对慢速方法的调用分开。

add(new ListView<DataHolder>("list", list) {

    @Override
    protected void populateItem(ListItem<DataHolder> item) {
        DataHolder dh = item.getModelObject();
        item.add(new Label("itemNumber", new PropertyModel<Integer>(dh, "number")));
        Label result = new Label("itemResult", new PropertyModel<String>(dh, "result"));
        result.setOutputMarkupId(true);
        result.add(new AjaxSelfUpdatingTimerBehavior(Duration.seconds(2)));
        item.add(result);
        Thread thread = new Thread(new Processor(item.getModelObject()));
        thread.start();
    }
});

如您所见,标签模型不再直接调用doSomeLengthyOperation()。相反,会产生一个新的线程来完成繁重的工作。 Processor类只是实现Runnable接口并使用run-method来完成工作(在你的情况下,在演示中它只是等待一段时间)。

PropertyModel的getter封装了这个特技并使其透明,同时快速返回以防止阻塞。

public String getResult() {
    String retValue;
    if (!processed) {
        retValue = String.format("Still busy after %d requests", counter++);
    } else {
        retValue = result;
    }
    return retValue;
}

处理后的成员只是一个标志,处理器用它来表示它已经完成等待(ehr工作)。

由于您可能会同时发出超过5个线程,我建议使用某种Threadpool,但这超出了这个小型演示的范围。


免责声明:这不是生产代码。它只是用于演示。它对你的资源不好,也不会优雅地处理它的缺乏。当用户点击重新加载或其他任何事情时,它将无法工作。

答案 1 :(得分:0)

我不完全确定WicketStuff异步任务是否可以帮助您,但尝试一下:

https://github.com/wicketstuff/core/wiki/Async-tasks

以下是Async Tasks项目中的简短演示:

public class DemoPage extends WebPage implements IRunnableFactory {

public DemoPage() {

    Form<?> form = new Form<Void>("form");
    AbstractTaskContainer taskContainer = DefaultTaskManager.getInstance()
        .makeContainer(1000L, TimeUnit.MINUTES);
    ProgressButton progressButton = new ProgressButton("button", form, 
        Model.of(taskContainer), this, Duration.milliseconds(500L));
    ProgressBar progressBar = new ProgressBar("bar", progressButton);

    add(form);
    form.add(progressButton);
    form.add(progressBar);
}

@Override
public Runnable getRunnable() {
    return new IProgressObservableRunnable() {
        // Runnable implementation.
    };
}