Spring Boot实战之基于WebSocket协议构建交互式Web应用

本文阅读时间大约8分钟。


1. WebSocket简介

WebSocekt协议诞生于2008年,在2011年成为国际标准,目前所有的浏览器都已经支持WebSocket协议了。WebSocket协议属于服务器推送技术的一种,它最大的特点就是可以实现服务端和客户端的双向通信。

WebSocket协议和HTTP协议一样,也是在TCP协议层之上的应用层协议,刚接触WebSocket协议的人通常会有个疑问:都有HTTP这个应用层协议了,为啥还要再搞出一个WebSocket协议?

事实上,HTTP是无状态的,并且只能支持单向通信,即都是浏览器向服务端发送HTTP请求,然后得到一个响应。

在实际应用中,还有另外一种场景:服务端有数据更新的时候,希望客户端能够及时感知到。针对这种场景,在WebSocket出现之前,只能采用长轮询的方案(如下图所示)——客户端通过一个AJAX请求和定时器进行轮询查询;这样的方案在服务端数据变化比较频繁的时候,是比较适合使用的,但是当服务端数据变化不频繁的时候,就会面临一个两难的选择:轮询间隔时间短了,会增加服务端的负担,轮询得时间间隔长了,又不能及时感知到服务端数据的变化。

WebSocket协议的出现就是为了解决上面这个两难问题的,可以弥补长轮询方案的不足,使用WebSocket协议的方案的时序图如下图所示,浏览器和服务端之间会建立一个WebSocket连接,基于这个连接客户端可以给服务端发送信息,服务端也可以给客户端发送信息,如果服务端的数据变更不频繁,或者客户端对数据感知的时效性要求不高,就比较适合使用WebSocket这种方案。

2. Spring Boot实战

下面我们会使用Spring Boot中的Websocket支持组件,实现一个交互式的Web应用程序,演示下WebSocket协议的工作过程。

2.1 服务端

1. 新建一个Spring Boot工程,在pom中加入下面的依赖:

Spring Boot Maven插件提供了很多方便的特性:

  • 将classpath下的Jar包打包成一个独立的可以运行的Jar包,方便应用的交付和部署;

  • 搜索所有的类,将含有main方法的那个类标记为运行入口类;

  • 内置了一个依赖解析器,可以自动选择跟当前的Spring Boot版本适配的版本号

2. 创建请求和响应的消息类,分别是:HelloMessage.java和Greeting.java,代码如下所示:

3. 接下来增加Spring配置,开启WebSocket和STOMP消息的支持,具体的WebSocketConfig代码如下所示:

  • @Configuration注解表示WebSocketConfig是一个Spring配置类;

  • @EnableWebSocketMessageBroker注解用来启动Spring的WebSocket消息处理代理;

  • configureMessageBroker()方法用来配置消息代理的一些特性,通过调用enableSiampleBroker()方法,启动一个基于内存的消息代理,该消息代理会将打招呼的消息广播给那些订阅了“/topic”卡头的客户端;

  • setApplicationDestinationPrefixes()方法用来跟@MessageMapping注解一起起作用,这个注解指定的是服务端接口的前缀,整体下来,greeting()方法对应的请求路径是"/app/hello"。

  • registerStompEndpoints()方法用来注册"/gs-guide-websocket"端点,使得SockJS客户端在不支持WebSocket协议的时候,可以选择其他的传输协议连接服务端,例如:xhr-streaming、xhr-polling等等。

4. 创建基于ws协议的消息处理Controller类,在Spring中,我们计划使用STOMP协议来演示ws协议的应用,STOMP协议并不是为websocket设计的,它属于消息队列的一种协议,和AMQP、 JMS是一个层面的东西,只不过由于它的简单性恰巧可以用于定义websocket的消息体格式。

  • @MessageMapping注解的作用类似于Spring MVC中的@RequestMapping,表示greeting()方法可以处理发往“/hello”的消息;

  • greeting()方法的参数是HelloMessage类,消息的内容会被转换成HelloMessage对象,这个方法的内部会先休眠1秒——模拟服务端的处理过程,然后给客户端返回一个消息响应对象(Greeting对象);

  • @SendTo注解表示:消息的响应使用的是广播模式,greeting()方法返回的消息,会发送给所有订阅了“/topic/greetings”的订阅者

