详解spring boot Websocket使用笔记
本文只作为个人笔记,大部分代码是引用其他人的文章的。
在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已经有了自己的配置,再这些配置有可能导致各种各样的异常。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
下一篇: Django查询数据库的性能优化示例代码