本文只作为个人笔记,大部分代码是引用其他人的文章的。

参考: 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标准即可使用。

  1. <dependency>
  2. <groupId>javax</groupId>
  3. <artifactId>javaee-api</artifactId>
  4. <version>7.0</version>
  5. <scope>provided</scope>
  6. </dependency>

  但使用springboot的内置tomcat时,就不需要引入javaee-api了,spring-boot已经包含了。使用springboot的websocket功能首先引入springboot组件。

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-websocket</artifactId>
  4. <version>1.3.5.RELEASE</version>
  5. </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,因为它将由容器自己提供和管理。

  1. @Configuration
  2. public class WebSocketConfig {
  3. @Bean
  4. public ServerEndpointExporter serverEndpointExporter() {
  5. return new ServerEndpointExporter();
  6. }
  7.  
  8. }

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

  1. @ServerEndpoint(value = "/websocket")
  2. @Component
  3. public class MyWebSocket {
  4. //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
  5. private static int onlineCount = 0;
  6.  
  7. //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
  8. private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();
  9.  
  10. //与某个客户端的连接会话,需要通过它来给客户端发送数据
  11. private Session session;
  12.  
  13. /**
  14. * 连接建立成功调用的方法*/
  15. @OnOpen
  16. public void onOpen(Session session) {
  17. this.session = session;
  18. webSocketSet.add(this); //加入set中
  19. addOnlineCount(); //在线数加1
  20. System.out.println("有新连接加入!当前在线人数为" + getOnlineCount());
  21. try {
  22. sendMessage(CommonConstant.CURRENT_WANGING_NUMBER.toString());
  23. } catch (IOException e) {
  24. System.out.println("IO异常");
  25. }
  26. }
  27.  
  28. /**
  29. * 连接关闭调用的方法
  30. */
  31. @OnClose
  32. public void onClose() {
  33. webSocketSet.remove(this); //从set中删除
  34. subOnlineCount(); //在线数减1
  35. System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount());
  36. }
  37.  
  38. /**
  39. * 收到客户端消息后调用的方法
  40. *
  41. * @param message 客户端发送过来的消息*/
  42. @OnMessage
  43. public void onMessage(String message, Session session) {
  44. System.out.println("来自客户端的消息:" + message);
  45.  
  46. //群发消息
  47. for (MyWebSocket item : webSocketSet) {
  48. try {
  49. item.sendMessage(message);
  50. } catch (IOException e) {
  51. e.printStackTrace();
  52. }
  53. }
  54. }
  55.  
  56. /**
  57. * 发生错误时调用
  58. @OnError
  59. public void onError(Session session, Throwable error) {
  60. System.out.println("发生错误");
  61. error.printStackTrace();
  62. }
  63.  
  64. public void sendMessage(String message) throws IOException {
  65. this.session.getBasicRemote().sendText(message);
  66. //this.session.getAsyncRemote().sendText(message);
  67. }
  68.  
  69. /**
  70. * 群发自定义消息
  71. * */
  72. public static void sendInfo(String message) throws IOException {
  73. for (MyWebSocket item : webSocketSet) {
  74. try {
  75. item.sendMessage(message);
  76. } catch (IOException e) {
  77. continue;
  78. }
  79. }
  80. }
  81.  
  82. public static synchronized int getOnlineCount() {
  83. return onlineCount;
  84. }
  85.  
  86. public static synchronized void addOnlineCount() {
  87. MyWebSocket.onlineCount++;
  88. }
  89.  
  90. public static synchronized void subOnlineCount() {
  91. MyWebSocket.onlineCount--;
  92. }
  93. }

使用springboot的唯一区别是要@Component声明下,而使用独立容器是由容器自己管理websocket的,但在springboot中连容器都是spring管理的。

虽然@Component默认是单例模式的,但springboot还是会为每个websocket连接初始化一个bean,所以可以用一个静态set保存起来。

3、前端代码

   

  1. <!DOCTYPE HTML>
  2. <html>
  3. <head>
  4. <title>My WebSocket</title>
  5. </head>
  6.  
  7. <body>
  8. Welcome<br/>
  9. <input id="text" type="text" /><button onclick="send()">Send</button> <button onclick="closeWebSocket()">Close</button>
  10. <div id="message">
  11. </div>
  12. </body>
  13.  
  14. <script type="text/javascript">
  15. var websocket = null;
  16.  
  17. //判断当前浏览器是否支持WebSocket
  18. if('WebSocket' in window){
  19. websocket = new WebSocket("ws://localhost:8084/websocket");
  20. }
  21. else{
  22. alert('Not support websocket')
  23. }
  24.  
  25. //连接发生错误的回调方法
  26. websocket.onerror = function(){
  27. setMessageInnerHTML("error");
  28. };
  29.  
  30. //连接成功建立的回调方法
  31. websocket.onopen = function(event){
  32. setMessageInnerHTML("open");
  33. }
  34.  
  35. //接收到消息的回调方法
  36. websocket.onmessage = function(event){
  37. setMessageInnerHTML(event.data);
  38. }
  39.  
  40. //连接关闭的回调方法
  41. websocket.onclose = function(){
  42. setMessageInnerHTML("close");
  43. }
  44.  
  45. //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
  46. window.onbeforeunload = function(){
  47. websocket.close();
  48. }
  49.  
  50. //将消息显示在网页上
  51. function setMessageInnerHTML(innerHTML){
  52. document.getElementById('message').innerHTML += innerHTML + '<br/>';
  53. }
  54.  
  55. //关闭连接
  56. function closeWebSocket(){
  57. websocket.close();
  58. }
  59.  
  60. //发送消息
  61. function send(){
  62. var message = document.getElementById('text').value;
  63. websocket.send(message);
  64. }
  65. </script>
  66. </html>

  4、总结

  springboot已经做了深度的集成和优化,要注意是否添加了不需要的依赖、配置或声明。由于很多讲解组件使用的文章是和spring集成的,会有一些配置,在使用springboot时,由于springboot已经有了自己的配置,再这些配置有可能导致各种各样的异常。

