2013-03-11 105 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. 
    }; 
}