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

Posted

技术标签:

【中文标题】如何将 spring-data-rest 与 spring websocket 混合到一个实现中【英文标题】:How to mix spring-data-rest with spring websocket into a single implementation 【发布时间】:2014-02-12 05:42:54 【问题描述】:

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

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

所以从技术上讲,我会对将 spring-data-rest 与 spring websockets implementation 混合以实现类似 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:Websocket APIREST/HTTP API调用

规则:

客户端请求总是REST/HTTP API 所有操作的回复是REST/HTTP API 此外,对于修改操作,websocket 消息也会出现

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

从spring-rest-data events调用websocket控制器(即在AfterCreateEventAfterSaveEventAfterLinkSaveEventAfterDeleteEvent

仍然解决方案对我来说似乎很糟糕,因为我需要去:

    client A --HTTP request--> 服务器(spring-data-rest 控制器) 服务器(spring-data-rest 控制器中的 AfterXXXEvent)--websocket 消息--> Spring websocket 控制器 Spring websocket 控制器 --websocket 通过主题发送消息--> 对主题感兴趣的所有客户端 服务器(spring-data-rest 控制器)--HTTP 响应--> 客户端A

场景 2:Websocket API 独立于 REST API

规则:

客户端请求为REST/HTTP API,仅用于非修改操作 回复是REST/HTTP API,仅用于非修改操作 客户端为所有修改操作发送websocket消息 websocket 消息仅发送给客户端进行所有修改操作

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

我觉得我必须手动公开(通过*WebSocketControllers)我所有实体的所有CUD 方法。我可能太懒了。

想法?

【问题讨论】:

有趣!鉴于 Spring 4.0 对 websockets 有很好的支持,Spring Data REST 应该能够向端点发送消息。为什么不针对 SDR 打开 JIRA (jira.springsource.org/browse/DATAREST)? @saintbands 感谢您的提示!我之前也考虑过。然而,*** 方式赢了。尽管如此,我还是提出了这个问题:jira.springsource.org/browse/DATAREST-232 无论如何,这似乎是从 spring-data-rest 团队本身获得一些想法的最佳方式。 我也将在春季刊中对此投一票。这正是我想要做的。如果我必须为所有真正带走一些好处的 SDR 方法编写相应的控制器方法。您最终选择了一种解决方案还是另一种解决方案? @BrandonV 不。我没有时间在这里继续前进。 天哪,我需要这个! 【参考方案1】:

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

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

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

【讨论】:

【参考方案2】:

同样的架构已经困扰了我一段时间,如果我想提到它的所有缺点和优点,那就说来话长了,所以让我跳入实现。

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

我搜索了一段时间,在您提出问题 6 年后,我仍然找不到任何可以实现这一点的 websocket 协议,所以我决定自己解决这个问题,因为我需要它用于另一个虚拟项目。

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

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

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

因此,创建 websocket 适配器来调用 http 控制器会有很多弊端。

您可以在此处查看该项目:Rest Over Websocket。它是为 Spring Boot 编写的。

【讨论】:

以上是关于如何将 spring-data-rest 与 spring websocket 混合到一个实现中的主要内容,如果未能解决你的问题,请参考以下文章

排除 Spring-data-rest 资源的部分字段

如何在 Spring-Data-Rest 中实现细粒度的访问控制?

使用 spring-data-rest 将资源添加到集合

将业务逻辑添加到 spring-data-rest 应用程序

Spring-Data-Rest 验证器

如何在 spring-data-rest 中将 Page<ObjectEntity> 映射到 Page<ObjectDTO>