最近需要一个动态图表的功能,如下图。
这种实现需要实时推送数据上来,那一般有两种方法
方法一:前端写个定时器,不断轮询后台即可。这当然是很low的,请求太多很不友好,果断抛弃
方法二:使用websocket,废话不多说直接上代码
springboot 整合websocket有两种方法,这里先记录原始方法:
添加webSocket插件
org.springframework.boot
spring-boot-starter-websocket
WebSocketConfig配置
importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.socket.config.annotation.EnableWebSocket;importorg.springframework.web.socket.server.standard.ServerEndpointExporter;
//注意注解
@EnableWebSocket
@Configurationpublic classWebSocketConfig {
@BeanpublicServerEndpointExporter serverEndpointExporter() {return newServerEndpointExporter();
}
}
然后写个webSocket工具类
importorg.springframework.stereotype.Controller;importjavax.websocket.OnClose;importjavax.websocket.OnMessage;importjavax.websocket.OnOpen;importjavax.websocket.Session;importjavax.websocket.server.PathParam;importjavax.websocket.server.ServerEndpoint;importjava.util.ArrayList;importjava.util.HashMap;importjava.util.List;importjava.util.Map;importjava.util.concurrent.CopyOnWriteArraySet;
//注意是controller注解
@Controller
@ServerEndpoint("/websocket/{tableId}")public classWebSocket {privateSession session;public static CopyOnWriteArraySet webSockets =new CopyOnWriteArraySet<>();private static Map sessionPool = new HashMap();
@OnOpenpublic void onOpen(Session session, @PathParam(value="tableId")String code) {this.session =session;
webSockets.add(this);
sessionPool.put(code, session);//Constants.WEBSOCKET = true;//定义常量 是否开启websocket连接
System.out.println("【websocket消息】有新的连接,总数为:"+webSockets.size());
}
@OnClosepublic voidonClose() {
webSockets.remove(this);//Constants.WEBSOCKET = false;
System.out.println("【websocket消息】连接断开,总数为:"+webSockets.size());
}
@OnMessagepublic voidonMessage(String message) {
System.out.println("【websocket消息】收到客户端消息:"+message);
}//此为广播消息
public voidsendAllMessage(String message) {for(WebSocket webSocket : webSockets) {
System.out.println("【websocket消息】广播消息:"+message);try{
webSocket.session.getAsyncRemote().sendText(message);
}catch(Exception e) {
e.printStackTrace();
}
}
}//此为单点消息
public voidsendOneMessage(String code, String message) {
Session session=sessionPool.get(code);
System.out.println(code);/*在发送数据之前先确认 session是否已经打开 使用session.isOpen() 为true 则发送消息
* 不然会报错:The WebSocket session [0] has been closed and no method (apart from close()) may be called on a closed session*/
if (session != null &&session.isOpen()) {try{
session.getAsyncRemote().sendText(message);
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
简单的已经可以使用的,注意如果后台有用shiro权限框架的注意要开放接口
测试
如果项目是前后端分离的,需要nginx进行请求转发的需要在nginx的配置文件里添加如下配置:红色字体部分
主要是把websocket的请求和http请求区分开
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout65;
map $http_upgrade $connection_upgrade {default upgrade;
''close;
}
server {
listen888;
server_name localhost;
location~/websocket/ {
proxy_pass http://127.0.0.1:8089;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For
$proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
error_page500 502 503 504 /50x.html;
location= /50x.html {
root html;
}
}
}
这个时候接口换成nginx监听接口即可:
待这些测试完之后在页面new一个websocket即可,我这里用的vue
created(){
this.initWebSocket();
},
destroyed() {
this.websocketclose();
},
initWebSocket: function () {//debugger;//WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于https key你自定义的key//var host = window.location.host
this.websock = new WebSocket("ws://47.106.172.176:888/websocket/123");this.websock.onopen = this.websocketonopen;this.websock.onerror = this.websocketonerror;this.websock.onmessage = this.websocketonmessage;this.websock.onclose = this.websocketclose;
console.log(this.websock);//this.websock.send("您好啊");
},
websocketonopen: function () {
},
websocketonerror: function (e) {
},
websocketonmessage: function (e) {//JSON.parse(e.data);//这个是收到后端主动推送的值
},
websocketclose: function (e) {
},
如果想要后端不断推送数据上来,可以写个定时任务:
@Componentpublic classScheduledTask {
@AutowiredprivateWebSocket webSocket;//添加定时任务//@Scheduled(cron = "0/5 * * * * ?")
@Scheduled(fixedRate=2000)public voidsendMessage() {
System.out.println("定时发送数据");//webSocket.sendAllMessage(JSON.toJSONString("str"));
//调用websocket推送消息
webSocket.sendOneMessage("1","str");
}
}