2013-03-11 106 views
4

基于此SO question,我了解到Wicket会对后续的AJAX请求进行排队。现在我的页面被几个AJAX请求缠住了,我想再添加一个,产生一个冗长的操作。Wicket调用冗长的操作并通过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)

+0

你能更详细地解释你的问题吗?您有一个列表视图,其中lenghtyOperation导致ListView项目非常缓慢地出现。然后,当ListView完成时,你又得到了一个完整的ajax请求队列?你期望的行为是什么? – 2013-03-11 12:31:40

+0

啊哈,我这次解释好了吗?对困惑感到抱歉。 – 2013-03-11 13:06:49

+0

看看http://wicket.apache.org/apidocs/1.5/org/apache/wicket/ajax/AjaxChannel.html我还没完全理解。问题是,填充列表视图许多ajaxrequest阻止你实际上提交使用按钮的可能性,因为请求将是队列中的最后一个? – 2013-03-11 14:24:36

回答

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封装了这个特技并使其透明,而allways快速返回以防止阻塞。

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

处理后的成员只是一个标志,处理器用它来指示它是否已完成等待(ehr working)。

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


声明:这不是生产代码。这只是为了演示。这对你的资源不好,也不会妥善处理它的缺点。当用户重新加载或其他任何事情发生时,它将不起作用。

+0

感谢队友,但我实际上正在轮询某种状态,所以删除'AjaxSelfUpdatingTimerBehavior'是不行的:( – 2013-03-11 12:53:49

+0

然后不要删除它,这个解决方案不需要这样做 – Nicktar 2013-03-12 08:44:11

+0

我的问题是如果我不删除它,它会堵塞队列,如果我这样做了,我将不能再更新它,实际上是寻找一个解决方案,让我可以异步运行我的Ajax调用 – 2013-03-13 02:46:17

0

我不能完全确定,如果WicketStuff异步任务可以帮助你,但不妨一试:

https://github.com/wicketstuff/core/wiki/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. 
    }; 
}