springboot1.5.9整合websocket实现实时显示的小demo

时间:2022-11-13 22:53:12

最近由于项目需要实时显示数据库更新的数据变化情况,一开始想过在前端使用ajax异步轮询方法实现,但后面考虑到性能和流量等要求,就放弃该方法而选择使用websocket(毕竟现在springboot整合websocket的技术算是比较成熟了,哈哈),现在此小小记录下。

首先,在springboot项目创建并配置成功的基础上对websocket进行整合。

1、在pom文件中添加对websocket的依赖

      <!-- 引入 websocket 依赖类-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

2、个人习惯是先从后端写到前端,先写websocket的配置类吧

 import org.springframework.stereotype.Component;

 import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet; /**
* @Name:WebSocket
* @Description:WebSocket配置
* @Version:V1.0.0
* @Author:mYunYu
* @Create Date:2018/11/15 14:45
*/
@Component
@ServerEndpoint(value = "/ws/webSocket" , encoders = {EncoderClassVo.class})
public class WebSocket {
//每个客户端都会有相应的session,服务端可以发送相关消息
private Session session; //J.U.C包下线程安全的类,主要用来存放每个客户端对应的webSocket连接
private static CopyOnWriteArraySet<WebSocket> copyOnWriteArraySet = new CopyOnWriteArraySet<WebSocket>(); /**
* @Name:onOpen
* @Description:打开连接。进入页面后会自动发请求到此进行连接
* @Author:mYunYu
* @Create Date:14:46 2018/11/15
* @Parameters:
* @Return:
*/
@OnOpen
public void onOpen(Session session) {
this.session = session;
copyOnWriteArraySet.add(this);
System.out.println("websocket有新的连接, 总数:"+ copyOnWriteArraySet.size()); } /**
* @Name:onClose
* @Description:用户关闭页面,即关闭连接
* @Author:mYunYu
* @Create Date:14:46 2018/11/15
* @Parameters:
* @Return:
*/
@OnClose
public void onClose() {
copyOnWriteArraySet.remove(this);
System.out.println("websocket连接断开, 总数:"+ copyOnWriteArraySet.size());
} /**
* @Name:onMessage
* @Description:测试客户端发送消息,测试是否联通
* @Author:mYunYu
* @Create Date:14:46 2018/11/15
* @Parameters:
* @Return:
*/
@OnMessage
public void onMessage(String message) {
System.out.println("websocket收到客户端发来的消息:"+message);
} /**
* @Name:onError
* @Description:出现错误
* @Author:mYunYu
* @Create Date:14:46 2018/11/15
* @Parameters:
* @Return:
*/
@OnError
public void onError(Session session, Throwable error) {
System.out.println("发生错误:" + error.getMessage() + "; sessionId:" + session.getId());
error.printStackTrace();
} public void sendMessage(Object object){
//遍历客户端
for (WebSocket webSocket : copyOnWriteArraySet) {
System.out.println("websocket广播消息:" + object.toString());
try {
//服务器主动推送
webSocket.session.getBasicRemote().sendObject(object) ;
} catch (Exception e) {
e.printStackTrace();
}
}
} /**
* @Name:sendMessage
* @Description:用于发送给客户端消息(群发)
* @Author:mYunYu
* @Create Date:14:46 2018/11/15
* @Parameters:
* @Return:
*/
public void sendMessage(String message) {
//遍历客户端
for (WebSocket webSocket : copyOnWriteArraySet) {
System.out.println("websocket广播消息:" + message);
try {
//服务器主动推送
webSocket.session.getBasicRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
} /**
* @Name:sendMessage
* @Description:用于发送给指定客户端消息
* @Author:mYunYu
* @Create Date:14:47 2018/11/15
* @Parameters:
* @Return:
*/
public void sendMessage(String sessionId, String message) throws IOException {
Session session = null;
WebSocket tempWebSocket = null;
for (WebSocket webSocket : copyOnWriteArraySet) {
if (webSocket.session.getId().equals(sessionId)) {
tempWebSocket = webSocket;
session = webSocket.session;
break;
}
}
if (session != null) {
tempWebSocket.session.getBasicRemote().sendText(message);
} else {
System.out.println("没有找到你指定ID的会话:{}"+ "; sessionId:" + sessionId);
}
} /**
* 如果使用springboot内置tomcat,需要配置,否则不需要
*
* @return
*/
// @Bean
// public ServerEndpointExporter serverEndpointExporter() {
// return new ServerEndpointExporter();
// } }

上面类中的红色注释的代码是只有当springboot项目使用内置tomcat时需要配置(即打成jar包),如果使用外置tomcat则不需要配置(即打成war包)

3、配置编码器,主要是需要后端向前端发送对象数据,如果只是发送普通的字符串数据的话,就不需要

 import com.alibaba.fastjson.JSON;
import com.xxx.utils.MsgUtil; import javax.websocket.EncodeException;
import javax.websocket.Encoder;
import javax.websocket.EndpointConfig; /**
* @Name:EncoderClassVo
* @Description:编码器,防止发送对象出错
* @Version:V1.0.0
* @Author:mYunYu
* @Create Date:2018/11/15 14:43
*/
public class EncoderClassVo implements Encoder.Text<MsgUtil> { @Override
public void init(EndpointConfig endpointConfig) { } @Override
public void destroy() { } @Override
public String encode(MsgUtil msgUtil) throws EncodeException {
try{
return JSON.toJSONString(msgUtil) ;
}catch (Exception e){
e.printStackTrace() ;
return null;
}
}
}

4、接下来就是写controller层了,我这边demo只是简单的发送一些随机的数据,具体信息还需要根据各个项目需要来写

 import com.xxx.pojo.User;
import com.xxx.utils.MsgUtil;
import com.xxx.webSocket.WebSocket;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource;
import java.io.IOException; /**
* @Name:SocketController
* @Description:消息发送Controller
* @Version:V1.0.0
* @Author:mYunYu
* @Create Date:2018/11/15 16:44
*/
@RestController
public class SocketController { @Resource
WebSocket webSocket; /**
* @Name:helloManyWebSocket
* @Description:群发消息
* @Author:mYunYu
* @Create Date:16:44 2018/11/15
* @Parameters:
* @Return:
*/
@RequestMapping("many")
public String helloManyWebSocket(){ int i = 1 ;
while(i > 0){
i=1+(int)(Math.random()*600) ;
User user = new User() ;
user.setUserid(i+1) ;
user.setUsername(String.valueOf(i) + String.valueOf(i+i)) ; //将对象转为json对象,并发送到前端
MsgUtil msgUtil = MsgUtil.success().addMsg("map", user);
webSocket.sendMessage(msgUtil); try{
Thread.sleep(1000) ;
}catch (Exception e){
e.printStackTrace() ;
}
} return "发送成功";
} /**
* @Name:helloOneWebSocket
* @Description:根据session单个发送消息
* @Author:mYunYu
* @Create Date:16:44 2018/11/15
* @Parameters:
* @Return:
*/
@RequestMapping("one")
public String helloOneWebSocket(String sessionId) throws IOException {
//向某个人发送消息
webSocket.sendMessage(sessionId,"你好~!,单个用户"); return "发送成功";
} }

5、接下来该在前端写配置了,我这里使用的是thymeleaf模板

 <!DOCTYPE html >
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>Title</title>
</head>
<body> 自动连接websocket
<script type="text/javascript"> var socket;
if (typeof (WebSocket) == "undefined") {
console.log("遗憾:您的浏览器不支持WebSocket");
} else {
console.log("恭喜:您的浏览器支持WebSocket"); //实现化WebSocket对象
//指定要连接的服务器地址与端口建立连接
//注意ws、wss使用不同的端口。我使用自签名的证书测试,
//无法使用wss,浏览器打开WebSocket时报错
//ws对应http、wss对应https。
socket = new WebSocket("ws://127.0.0.1:端口号/项目名/ws/webSocket");
//连接打开事件
socket.onopen = function() {
console.log("Socket 已打开");
socket.send("消息发送测试(From Client)");
};
//收到消息事件
socket.onmessage = function(msg) {
console.log(msg.data) ;
};
//连接关闭事件
socket.onclose = function() {
console.log("Socket已关闭");
};
//发生了错误事件
socket.onerror = function() {
alert("Socket发生了错误");
} //窗口关闭时,关闭连接
window.unload=function() {
socket.close();
}; } </script> </body>
</html>

6、最后就是测试了,先右击项目,选择Run Mavan-->clear install进行项目打包

springboot1.5.9整合websocket实现实时显示的小demo

打包成功之后再启动外置tomcat来启动项目

springboot1.5.9整合websocket实现实时显示的小demo

启动项目成功,在浏览器中访问

springboot1.5.9整合websocket实现实时显示的小demo

按f12,如果出现”Socket已打开“字样,则表示客户端连接ok,现在需要使用服务端向客户端发送消息

再打开另一个浏览器,输入http://localhost:端口号/项目名/many进行访问,就可以观察到idea和浏览器中已经打印了发送的消息字样了

springboot1.5.9整合websocket实现实时显示的小demo

上图是客户端访问的浏览器所显示的消息,下图是服务器端所打印的消息

springboot1.5.9整合websocket实现实时显示的小demo

好了,实现的很成功,接下来就是对发送的数据进行替换就差不多了,哈哈~