从 Spring 流式传输 JSON Patch 到 React UI

工程 | 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 将比分更新推送到浏览器。我利用了他的概念验证,引入了 RaveJS,添加了客户端响应式流,并将更新集成到一个 React UI 组件中。

您可以在我的 github 仓库的 rave-most-react 分支中找到完整的代码。服务器与 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 社区的所有近期活动。

查看全部