2015-11-03 59 views
0

我正在使用Spring @RequestMapping獲取和生成JSON的REST同步服務。我現在想要添加異步響應,當客戶端發送一個id列表,並且服務器發回它的細節,因爲它只讓它們到達一個客戶端。與Spring的多個私有WebSocket消息

我一直在尋找一段時間,還沒有找到我在找什麼。我看到了Spring的兩種不同的方法。最常見的是消息代理方式,它看起來每個人都通過訂閱隊列或主題來獲取每條消息。這是非常不可接受的,因爲這是私人數據。我也有數量有限的數據點要返回。另一種方法是Callable,AsyncResult或DeferredResult。這似乎保持數據私密,但我想發送多個響應。

我已經看到類似於我想要的東西,但在服務器上使用Jersey SSE。我想堅持春天。

這是我目前使用僞代碼。

@RequestMapping(value = BASE_PATH + "/balances", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) 
public GetAccountBalancesResponse getAccountBalances(@RequestBody GetAccountBalancesRequest request) { 
    GetAccountBalancesResponse ret = new GetAccountBalancesResponse(); 

    ret.setBalances(synchronousService.getBalances(request.getIds()); 

    return ret; 
} 

這就是我期待的。因爲我不知道細節,所以這很粗糙。一旦我找出發送,我將工作在異步部分,但會採取任何建議。

@RequestMapping(value = BASE_PATH + "/balances", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) 
public ???<BalanceDetails> getAccountBalances(@RequestBody GetAccountBalancesRequest request) { 
    final ???<BalanceDetails> ret = new ???<>(); 

    new Thread(new Runnable() { 
    public void run() { 
     List<Future<BalanceDetails>> futures = asynchronousService.getBalances(request.getIds()); 

     while(!stillWaiting(futures)) { 
     // Probably use something like a Condition to block until there is some details. 
     ret.send(getFinishedDetails(futures)); 
     } 

     ret.close(); 
    } 
    }).start(); 

    return ret; 
} 

謝謝,韋斯。

回答

0

花了很多挖,但它看起來像春天的Web 4.2不支持服務器端的事件。我正在使用使用Spring Web 4.1.7的Spring Boot 1.2.7。切換到Spring Boot 1.3.0.RC1添加了SseEmitter。

這是我的僞代碼。

@RequestMapping(value = BASE_PATH + "/getAccountBalances", method = RequestMethod.GET) 
public SseEmitter getAccountBalances(@QueryParam("accountId") Integer[] accountIds) { 
    final SseEmitter emitter = new SseEmitter(); 

    new Thread(new Runnable() { 

    @Override 
    public void run() { 
     try { 
     for (int xx = 0; xx < ids.length; xx++) { 
      Thread.sleep(2000L + rand.nextInt(2000)); 

      BalanceDetails balance = new BalanceDetails(); 
      ... 
      emitter.send(emitter.event().name("accountBalance").id(String.valueOf(accountIds[xx])) 
        .data(balance, MediaType.APPLICATION_JSON)); 
     } 

     emitter.send(SseEmitter.event().name("complete").data("complete")); 
     emitter.complete(); 
     } catch (Exception ee) { 
     ee.printStackTrace(); 
     emitter.completeWithError(ee); 
     } 
    } 
    }).start(); 

    return emitter; 
} 

仍在制定正常關閉通道和解析使用新澤西州的EventSource JSON對象,但它比一條消息總線好得多。

也產生一個新的線程和使用睡眠只是爲POC。我也不需要,因爲我們已經有一個異步進程來訪問慢速後端系統。

Wes。

0

它不會像這樣工作:您正在使用普通的Spring動作,這些動作旨在在一個單獨的線程中進行處理,直到完成請求計算爲止。你不要在控制器內創建線程 - 或者至少不是這樣。

如果計算持續時間很長,你想給你的用戶提供視覺反饋,這些步驟如下:

  • 優化程序:)使用索引,緩存,無論
  • 如果仍然ISN這還不夠,計算仍然持續不斷,用戶需求反饋,您將有兩個選項

    • 使用javascript進行輪詢並顯示視覺反饋(更簡單)。基本上,您將任務提交到線程池並立即返回,並且還有另一個控制器方法,用於讀取計算的當前狀態並將其返回給用戶。這種方法每隔10秒左右由JavaScript調用一次
    • 使用反向通道(服務器推送,websocket) - 並不那麼容易,因爲您必須同時實現客戶端和服務器部分。很顯然,有些庫和協議會使這些代碼只有很少的一段代碼,但如果你以前從未嘗試過,那麼你需要花一些時間瞭解設置 - 此外,調試websockets並不像普通的HTTP那麼容易,因爲調試工具
+0

我想弄清楚如何使用websockets,我看到的只是Spring的消息總線/廣播示例。我添加了一個RequestBody來顯示我想要接收一個有效載荷。我添加了線程來顯示我想要一個返回多個響應的異步進程。我只找到了匹配我想要做的Jersey例子或者只返回1個異步響應的Spring例子。 我無法控制數據需要多長時間,因爲它來自我無法控制的遠程後端系統。我也沒有控制數據,因爲那是依賴於用戶的。 – Wes

+0

讓我改述一下:websockets是一種服務器推送技術。如果您需要它,您還需要客戶端註冊的服務器端消息總線。從你的評論看來,你似乎沒有控制權,沒有約束,也沒有要求。我想知道你如何編寫任何代碼... – Raffaele

+0

另外,看看['MessageBrokerRegistry.setUserPrefix'](http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/消息/ SIMP /配置/ MessageBrokerRegistry.html#setUserDestinationPrefix-java.lang.String-) – Raffaele