如何将 spring-data-rest 与 spring websocket 混合到单个实现中

我想将状态同步到对特定实体更改感兴趣的所有客户端。所以我想实现这样的目标:

  • 在实体上公开 CRUD API(通过 和HTTP/RESTwebsockets)
  • 并将(修改调用的)响应路由到主题websockets

因此,从技术上讲,我对将spring-data-restspring websockets实现相结合的想法很感兴趣,以实现类似spring-data-websocket的东西。

我想到的是两种解决方案,事实上两者都是:

  • spring-data-rest 通过以下方式公开我的实体REST/HTTP API
  • websocket控制器(用于对实体的修改调用)

控制器将如下所示:websocket

@Controller
public class EntityAWebSocketController {
      @MessageMapping("/EntityA/update")
      @SendTo("/topic/EntityA/update")
      public EntityA update(EntityA entityA) throws Exception {
           // persist,....
           return entityA;
     }
}

场景 1:从 REST/HTTP API 调用的 Websocket API

规则:

  • 客户端请求始终是REST/HTTP API
  • 响应适用于所有操作REST/HTTP API
  • 此外,为了修改操作,消息也会出现websocket

从技术上讲,可以通过以下方式实现:

  • spring-rest-data 事件(即在 、websocketAfterCreateEventAfterSaveEventAfterLinkSaveEventAfterDeleteEvent)

尽管如此,这个解决方案对我来说似乎很恶心,因为我需要去:

  1. 客户端 A -- 请求 -- > 服务器(弹簧-数据-休息控制器)HTTP
  2. 服务器(弹簧数据休息控制器中的XXX事件之后)-- 消息-->弹簧控制器websocketwebsocket
  3. 弹簧网络盒控制器 - 通过主题发送消息 - >所有对该主题感兴趣的客户websocket
  4. 服务器(弹簧数据休息控制器)--响应-->客户端 AHTTP

场景 2:独立于 REST API 的 Websocket API

规则:

  • 客户端请求仅用于非修改操作REST/HTTP API
  • 响应仅适用于非修改操作REST/HTTP API
  • 客户端为所有修改操作发送消息websocket
  • websocket消息仅针对所有修改操作发送到客户端

好吧,如果没有其他想法出现,我会选择后一个,但是,如果我能以某种方式生成通过暴露的方法,比如spring-data-websockets并且只处理我实现中的路由,那就太好了。C(R)UDwebsockets

因为我觉得我必须手动公开(通过s)我所有实体的所有方法。我可能为此太懒了。*WebSocketControllerCUD

想法?


答案 1

方案 2 在最后一步中讨论单个客户端。但我认为你的要求是一个主题,因为你想要多个客户端。如果我想完成 2 以满足您声明的要求,那么您可能希望维护一个客户端列表并实现自己的队列,或者使用 ForkJoinPool 向所有监听 WebSockets 的客户端发送消息。话虽如此,一个主题在这里肯定更优雅,但整体看起来太复杂了,有不同的界面。

对于从客户端到服务器的所有消息,只需使用简单的有线协议并使用集合进行参数化,它可能是RParam1.......

在服务器上,您需要一个控制器将这些映射到不同的请求(和操作)。不知何故,看起来没有太多的工作。希望这有帮助。


答案 2

同样的架构已经困扰了我一段时间了,如果我想提到它的所有缺点和优点,那将是一个很长的故事,所以让我跳到实现中。

第二种情况是有效的,但正如你所提到的,最好在同一 websocket 会话上执行 crud 操作。这将消除每个请求对HTTP握手的需求,并减少消息的正文大小,因此您将有更好的延迟。同时,您已经与服务器建立了持久连接,那么为什么不充分利用它呢?

我搜索了一段时间,从你的问题开始6年后,我仍然找不到任何可以实现这一目标的websocket协议,所以我决定自己做这件事,因为我需要它用于另一个虚拟项目。

这种协议的另一个优点可能是它不需要对已经编写的控制器进行太多更改。因此,它应该能够支持Spring Framework(例如)注释,并从中制作websocket端点。在像spring这样的另一个框架中实现这种协议的困难之处在于,由于创建ServletRequest和ServletResponse并将其转换为您自己的websocket协议并不好,因此您失去了一些优势。例如,在那一刻之前,您在应用程序中编写的任何http过滤器都将毫无意义,因为通过这些过滤器传递websocket消息并不容易。

关于协议本身:我决定通过json格式传递所有内容,以及每个请求的唯一ID,以便我们可以将客户端上的回调映射到请求ID。当然,还有一个过滤器链可以将过滤器添加到其中。

另一个难以处理的事情是Spring Security,因为在某些情况下,它也可以像http过滤器一样工作。在我自己的库中,我终于可以处理注释,但是如果您在HTTP安全配置中使用,那将是一个问题。@PreAuthorizeantMatchers

因此,创建 websocket 适配器来调用 http 控制器将有许多缺点。

你可以在这里查看这个项目:Rest Over Websocket。它是为Spring Boot编写的。


推荐