2.2 客户端

前面准备好了服务端代码,接下来我们需要开发一个JS客户端,用来跟服务端进行双向通信。

1. 创建客户端界面,这里非常简单,就一个index.html文件,在这个文件的开头,引入了SOCKJSSTOMP两个JS库,用来跟服务端进行通信。

2. 编写客户端逻辑,创建一个JS文件——app.js,代码如下所示,其中最需要关注的是connect()方法和sendName()方法。

  • connect()方法利用SOCKJSstomp.js访问服务端的"/gs-guide-websocket"端点来建立连接,如果建连成功,客户单就会订阅主题“/topic/greetings”——服务端会将返回的消息广播发送到该主题;如果该主题收到了消息,那么客户端会调用showGreeting()方法,在浏览器上渲染出它收到的消息内容;

  • sendName()方法用来接收用户的输入,并利用STOMP客户端将用户输入的内容发送到服务端——"/app/hello",相应地,该请求会被服务端的GreetingController.greeting()方法处理。

最后,前后端的代码架构如下图所示


2.3 运行演示

1. 通过WebsocketdemoApplication.main()启动应用程序,启动过程如下:

2. 打开两个浏览器页面,都访问localhost:8080,分别点击Connect按钮,将这两个客户端都跟服务端建立连接,如下图所示:

3. 在任意一个客户端中发送消息,延迟一会,可以看到两个客户端页面都看到了服务端返回的消息——这就是前文说的广播模式。

3. 总结

本文首先介绍了WebSocket的定义,然后比较了HTTP协议和WebSocket协议的异同点,并且针对实际应用中的服务端-客户端数据同步的场景进行了不同方案的分析和讨论,分别讨论了长轮询方案和基于WebSocket协议的方案的优劣点;最后利用Spring Boot提供的组件,实现了一个简单的交互应用,用来展示WebSocket协议的实际应用和效果。

4. 参考资料

  1. http://www.ruanyifeng.com/blog/2017/05/websocket.html

  2. https://www.fullstackpython.com/websockets.html

  3. https://spring.io/guides/gs/messaging-stomp-websocket/

  4. 《Spring Boot实战》

往期精选

Spring Boot实战之定时任务调度

Spring Boot实战之业务状态机

跟着阿杜拆书:《慢思考》

Mac高效开发之iTerm2、Prezto和Solarized主题

本号专注于后端技术、JVM问题排查和优化、Java面试题、个人成长和自我管理等主题,为读者提供一线开发者的工作和成长经验,期待你能在这里有所收获。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
演示。 非常抱歉,我无法提供源代码演示,因为我是一个基于自然语言处理的AI语言模型,无法演示具体的代码实现。但是,我可以提供一些相关的参考资料,希望可以帮到你。 对于 Spring Boot Websocket 服务端的实现,你可以先了解一些基本概念和实现原理。Websocket 协议是一种基于 TCP 的通信协议,它实现了双向通信,可以在客户端和服务器之间建立持久性连接,支持实时更新、交互式的数据传输。 Spring BootWebsocket 的支持是通过 Spring Websocket 模块来实现的。你可以先学习一下 Spring Websocket 的基本概念和使用方法,了解如何创建和配置 Websocket 服务端。 下面是一个简单的 Spring Boot Websocket 服务端代码示例,供参考: ``` @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(new WebSocketHandler(), "/ws"); } } public class WebSocketHandler extends TextWebSocketHandler { private static final List<WebSocketSession> sessions = new CopyOnWriteArrayList<>(); @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { sessions.add(session); System.out.println("New client connected"); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { sessions.remove(session); System.out.println("Client disconnected"); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { System.out.println("Received message: " + message.getPayload()); for (WebSocketSession s : sessions) { s.sendMessage(message); } } } ``` 这段代码实现了一个简单的 Websocket 服务端,它在服务器启动时注册一个 WebSocketHandler,用于处理客户端的连接和消息。在客户端连接建立后,它会将该连接添加到一个 List 中保存。当客户端断开连接时,它会从 List 中移除该连接。在接收到客户端的消息后,它会将该消息发送给所有连接的客户端。具体的实现过程中还涉及到一些异常处理、日志记录等问题,需要根据具体需求进行调整。 希望这个代码示例能够帮到你,如果你还有其他的问题或疑问,可以随时向我提出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值