首先需要了解一下背景,什么是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 学习笔记的更多相关文章

  1. Spring BOOT的学习笔记

    1,静态文件夹src/main/resources/static下的,图片必须放在images文件夹下才能访问,直接放在static下不能访问 2,配置热部署,否则修改下Html,图片都得重启 htt ...

  2. Spring boot + jdbc学习笔记

    pom.xml: <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www. ...

  3. Spring boot ----RestTemplate学习笔记

    ****spring boot-----restTemplate 封装了HttpURLConnection,HttpClient,Netty等接口访问实现库 restTemplet包含以下部分 Htt ...

  4. Spring Boot WebSocket从入门到放弃

    在构建Spring boot项目时已经提供webSocket依赖的勾选.webSocket是TCP之上的一个非常薄的轻量级层 ,webSocket主要的应用场景离不开即时通讯与消息推送,但只要应用程序 ...

  5. spring cloud(学习笔记)高可用注册中心(Eureka)的实现(二)

    绪论 前几天我用一种方式实现了spring cloud的高可用,达到两个注册中心,详情见spring cloud(学习笔记)高可用注册中心(Eureka)的实现(一),今天我意外发现,注册中心可以无限 ...

  6. WebSocket学习笔记IE,IOS,Android等设备的兼容性问

    WebSocket学习笔记IE,IOS,Android等设备的兼容性问 一.背景 公司最近准备将一套产品放到Andriod和IOS上面去,为了统一应用的开发方式,决定用各平台APP嵌套一个HTML5浏 ...

  7. WebSocket学习笔记——无痛入门

    WebSocket学习笔记——无痛入门 标签: websocket 2014-04-09 22:05 4987人阅读 评论(1) 收藏 举报  分类: 物联网学习笔记(37)  版权声明:本文为博主原 ...

  8. 玩转spring boot——websocket

    前言 QQ这类即时通讯工具多数是以桌面应用的方式存在.在没有websocket出现之前,如果开发一个网页版的即时通讯应用,则需要定时刷新页面或定时调用ajax请求,这无疑会加大服务器的负载和增加了客户 ...

  9. spring boot websocket stomp 实现广播通信和一对一通信聊天

    一.前言 玩.net的时候,在asp.net下有一个叫 SignalR 的框架,可以在ASP .NET的Web项目中实现实时通信.刚接触java寻找相关替代品,发现 java 体系中有一套基于stom ...

随机推荐

  1. Vue + TypeScript + Element 搭建简洁时尚的博客网站及踩坑记

    前言 本文讲解如何在 Vue 项目中使用 TypeScript 来搭建并开发项目,并在此过程中踩过的坑 . TypeScript 具有类型系统,且是 JavaScript 的超集,TypeScript ...

  2. Linux系统启动流程(重要!)

    Linux系统启动流程   从上至下为: BIOS  MBR:Boot Code 执行引导程序-GRUB(操作系统) 加载内核 执行init run level 1.BIOS(Basic Input ...

  3. Spring学习之旅(六)--SpringMVC集成

    对大多数 Java 开发来说,基于 web 的应用程序是我们主要的关注点. Spring 也提供了对于 web 的支持,基于 MVC 模式的 Spring MVC 能够帮助我们灵活和松耦合的完成 we ...

  4. Spring框架的重要问题

    这篇文章总结了一些关于Spring框架的重要问题,这些问题都是你在面试或笔试过程中可能会被问到的. 目录 Spring概述 依赖注入 Spring Beans Spring注解 Spring的对象访问 ...

  5. Asp.net MVC 集成AD域认证

    1.首先WebApi 应用下Web.config要配置域认证服务器节点,如下 <!--LDAP地址 用于项目AD系统账号密码验证--> <!--0:关闭域认证:1:开启域认证--&g ...

  6. docker使用nginx反向代理springboot

    docker运行nginx容器 快速安装运行 docker-hub文档 https://hub.docker.com/_/nginx 拉取nginx1.6.0 docker pull nginx:1. ...

  7. HDU2874 Connections between cities 最近公共祖先

    第一次按常规的方法求,将所有的查询的u,v,和最近公共祖先都保存起来,然后用tarjan+并查集求最近公共祖先.因为询问的次数过多,所以在保存查询的时候总是MLE,后来参考了一下别人的代码,才突然觉悟 ...

  8. codeforces 828 D. High Load(思维,水题)

    题目链接:http://codeforces.com/contest/828/problem/D 题解:任意去一个点为根然后有几个k就是几个子叶也就是根结点有几个分支然后最好的解法就是贪心,将剩下的点 ...

  9. Numbers That Count POJ - 1016

    "Kronecker's Knumbers" is a little company that manufactures plastic digits for use in sig ...

  10. codeforces 264 B. Good Sequences(dp+数学的一点思想)

    题目链接:http://codeforces.com/problemset/problem/264/B 题意:给出一个严格递增的一串数字,求最长的相邻两个数的gcd不为1的序列长度 其实这题可以考虑一 ...