spring boot Websocket
本文只作为个人笔记,大部分代码是引用其他人的文章的。
参考: https://blog.csdn.net/moshowgame/article/details/80275084
在springboot项目中使用websocket做推送,虽然挺简单的,但初学也踩过几个坑,特此记录。
使用websocket有两种方式:1是使用sockjs,2是使用h5的标准。使用Html5标准自然更方便简单,所以记录的是配合h5的使用方法。
1、pom
核心是@ServerEndpoint这个注解。这个注解是Javaee标准里的注解,tomcat7以上已经对其进行了实现,如果是用传统方法使用tomcat发布项目,只要在pom文件中引入javaee标准即可使用。

- <dependency>
- <groupId>javax</groupId>
- <artifactId>javaee-api</artifactId>
- <version>7.0</version>
- <scope>provided</scope>
- </dependency>

但使用springboot的内置tomcat时,就不需要引入javaee-api了,spring-boot已经包含了。使用springboot的websocket功能首先引入springboot组件。
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-websocket</artifactId>
- <version>1.3.5.RELEASE</version>
- </dependency>
顺便说一句,springboot的高级组件会自动引用基础的组件,像spring-boot-starter-websocket就引入了spring-boot-starter-web和spring-boot-starter,所以不要重复引入。
2、使用@ServerEndpoint创立websocket endpoint
首先要注入ServerEndpointExporter,这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint。要注意,如果使用独立的servlet容器,而不是直接使用springboot的内置容器,就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理。

- @Configuration
- public class WebSocketConfig {
- @Bean
- public ServerEndpointExporter serverEndpointExporter() {
- return new ServerEndpointExporter();
- }
- }

接下来就是写websocket的具体实现类,很简单,直接上代码:


