Spring的多个私有WebSocket消息

时间:2015-11-03 21:31:54

标签: java spring spring-mvc websocket

我正在使用Spring @RequestMapping来使用和生成JSON的REST同步服务。我现在想要添加异步响应,如果客户端发送了一个id列表,服务器会将详细信息发回给它,只有那个客户端。

我一直在寻找并找不到我要找的东西。我见过两种不同的Spring方法。最常见的是消息代理方法,似乎每个人都通过订阅队列或主题来获取每条消息。这是非常不可接受的,因为这是私人数据。我还有一定数量的数据点可以返回。另一种方法是Callable,AsyncResult或DeferredResult。这似乎保持数据私密,但我想发送多个回复。

我已经看到类似于我想要的东西,但在服务器上使用Jersey SSE。我想坚持使用Spring。

这是我目前使用的伪代码。

@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;
}

谢谢,Wes。

2 个答案:

答案 0 :(得分:0)

它不会像这样工作:您正在使用普通的Spring操作,这些操作旨在在单个线程中处理,该线程可能会阻塞,直到计算完整的请求。你不能在控制器内部创建线程 - 或者至少不是这样。

如果计算持续时间很长,并且您希望为用户提供视觉反馈,请执行以下步骤:

  • 优化程序:)使用索引,缓存,无论
  • 如果仍然不够,计算仍然会持续,用户需要反馈,您将有两个选择

    • 使用javascript进行投票并显示视觉反馈(更简单)。基本上,您将任务提交给线程池并立即返回,并且还有另一个控制器方法,它读取计算的当前状态并将其返回给用户。这个方法每10秒左右被javascript调用
    • 使用反向通道(服务器推送,websocket) - 不是那么容易,因为您必须同时实现客户端和服务器部分。显然有些库和协议只会使这些代码很少,但是如果你以前从未尝试过,那么你将花一些时间来理解设置 - 加上调试websockets并不像普通的HTTP那么容易,因为调试工具

答案 1 :(得分:0)

进行了大量挖掘,但看起来Spring 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;
}

仍在努力优雅地关闭频道并使用Jersey EventSource解析JSON对象,但它比消息总线要好得多。

同样产生一个新线程并使用睡眠仅适用于POC。我不需要,因为我们已经有一个异步进程来访问慢速后端系统。

韦斯。