【问题标题】:Wicket calling a lengthy operation and updating through ajaxWicket 调用冗长的操作并通过 ajax 进行更新
【发布时间】:2013-02-26 13:08:38
【问题描述】:

基于此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()
  }
}

我想避免创建一个暴露我的服务的 Web 服务并且不必编写我自己的 AJAX 调用。我有哪些选择? (使用 Wicket 1.5 / Pax-Wicket)

【问题讨论】:

  • 你能更详细地解释你的问题吗?您有一个 ListView 项目,其中 lenghtyOperation 导致 ListView 项目非常缓慢地出现。然后当 ListView 完成时,你又得到了一个完整的 ajax 请求队列?您期望的期望行为是什么?
  • 哎呀,我这次解释得更好了吗?很抱歉造成混乱。
  • 看看wicket.apache.org/apidocs/1.5/org/apache/wicket/ajax/…我还是不太明白。问题是填充列表视图许多 ajaxrequest 实际上阻止了您使用按钮提交的可能性,因为请求将是队列中的最后一个?
  • 是的,或多或少。考虑到我在getObject() 方法中执行的操作可能需要几分钟,它会阻塞其他AJAX 请求(例如AjaxButton#onSubmit

标签: java web-applications web osgi wicket


【解决方案1】:

我不完全确定 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.
    };
}

【讨论】:

    【解决方案2】:

    最简单的方法是让初始 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 个以上的线程,我建议使用某种线程池,但这超出了这个小演示的范围。


    免责声明:这不是生产代码。这只是为了演示。这对您的资源不利,也不会优雅地处理任何资源不足。当用户点击重新加载或发生其他任何事情时,它将不起作用。

    【讨论】:

    • 谢谢伙计,但我实际上是在轮询某种状态,所以删除 AjaxSelfUpdatingTimerBehavior 是不行的 :(
    • 然后不要删除它。这个解决方案根本不需要。
    • 我的问题是如果我不删除它会阻塞队列,如果我删除它,我将无法多次更新它。实际上正在寻找一种允许我异步运行 Ajax 调用的解决方案。
    • 我不认为,你理解我的想法。我将很快编辑我的答案以包含一些演示代码。
    • 实际上,我解决它的方法是为该方法公开一个 Web 服务并编写我自己的 Ajax 调用,但您的答案绝对是 Wicket 的解决方法。感谢您的澄清,很抱歉回复很晚。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多