spring boot Websocket的更多相关文章

  1. 玩转spring boot——websocket

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

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

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

  3. Spring Boot WebSocket从入门到放弃

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

  4. 使用spring boot +WebSocket实现(后台主动)消息推送

    言:使用此webscoket务必确保生产环境能兼容/支持!使用此webscoket务必确保生产环境能兼容/支持!使用此webscoket务必确保生产环境能兼容/支持!主要是tomcat的兼容与支持. ...

  5. Spring Boot + WebSocket 学习笔记

    首先需要了解一下背景,什么是WebSocket以及为什么要用WebSocket. 在常见的Web应用中,客户端与服务器通信,都是通过HTTP协议进行通信,客户端一次请求,服务端一次响应.而WebSoc ...

  6. spring boot Websocket(使用笔记)

    ​ 使用websocket有两种方式:1是使用sockjs,2是使用h5的标准.使用Html5标准自然更方便简单,所以记录的是配合h5的使用方法. 1.pom ​ 核心是@ServerEndpoint ...

  7. Spring Boot + Websocket + Thymeleaf + Lombok

    https://github.com/guillermoherrero/websocket 验证错误消息文件名字:是默认名ValidationMessages.properties,编译后存放在cla ...

  8. 解决spring boot websocket

    在网上找的demo写了一个小例子,本地开发测试都很正常,但是部署在tomcat就各种坑 1.MyWebSocket不要用spring 注解标注 2.main方法对应的类继承SpringBootServ ...

  9. Spring boot+Websocket实例1

    简单的demo https://github.com/callicoder/spring-boot-websocket-chat-demo

随机推荐

  1. 05. redis事务

    目录 Redis 事务 事务 1. 命令有序 2. 始终原子 开启使用事务 Redis事务中出现错误 1. EXEC前的错误 2. EXEC后的错误 为什么出错了不支持roll backs? Redi ...

  2. 海思3519A 移植ffmpeg

    文件下载 下载x264 git clone git://git.videolan.org/x264.git 下载ffmpeg git clone git://source.ffmpeg.org/ffm ...

  3. Firefox火狐浏览器打开新标签页一直闪烁

    问题:Firefox浏览器打开新标签页一直刷新,不能打开页面 解决办法:在url栏输入about:support,打开配置文件夹,然后删除目录中包含storage所有文件,重启Firefox即可.

  4. 十八、Python面向对象之魔术方法

    1.类的比较 class A(object): def __init__(self,value): self.value = value def __eq__(self,other): return ...

  5. 三、python对字符串和集合的内存垃圾回收机制

    变量声明: name1 = "andy" name2 = name1   这个时候我把name1的值给改成了“tom”,问现在name2的值是什么?为什么? 答:andy,因为你把 ...

  6. shell 脚本命令之alias

    1.alias的功能 设置一个别名,即为一个长命令起一个新的名字 2.alias的基本格式 alias   alias_name='origin_command' alias是指定别名命令的关键字 a ...

  7. 使用pipenv管理虚拟环境

    使用pipenv管理虚拟环境 安装 pip install pipenv 命令介绍 pipenv --help Usage: pipenv [OPTIONS] COMMAND [ARGS]... Op ...

  8. USB驱动程序涉及的概念及框架

    引入:当我们把一个USB设备接入PC机时,会出现什么样的现象? 现象:把USB设备接到PC1.右下角弹出“发现android phone”2.跳出一个对话框,提示你安装驱动程序 首先来看一下,USB驱 ...

  9. destoon中get_maincat函数的用法

    求解get_maincat函数的用法,如get_maincat(0, $CATEGORY, 1),其中第一.二.三个参数分别表示什么,有谁知道,请介绍下,谢谢! 答:get_maincat() 三个参 ...

  10. Consul 知识点

    平时开发时,一般使用consul dev模式,开发模式下kv存储不会持久化存储,全在内存中(重启consul就丢了!),所以一般建议yml配置文件内容,在项目中单独存一个文件,启动调试时,直接把配置文 ...