Spring Boot + WebSocket 学习笔记
首先需要了解一下背景,什么是WebSocket以及为什么要用WebSocket。
在常见的Web应用中,客户端与服务器通信,都是通过HTTP协议进行通信,客户端一次请求,服务端一次响应。而WebSocket使得客户端与服务端可以直接构建起一条TCP的通道。这里附上一段百度百科的文字说明:WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
当客户端有需要向后台实时请求最新数据的情景下(实际上应该是服务端侦知到数据发生变更主动推送给客户端),目前一般是使用AJAX来进行一个定时的轮询,而使用WebSocket即可很好的适配该种需求场景。两种方式的对比可见下图:
相关背景就说到这里,下面结合代码进行实战。
首先在Spring Boot工程的pom文件中添加相关依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
接下来先实现一个WebSocket类,并通过注解@ServerEndpoint指定在服务器上发布的URI供客户端连接时填写。
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet; import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RestController; @ServerEndpoint("/testWebSocket")
@RestController
public class TestWebSocket { // 用来记录当前连接数的变量
private static volatile int onlineCount = 0; // concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象
private static CopyOnWriteArraySet<TestWebSocket> webSocketSet = new CopyOnWriteArraySet<TestWebSocket>(); // 与某个客户端的连接会话,需要通过它来与客户端进行数据收发
private Session session; private static final Logger LOGGER = LoggerFactory.getLogger(TestWebSocket.class); @OnOpen
public void onOpen(Session session) throws Exception {
this.session = session;
System.out.println(this.session.getId());
webSocketSet.add(this);
LOGGER.info("Open a websocket.");
} @OnClose
public void onClose() {
webSocketSet.remove(this);
LOGGER.info("Close a websocket. ");
} @OnMessage
public void onMessage(String message, Session session) throws IOException, InterruptedException {
LOGGER.info("Receive a message from client: " + message); for (int i = 0; i < 10; i ++) { session.getBasicRemote().sendText(String.valueOf(i));
Thread.sleep(1000);
}
} @OnError
public void onError(Session session, Throwable error) {
LOGGER.error("Error while websocket. ", error);
} public void sendMessage(String message) throws Exception {
if (this.session.isOpen()) {
this.session.getBasicRemote().sendText("Send a message from server. ");
}
} public static synchronized int getOnlineCount() {
return onlineCount;
} public static synchronized void addOnlineCount() {
TestWebSocket.onlineCount++;
} public static synchronized void subOnlineCount() {
TestWebSocket.onlineCount--;
}
}
对应前端页面websocket.html内容如下方所示。
<html>
<body>
<input id="text" type="text"/>
<button onclick="send()">发送消息</button>
<hr/>
<div id="message"></div>
</body> <script type="text/javascript">
var websocket = null;
//判断当前浏览器是否支持WebSocket
if ('WebSocket' in window) {
websocket = new WebSocket("ws://localhost:8080/testWebSocket");
}
else {
alert('当前浏览器 不支持WebSocket')
} //连接发生错误的回调方法
websocket.onerror = function () {
setMessageInnerHTML("WebSocket连接发生错误");
}; //连接成功建立的回调方法
websocket.onopen = function () {
setMessageInnerHTML("WebSocket连接成功");
} //接收到消息的回调方法
websocket.onmessage = function (event) {
setMessageInnerHTML(event.data);
} //连接关闭的回调方法
websocket.onclose = function () {
setMessageInnerHTML("WebSocket连接关闭");
} //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = function () {
closeWebSocket();
} //将消息显示在网页上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
} //关闭WebSocket连接
function closeWebSocket() {
websocket.close();
} //发送消息
function send() {
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</html>
同时在控制层中增加对新增页面的定向。
@RequestMapping("/websocket")
public String websocket() {
return "websocket";
}
这时启动项目并通过http://localhost:8080/websocket访问,出现如下报错。
原因是未将WebSocket添加到Spring的容器中。
@Configuration
public class WebSocketConfig { @Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
网上有资料提到,该类必须与项目入口或者说启动类在同一个子包下,不然可能会出现注入失败的问题。我这里倒没有遇到,也没办法复现,该问题也就不继续深究。
验证成功!
参考资料:
https://www.runoob.com/html/html5-websocket.html
https://www.cnblogs.com/strugglion/p/10021173.html
Spring Boot + WebSocket 学习笔记的更多相关文章
- Spring BOOT的学习笔记
1,静态文件夹src/main/resources/static下的,图片必须放在images文件夹下才能访问,直接放在static下不能访问 2,配置热部署,否则修改下Html,图片都得重启 htt ...
- Spring boot + jdbc学习笔记
pom.xml: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www. ...
- Spring boot ----RestTemplate学习笔记
****spring boot-----restTemplate 封装了HttpURLConnection,HttpClient,Netty等接口访问实现库 restTemplet包含以下部分 Htt ...
- Spring Boot WebSocket从入门到放弃
在构建Spring boot项目时已经提供webSocket依赖的勾选.webSocket是TCP之上的一个非常薄的轻量级层 ,webSocket主要的应用场景离不开即时通讯与消息推送,但只要应用程序 ...
- spring cloud(学习笔记)高可用注册中心(Eureka)的实现(二)
绪论 前几天我用一种方式实现了spring cloud的高可用,达到两个注册中心,详情见spring cloud(学习笔记)高可用注册中心(Eureka)的实现(一),今天我意外发现,注册中心可以无限 ...
- WebSocket学习笔记IE,IOS,Android等设备的兼容性问
WebSocket学习笔记IE,IOS,Android等设备的兼容性问 一.背景 公司最近准备将一套产品放到Andriod和IOS上面去,为了统一应用的开发方式,决定用各平台APP嵌套一个HTML5浏 ...
- WebSocket学习笔记——无痛入门
WebSocket学习笔记——无痛入门 标签: websocket 2014-04-09 22:05 4987人阅读 评论(1) 收藏 举报 分类: 物联网学习笔记(37) 版权声明:本文为博主原 ...
- 玩转spring boot——websocket
前言 QQ这类即时通讯工具多数是以桌面应用的方式存在.在没有websocket出现之前,如果开发一个网页版的即时通讯应用,则需要定时刷新页面或定时调用ajax请求,这无疑会加大服务器的负载和增加了客户 ...
- spring boot websocket stomp 实现广播通信和一对一通信聊天
一.前言 玩.net的时候,在asp.net下有一个叫 SignalR 的框架,可以在ASP .NET的Web项目中实现实时通信.刚接触java寻找相关替代品,发现 java 体系中有一套基于stom ...
随机推荐
- Zabbix添加windows主机监控
zabbix监控windows主机 1.官网下载zabbix的windows-agent(选择相应版本): https://www.zabbix.com/cn/download_agents 2.将下 ...
- react native 8081 端口号被占
McAfee Agent 占用8081 端口号 公司电脑被标装,McAfee Agent关不掉 sudo lsof -n -i4TCP:8081 sudo launchctl list | grep ...
- Homebrew 安装 Docker Desktop for Mac
无意中发现Homebrew现在已经支持Docker Desktop for Mac了,因此特意把原来通过 https://docs.docker.com/docker-for-mac/install/ ...
- 启xin宝app的token算法破解——token分析篇(三)
前两篇文章分析该APP的抓包.的逆向: 启xin宝app的token算法破解--抓包分析篇(一) 启xin宝app的token算法破解--逆向篇(二) 本篇就将对token静态分析,其实很简单就可以搞 ...
- WPF中查看PDF文件 - 基于开源的MoonPdfPanel (无需安装任何PDF阅读器)问题汇总
致敬Yang-Fei—有一个简单的用法示例: http://www.cnblogs.com/yang-fei/p/4885570.html. 写MoonPdfPanel的哥们关于这个开源软件的实现介绍 ...
- STM32F0系列芯片SPI发送一字节数据却输出16个CLK时钟的解决办法
问题 上一个项目在用寄存器操作STM32F0芯片的SPI_DR寄存器的时候,发现一个问题: 我给DR寄存器赋值一个uint8_t一字节大小的数据,SPI引脚能正确输出数据和时钟,但前面八位正确的数据输 ...
- Fire Balls 04——砖塔的创建,动态上升以及旋转
版权申明: 本文原创首发于以下网站: 博客园『优梦创客』的空间:https://www.cnblogs.com/raymondking123 优梦创客的官方博客:https://91make.top ...
- unity_实用小技巧(相机跟随两个主角移动)
在两人对战的游戏中,有时候我们希望能看清楚两玩家的状态,这时我们需要让相机跟随玩家,可是我们不能让相机只跟随一个玩家移动,这时我们可以取两玩家的中点作为相机的位置.方法如下: public Trans ...
- Leetcode之回溯法专题-22. 括号生成(Generate Parentheses)
Leetcode之回溯法专题-22. 括号生成(Generate Parentheses) 给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合. 例如,给出 n ...
- 详解javascript中的this的指向问题
首先,要明白this 既不指向函数自身,也不指函数的词法作用域.this一般存在于函数中,表示当前函数的执行上下文,如果函数没有执行,那么this没有内容,只有函数在执行后this才有绑定. 然后,我 ...