如何将Spring Data Rest和Spring WebSocket混合到单个实现中

34

我希望将状态同步到所有对特定实体更改感兴趣的客户端,因此我想要实现以下内容:

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

因此从技术上讲,我对将spring-data-restspring 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: REST/HTTP API 调用 Websocket API

规则:

  • 客户端请求始终为 REST/HTTP API
  • 对于所有操作,响应都是 REST/HTTP API
  • 此外,对于修改操作,也会收到 websocket 消息

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

  • spring-rest-data 事件 中调用 websocket 控制器(即在 AfterCreateEvent, AfterSaveEvent, AfterLinkSaveEvent, AfterDeleteEvent 中)

但我认为这个解决方案相当不可取,因为我需要进行以下步骤:

  1. 客户端A --HTTP请求--> 服务器(spring-data-rest控制器)
  2. 服务器(spring-data-rest控制器中的 AfterXXXEvent)--websocket消息--> Spring websocket控制器
  3. Spring websocket控制器 --websocket消息通过 topic --> 所有感兴趣的客户端
  4. 服务器(spring-data-rest控制器)--HTTP响应--> 客户端A

场景2: Websocket API 与 REST API 独立

规则:

  • 对于非修改操作,客户端请求为 REST/HTTP API
  • 对于非修改操作,响应也是 REST/HTTP API
  • 对于所有修改操作,客户端发送 websocket 消息
  • 只有对于所有修改操作,才会将 websocket 消息发送到客户端

如果没有其他想法,我会选择后者,但是,如果可以通过类似 spring-data-websockets 的方式生成暴露在 websockets 中的 C(R)UD 方法,并且仅在我的实现中处理路由,那就太好了。

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

有什么想法吗?


1
有趣!考虑到Spring 4.0对Websockets有很好的支持,Spring Data REST应该能够消息端点。为什么不在SDR上开一个JIRA(https://jira.springsource.org/browse/DATAREST)? - Stackee007
@saintbands,感谢你的建议!我之前也考虑过这个方法。然而,Stackoverflow 的方式胜出了。不过,我还是提出了这个问题:https://jira.springsource.org/browse/DATAREST-232。无论如何,这似乎是从 spring-data-rest 团队本身获取一些想法的最佳方式。 - Peter Butkovic
1
我也会在春季期刊中为此投票。这正是我想要做的。如果我必须为所有SDR方法编写相应的控制器方法,那么这确实会削弱一些好处。你最终选择了哪个解决方案? - bvulaj
@BrandonV 不,我没有时间在这里继续了。 - Peter Butkovic
1
哇,这个我需要! - Nestor Ledon
2个回答

1
场景2讨论了最后一步中单个客户端的情况,但我认为您的要求是关于一个主题,因为您需要多个客户端。如果我想满足您所述的要求完成第2步,则您可能需要维护客户端列表并实现自己的队列或使用ForkJoinPool向监听您的WebSocket的所有客户端发送消息。话虽如此,在这里使用主题肯定更加优雅,但总体看起来过于复杂,带有不同的接口。
对于客户端到服务器的所有消息,只需采用简单的传输协议并使用集合进行参数化即可,可以是RParam1.......
在服务器上,您需要一个控制器将其映射到不同的请求(和操作)。看起来不像太多工作。希望这可以帮到您。

0

同样的架构已经困扰了我一段时间,如果我想提到所有的缺点和优点,那将是一个漫长的故事,所以让我们直接进入实现。

第二种情况是有效的,但正如你所提到的,最好在同一个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编写的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接