最近需要一个动态图表的功能,如下图。
这种实现需要实时推送数据上来,那一般有两种方法
方法一:前端写个定时器,不断轮询后台即可。这当然是很low的,请求太多很不友好,果断抛弃
方法二:使用websocket,废话不多说直接上代码
springboot 整合websocket有两种方法,这里先记录原始方法:
添加webSocket插件
<!--websocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
WebSocketConfig配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
//注意注解
@EnableWebSocket
@Configuration
publicclass WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
returnnew ServerEndpointExporter();
}
}
然后写个webSocket工具类
import org.springframework.stereotype.Controller;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;
//注意是controller注解
@Controller
@ServerEndpoint("/websocket/{tableId}")
publicclass WebSocket {
private Session session;
publicstatic CopyOnWriteArraySet<WebSocket> webSockets =new CopyOnWriteArraySet<>();
privatestatic Map<String,Session> sessionPool = new HashMap<String,Session>();
@OnOpen
publicvoid onOpen(Session session, @PathParam(value="tableId")String code) {
this.session = session;
webSockets.add(this);
(code, session);
// Constants.WEBSOCKET = true;//定义常量 是否开启websocket连接
("【websocket消息】有新的连接,总数为:"+());
}
@OnClose
publicvoid onClose() {
(this);
//Constants.WEBSOCKET = false;
("【websocket消息】连接断开,总数为:"+());
}
@OnMessage
publicvoid onMessage(String message) {
("【websocket消息】收到客户端消息:"+message);
}
// 此为广播消息publicvoid sendAllMessage(String message) {
for(WebSocket webSocket : webSockets) {
("【websocket消息】广播消息:"+message);
try {
().sendText(message);
} catch (Exception e) {
();
}
}
}
// 此为单点消息publicvoid sendOneMessage(String code, String message) {
Session session = (code);
(code);
/*在发送数据之前先确认 session是否已经打开 使用() 为true 则发送消息
* 不然会报错:The WebSocket session [0] has been closed and no method (apart from close()) may be called on a closed session */if (session != null && ()) {
try {
().sendText(message);
} catch (Exception e) {
();
}
}
}
}
简单的已经可以使用的,注意如果后台有用shiro权限框架的注意要开放接口
下面介绍一种在线测试工具
如果项目是前后端分离的,需要nginx进行请求转发的需要在nginx的配置文件里添加如下配置:红色字体部分
主要是把websocket的请求和http请求区分开
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 888;
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_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
这个时候接口换成nginx监听接口即可:
待这些测试完之后在页面new一个websocket即可,我这里用的vue
created(){
();
},
destroyed() {
();
},
initWebSocket: function () {
//debugger;
// WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于https key你自定义的key
//var host = window.location.hostthis.websock = new WebSocket("ws://");
this.websock.onopen = this.websocketonopen;
this.websock.onerror = this.websocketonerror;
this.websock.onmessage = this.websocketonmessage;
this.websock.onclose = this.websocketclose;
console.log(this.websock);
//.send("您好啊"); },
websocketonopen: function () {
},
websocketonerror: function (e) {
},
websocketonmessage: function (e) {//(); //这个是收到后端主动推送的值 },
websocketclose: function (e) {
},
如果想要后端不断推送数据上来,可以写个定时任务:
@Component
publicclass ScheduledTask {
@Autowired
private WebSocket webSocket;
//添加定时任务
//@Scheduled(cron = "0/5 * * * * ?")
@Scheduled(fixedRate=2000)
publicvoid sendMessage() {
("定时发送数据");
//(("str"));
//调用websocket推送消息
("1","str");
}
}