从 Spring 到 React UI 的 JSON Patch 流式传输

工程 | Brian Cavalier | 2014 年 10 月 8 日 | ...

我们正在探索帮助开发人员创建丰富、现代的前端,这些前端可以轻松地与 Spring 后端集成的方法。如果您今年参加了 SpringOne,那么您已经看到了一些我们一直在努力的方向。

  1. Spring Data REST 中的超媒体支持,由 Greg Turnquist、Oliver Gierke 和 Roy Clarkson 发表
  2. RaveJS:适用于 JavaScript 应用程序的 Spring Boot 概念,由 John Hann 发表
  3. 差异同步和 JSON Patch,由 Craig Walls 和我发表

简而言之,我们希望简化 Spring 后端与客户端之间的有效通信,并轻松集成最佳和最流行的客户端技术。

React + 流式更新

JSON Patch 是一种用于发送结构化数据增量更改的格式。我认为尝试通过 STOMP 以 JSON Patch 格式将更新流式传输到 Web UI 会很有趣。

Craig Walls 已经使用新的 Spring Sync 项目构建了一个简单的 足球比分概念验证,以通过 STOMP 上的 JSON Patch 将比分更新推送到浏览器。我能够使用他的 POC,引入 RaveJS,添加客户端响应式流,并将更新集成到 React UI 组件中。

您可以在 我的 rave-most-react 分支的 github 上找到完整代码。服务器与 Craig 的原始版本相同。 Web 客户端 是行动发生的地方。在深入了解一些细节之前,请查看 main.js 以了解应用程序的整体情况

开始

我使用 RaveJS 和 npm 来管理我的客户端依赖项,因此我的启动非常简单。

> cd src/main/resources/public

> npm init

<answer a few questions>

> npm install --save rave most jiff react rave-load-jsx rave-node-process stompjs

然后,我只需要在现有的 HTML 中添加一个脚本标签,就可以开始编码了!

<script src="node_modules/rave/rave.js"></script>

介绍 most.js

多亏了 Craig,我已经有一系列更新(以 JSON Patch 格式)通过 STOMP 流向客户端。我决定处理补丁流的最佳方法是(不出所料!)实际使用流

Most.js 是 cujoJS 的新 JavaScript 响应式流包。它提供了一组小型但功能强大的 API,用于创建、转换和使用事件流。我用它来包装 stompjs API。

事实证明,有两个 STOMP 订阅:一个承载所有得分数据的初始完整副本,另一个承载所有后续更改。我能够将这两个订阅包装成一个表示“最新得分集”的单个响应式流,方法是使用 jiff.js 应用到达的 JSON Patch。

这段代码从 STOMP 订阅到初始数据创建一个流,获取第一个事件(所有得分的完整快照),并将其与仅包含 JSON Patch 更新的第二个流组合起来,以生成随时间变化的得分视图。

function getScoresStream(initDestination, updateDestination, client) {
	// Create a stream containing one full copy of the data, and
	// flatMap that to a stream containing the time-varying
	// current set of scores, by accumulating each patch
	// and emitting the updated scores data.
	return getInitialDataStream(initDestination, client)
		.flatMap(function(data) {
			return getUpdatesStream(updateDestination, client, data);
		});
}

function getInitialDataStream (initDestination, client) {
	// Await a copy of the data from the STOMP subscription
	// that is sending the full scores data, then unsubscribe.
	return streamFromStompJson(initDestination, client)
		.take(1);
}

function getUpdatesStream (updateDestination, client, data) {
	// Incrementally accumulate patches from the STOMP subscription
	// that is carrying JSON Patches onto the scores data to produce
	// an updated view of the scores.
	return streamFromStompJson(updateDestination, client)
		.startWith([])
		.scan(updateWithJsonPatch, data);
}

Most.js 还自动清理流结束时的底层资源。很容易安排在收到完整得分数据的初始副本后取消订阅第一个订阅,只留下一个订阅:更改。

使用 React 制作 UI

现在我有一个表示最新得分的单个 most.js 流,我创建了一个 React 组件来显示它们。我安装了(见上文)rave-load-jsx 扩展,这是由社区成员创建的 RaveJS 扩展,它可以在 RaveJS 中直接加载 JSX 组件。我所要做的就是创建一个 Scoreboard.jsx 文件并开始编写一个简单的 React 记分牌组件。

React 组件有一个内部的 state 对象,其中包含将用于呈现组件的数据。我所要做的就是在创建组件时传递最新的得分流,然后让组件观察流并更新其 state。相关代码只有几行。

// this.props.scores is the scores stream provided when the
// Scoreboard component is created

this.props.scores.observe(function(scores) {
	self.setState({ scores: scores });
});

React 自动处理将 DOM 与 state 保持同步。

从比特到像素

这确实是一个玩具应用程序。但是,它展示了相当多的强大概念在非常小的空间内协同工作,代码量很少:小型服务器生成的增量数据通过 STOMP + WebSocket 流向客户端,客户端上的响应式流由 React 组件观察。更改从 Spring 后端流向 UI——可以说是从比特到像素。

我希望这个小型应用程序也能提供我们前进方向的概览。我们希望提供工具和客户端软件包,帮助开发人员构建丰富的现代客户端应用程序,这些应用程序与领先的客户端技术和 Spring 后端集成。

获取 Spring 时事通讯

与 Spring 时事通讯保持联系

订阅

领先一步

VMware 提供培训和认证,以加速您的进步。

了解更多

获取支持

Tanzu Spring 在一个简单的订阅中提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部