- @ServerEndpoint(value = "/websocket")
- @Component
- public class MyWebSocket {
- //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
- private static int onlineCount = 0;
- //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
- private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();
- //与某个客户端的连接会话,需要通过它来给客户端发送数据
- private Session session;
- /**
- * 连接建立成功调用的方法*/
- @OnOpen
- public void onOpen(Session session) {
- this.session = session;
- webSocketSet.add(this); //加入set中
- addOnlineCount(); //在线数加1
- System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
- try {
- sendMessage(CommonConstant.CURRENT_WANGING_NUMBER.toString());
- } catch (IOException e) {
- System.out.println("IO异常");
- }
- }
- /**
- * 连接关闭调用的方法
- */
- @OnClose
- public void onClose() {
- webSocketSet.remove(this); //从set中删除
- subOnlineCount(); //在线数减1
- System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
- }
- /**
- * 收到客户端消息后调用的方法
- *
- * @param message 客户端发送过来的消息*/
- @OnMessage
- public void onMessage(String message, Session session) {
- System.out.println("来自客户端的消息:" + message);
- //群发消息
- for (MyWebSocket item : webSocketSet) {
- try {
- item.sendMessage(message);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- /**
- * 发生错误时调用
- @OnError
- public void onError(Session session, Throwable error) {
- System.out.println("发生错误");
- error.printStackTrace();
- }
- public void sendMessage(String message) throws IOException {
- this.session.getBasicRemote().sendText(message);
- //this.session.getAsyncRemote().sendText(message);
- }
- /**
- * 群发自定义消息
- * */
- public static void sendInfo(String message) throws IOException {
- for (MyWebSocket item : webSocketSet) {
- try {
- item.sendMessage(message);
- } catch (IOException e) {
- continue;
- }
- }
- }
- public static synchronized int getOnlineCount() {
- return onlineCount;
- }
- public static synchronized void addOnlineCount() {
- MyWebSocket.onlineCount++;
- }
- public static synchronized void subOnlineCount() {
- MyWebSocket.onlineCount--;
- }
- }


使用springboot的唯一区别是要@Component声明下,而使用独立容器是由容器自己管理websocket的,但在springboot中连容器都是spring管理的。
虽然@Component默认是单例模式的,但springboot还是会为每个websocket连接初始化一个bean,所以可以用一个静态set保存起来。
3、前端代码

- <!DOCTYPE HTML>
- <html>
- <head>
- <title>My WebSocket</title>
- </head>
- <body>
- Welcome<br/>
- <input id="text" type="text" /><button onclick="send()">Send</button> <button onclick="closeWebSocket()">Close</button>
- <div id="message">
- </div>
- </body>
- <script type="text/javascript">
- var websocket = null;
- //判断当前浏览器是否支持WebSocket
- if('WebSocket' in window){
- websocket = new WebSocket("ws://localhost:8084/websocket");
- }
- else{
- alert('Not support websocket')
- }
- //连接发生错误的回调方法
- websocket.onerror = function(){
- setMessageInnerHTML("error");
- };
- //连接成功建立的回调方法
- websocket.onopen = function(event){
- setMessageInnerHTML("open");
- }
- //接收到消息的回调方法
- websocket.onmessage = function(event){
- setMessageInnerHTML(event.data);
- }
- //连接关闭的回调方法
- websocket.onclose = function(){
- setMessageInnerHTML("close");
- }
- //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
- window.onbeforeunload = function(){
- websocket.close();
- }
- //将消息显示在网页上
- function setMessageInnerHTML(innerHTML){
- document.getElementById('message').innerHTML += innerHTML + '<br/>';
- }
- //关闭连接
- function closeWebSocket(){
- websocket.close();
- }
- //发送消息
- function send(){
- var message = document.getElementById('text').value;
- websocket.send(message);
- }
- </script>
- </html>

4、总结
springboot已经做了深度的集成和优化,要注意是否添加了不需要的依赖、配置或声明。由于很多讲解组件使用的文章是和spring集成的,会有一些配置,在使用springboot时,由于springboot已经有了自己的配置,再这些配置有可能导致各种各样的异常。
spring boot Websocket的更多相关文章
- 玩转spring boot——websocket
前言 QQ这类即时通讯工具多数是以桌面应用的方式存在.在没有websocket出现之前,如果开发一个网页版的即时通讯应用,则需要定时刷新页面或定时调用ajax请求,这无疑会加大服务器的负载和增加了客户 ...
- spring boot websocket stomp 实现广播通信和一对一通信聊天
一.前言 玩.net的时候,在asp.net下有一个叫 SignalR 的框架,可以在ASP .NET的Web项目中实现实时通信.刚接触java寻找相关替代品,发现 java 体系中有一套基于stom ...
- Spring Boot WebSocket从入门到放弃
在构建Spring boot项目时已经提供webSocket依赖的勾选.webSocket是TCP之上的一个非常薄的轻量级层 ,webSocket主要的应用场景离不开即时通讯与消息推送,但只要应用程序 ...
- 使用spring boot +WebSocket实现(后台主动)消息推送
言:使用此webscoket务必确保生产环境能兼容/支持!使用此webscoket务必确保生产环境能兼容/支持!使用此webscoket务必确保生产环境能兼容/支持!主要是tomcat的兼容与支持. ...
- Spring Boot + WebSocket 学习笔记
首先需要了解一下背景,什么是WebSocket以及为什么要用WebSocket. 在常见的Web应用中,客户端与服务器通信,都是通过HTTP协议进行通信,客户端一次请求,服务端一次响应.而WebSoc ...
- spring boot Websocket(使用笔记)
使用websocket有两种方式:1是使用sockjs,2是使用h5的标准.使用Html5标准自然更方便简单,所以记录的是配合h5的使用方法. 1.pom 核心是@ServerEndpoint ...
- Spring Boot + Websocket + Thymeleaf + Lombok
https://github.com/guillermoherrero/websocket 验证错误消息文件名字:是默认名ValidationMessages.properties,编译后存放在cla ...
- 解决spring boot websocket
在网上找的demo写了一个小例子,本地开发测试都很正常,但是部署在tomcat就各种坑 1.MyWebSocket不要用spring 注解标注 2.main方法对应的类继承SpringBootServ ...
- Spring boot+Websocket实例1
简单的demo https://github.com/callicoder/spring-boot-websocket-chat-demo
随机推荐
- 05. redis事务
目录 Redis 事务 事务 1. 命令有序 2. 始终原子 开启使用事务 Redis事务中出现错误 1. EXEC前的错误 2. EXEC后的错误 为什么出错了不支持roll backs? Redi ...
- 海思3519A 移植ffmpeg
文件下载 下载x264 git clone git://git.videolan.org/x264.git 下载ffmpeg git clone git://source.ffmpeg.org/ffm ...
- Firefox火狐浏览器打开新标签页一直闪烁
问题:Firefox浏览器打开新标签页一直刷新,不能打开页面 解决办法:在url栏输入about:support,打开配置文件夹,然后删除目录中包含storage所有文件,重启Firefox即可.
- 十八、Python面向对象之魔术方法
1.类的比较 class A(object): def __init__(self,value): self.value = value def __eq__(self,other): return ...
- 三、python对字符串和集合的内存垃圾回收机制
变量声明: name1 = "andy" name2 = name1 这个时候我把name1的值给改成了“tom”,问现在name2的值是什么?为什么? 答:andy,因为你把 ...
- shell 脚本命令之alias
1.alias的功能 设置一个别名,即为一个长命令起一个新的名字 2.alias的基本格式 alias alias_name='origin_command' alias是指定别名命令的关键字 a ...
- 使用pipenv管理虚拟环境
使用pipenv管理虚拟环境 安装 pip install pipenv 命令介绍 pipenv --help Usage: pipenv [OPTIONS] COMMAND [ARGS]... Op ...
- USB驱动程序涉及的概念及框架
引入:当我们把一个USB设备接入PC机时,会出现什么样的现象? 现象:把USB设备接到PC1.右下角弹出“发现android phone”2.跳出一个对话框,提示你安装驱动程序 首先来看一下,USB驱 ...
- destoon中get_maincat函数的用法
求解get_maincat函数的用法,如get_maincat(0, $CATEGORY, 1),其中第一.二.三个参数分别表示什么,有谁知道,请介绍下,谢谢! 答:get_maincat() 三个参 ...
- Consul 知识点
平时开发时,一般使用consul dev模式,开发模式下kv存储不会持久化存储,全在内存中(重启consul就丢了!),所以一般建议yml配置文件内容,在项目中单独存一个文件,启动调试时,直接把配置文 ...