- 背景:
最近项目涉及到数据实时展示给前端推送消息通知功能,后端数据状态发生改变时发送消息给前端,登陆用户可以实时接收到消息的提醒,避免频繁刷新,通过websocket取代轮询。
- Spring boot部分:
- POM.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
- 新建配置类:
package io.xcc.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
/**
* 注入ServerEndpointExporter,
* 这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
- 新建实现类:
@Component
@ServerEndpoint("/ws/awdMatch/{userId}")
public class AWDMatchWebSocket {
private Session session;
private static CopyOnWriteArraySet<AWDMatchWebSocket> webSockets = new CopyOnWriteArraySet<>();
private static Map<Long, Session> sessionPool = new HashMap<>();
@OnOpen
public void onOpen(Session session, @PathParam(value = "userId") Long userId) {
this.session = session;
webSockets.add(this);
sessionPool.put(userId, session);
System.out.println(userId + " 已连接 \n【websocket消息】有新的连接,总数为:" + webSockets.size());
}
@OnClose
public void onClose() {
webSockets.remove(this);
System.out.println("【websocket消息】连接断开,总数为:" + webSockets.size());
}
@OnMessage
public void onMessage(String message) {
System.out.println("【websocket消息】收到客户端消息:" + message);
}
/**
* 此为广播消息
*/
public void sendAllMessage(String message) {
for (AWDMatchWebSocket webSocket : webSockets) {
System.out.println("【websocket消息】广播消息:" + message);
try {
webSocket.session.getAsyncRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 此为单点消息
*/
public void sendOneMessage(Long userId, String message) {
System.out.println("【websocket消息】单点消息:" + message);
Session session = sessionPool.get(userId);
if (session != null) {
try {
session.getAsyncRemote().sendText(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
- controller 新增调用类:
-
@Log @Api(tags = "websocket 测试接口") @RestController @RequestMapping("ws") public class AwdMatchWSTestController { @Autowired private AWDMatchWebSocket webSocket; @GetMapping("/sendAllWebSocket") public String test() { String text="你们好!这是websocket群体发送!"; webSocket.sendAllMessage(text); return text; } @GetMapping("/sendOneWebSocket/{userId}") public String sendOneWebSocket(@PathVariable Long userId) { String text=userId+" 你好! 这是websocket单人发送!"; webSocket.sendOneMessage(userId,text); return text; } }
- VUE部分:
<script>
export default {
data () {
return {
userId: 122222
}
},
methods: {
initWebSocket () {
// 连接错误
this.websocket.onerror = this.setErrorMessage
// 连接成功
this.websocket.onopen = this.setOnopenMessage
// 收到消息的回调
this.websocket.onmessage = this.setOnmessageMessage
// 连接关闭的回调
this.websocket.onclose = this.setOncloseMessage
// 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
window.onbeforeunload = this.onbeforeunload
},
setErrorMessage () {
console.log('WebSocket连接发生错误 状态码:' + this.websocket.readyState)
},
setOnopenMessage () {
console.log('WebSocket连接成功 状态码:' + this.websocket.readyState)
},
setOnmessageMessage (event) {
// 根据服务器推送的消息做自己的业务处理
console.log('服务端返回:' + event.data)
},
setOncloseMessage () {
console.log('WebSocket连接关闭 状态码:' + this.websocket.readyState)
},
onbeforeunload () {
this.closeWebSocket()
},
closeWebSocket () {
this.websocket.close()
}
},
mounted () {
// WebSocket
if ('WebSocket' in window) {
this.websocket = new WebSocket('ws://localhost:20181/ws/awdMatch/' + this.userId)
this.initWebSocket()
} else {
alert('当前浏览器 Not support websocket')
}
},
beforeDestroy () {
this.onbeforeunload()
}
}
</script>
实现 这一功能并不复杂,可以针对不同的功能模块 vue组件 接入websocket,后端数据 以json数据格式发送,针对不同 模块数据增加标识符进行区分。