后端
注入maven依赖
<!--websocket
-->
<dependency>
<groupId>org
.springframework
.boot
</groupId
>
<artifactId>spring
-boot
-starter
-websocket
</artifactId
>
</dependency
>
第一种方式
websocket配置
package com
.jx
.fly
.common
.config
;
import com
.jx
.fly
.module
.mapper
.LaborProjectConfigMapper
;
import com
.jx
.fly
.websocket
.WebSocketServer
;
import org
.springframework
.beans
.factory
.annotation
.Autowired
;
import org
.springframework
.context
.annotation
.Bean
;
import org
.springframework
.context
.annotation
.Configuration
;
import org
.springframework
.web
.socket
.server
.standard
.ServerEndpointExporter
;
@Configuration
public class WebSocketConfig{
@Bean
public ServerEndpointExporter
serverEndpointExporter() {
return new ServerEndpointExporter();
}
@Autowired
public void setMapper(LaborProjectConfigMapper laborProjectConfigMapper
){
WebSocketServer
.laborProjectConfigMapper
=laborProjectConfigMapper
;
}
}
websocket业务处理类
package com
.jx
.fly
.websocket
;
import cn
.hutool
.log
.StaticLog
;
import com
.jx
.fly
.module
.mapper
.LaborProjectConfigMapper
;
import com
.jx
.smart
.common
.model
.labor
.attendance
.project
.LaborProjectConfigModel
;
import org
.springframework
.stereotype
.Component
;
import javax
.websocket
.*
;
import javax
.websocket
.server
.PathParam
;
import javax
.websocket
.server
.ServerEndpoint
;
import java
.io
.IOException
;
import java
.util
.*
;
import java
.util
.concurrent
.CopyOnWriteArraySet
;
@ServerEndpoint("/websocket/{projectId}")
@Component
public class WebSocketServer {
public static LaborProjectConfigMapper laborProjectConfigMapper
;
private static Map
<Integer
, CopyOnWriteArraySet
<WebSocketServer>> SERVER_MAP
= new HashMap<>();
private Session session
;
private int projectId
;
@OnOpen
public void onOpen(Session session
,@PathParam("projectId") Integer projectId
){
this.session
= session
;
this.projectId
= projectId
;
if (projectId
!= null
){
LaborProjectConfigModel model
= laborProjectConfigMapper
.selectById(projectId
);
if (model
!= null
){
CopyOnWriteArraySet
<WebSocketServer> set
= SERVER_MAP
.get(projectId
);
if (set
!= null
){
set
.add(this);
}else {
CopyOnWriteArraySet
<WebSocketServer> sessionSet
= new CopyOnWriteArraySet<>();
sessionSet
.add(this);
SERVER_MAP
.put(projectId
,sessionSet
);
}
StaticLog
.info("session:"+session
+"连接成功,"+model
.getId()+"项目在线数量: "+SERVER_MAP
.get(projectId
).size());
sendMessage("连接成功");
}else {
StaticLog
.error("websocket IO异常");
sendMessage("非法连接");
}
}else {
sendMessage("projectId不能为空");
}
}
@OnClose
public void onClose() {
SERVER_MAP
.forEach((k
,v
)->v
.remove(this));
StaticLog
.info("projectId:"+projectId
+",session:"+session
+"关闭连接,项目在线数量: "+SERVER_MAP
.get(projectId
).size());
}
@OnMessage
public void onMessage(String message
, Session session
) {
SERVER_MAP
.forEach((k
,v
)->{
for (WebSocketServer item
: v
) {
item
.sendMessage(message
);
}
});
}
@OnError
public void onError(Session session
, Throwable error
) {
StaticLog
.error("session:"+session
+"发生错误");
error
.printStackTrace();
}
public void sendMessage(String message
) {
try {
StaticLog
.info("sendMessage projectId: "+projectId
+",message: "+message
);
this.session
.getBasicRemote().sendText(message
);
} catch (IOException e
) {
e
.printStackTrace();
}
}
public static void send(int projectId
,String message
) {
SERVER_MAP
.forEach((k
,v
)->{
for (WebSocketServer item
: v
) {
if(item
.projectId
== projectId
){
item
.sendMessage(message
);
}
}
});
}
}
第二种方式
websocket配置
package com
.jx
.fly
.common
.config
;
import com
.jx
.fly
.module
.mapper
.LaborProjectConfigMapper
;
import com
.jx
.fly
.websocket
.WebSocketHandler
;
import com
.jx
.fly
.websocket
.WebSocketInterceptor
;
import com
.jx
.fly
.websocket
.WebSocketServer
;
import org
.springframework
.beans
.factory
.annotation
.Autowired
;
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
.config
.annotation
.WebSocketConfigurer
;
import org
.springframework
.web
.socket
.config
.annotation
.WebSocketHandlerRegistry
;
import org
.springframework
.web
.socket
.server
.standard
.ServerEndpointExporter
;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Autowired
private LaborProjectConfigMapper laborProjectConfigMapper
;
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry
) {
webSocketHandlerRegistry
.addHandler(new WebSocketHandler(), "/websocket/{projectId}").setAllowedOrigins("*").addInterceptors(new WebSocketInterceptor(laborProjectConfigMapper
));
}
}
websocket业务处理类
package com
.jx
.fly
.websocket
;
import cn
.hutool
.log
.StaticLog
;
import com
.alibaba
.fastjson
.JSONObject
;
import com
.jx
.fly
.module
.mapper
.LaborProjectConfigMapper
;
import com
.jx
.smart
.common
.model
.labor
.attendance
.project
.LaborProjectConfigModel
;
import org
.springframework
.web
.socket
.CloseStatus
;
import org
.springframework
.web
.socket
.TextMessage
;
import org
.springframework
.web
.socket
.WebSocketMessage
;
import org
.springframework
.web
.socket
.WebSocketSession
;
import javax
.websocket
.*
;
import javax
.websocket
.server
.PathParam
;
import javax
.websocket
.server
.ServerEndpoint
;
import java
.io
.IOException
;
import java
.util
.HashMap
;
import java
.util
.Map
;
import java
.util
.concurrent
.CopyOnWriteArraySet
;
public class WebSocketHandler implements org.springframework.web.socket.WebSocketHandler {
private static Map
<Integer
, CopyOnWriteArraySet
<WebSocketSession>> SERVER_MAP
= new HashMap<>();
private int projectId
;
@Override
public void afterConnectionEstablished(WebSocketSession session
){
String url
= session
.getUri().toString();
projectId
= Integer
.parseInt(url
.substring(url
.lastIndexOf("/")+1));
CopyOnWriteArraySet
<WebSocketSession> sessionSet
= SERVER_MAP
.get(projectId
);
if (sessionSet
!= null
){
sessionSet
.add(session
);
}else {
sessionSet
= new CopyOnWriteArraySet<>();
sessionSet
.add(session
);
SERVER_MAP
.put(projectId
,sessionSet
);
}
StaticLog
.info(session
+"连接成功,在线数量: "+SERVER_MAP
.get(projectId
).size());
}
@Override
public void afterConnectionClosed(WebSocketSession session
, CloseStatus status
) throws Exception
{
SERVER_MAP
.forEach((k
,v
)->v
.remove(session
));
StaticLog
.info(session
+"关闭连接,在线数量: "+SERVER_MAP
.get(projectId
).size());
}
@Override
public boolean supportsPartialMessages() {
return false;
}
@Override
public void handleMessage(WebSocketSession webSocketSession
, WebSocketMessage
<?> webSocketMessage
) throws Exception
{
SERVER_MAP
.forEach((k
,v
)->{
v
.forEach(s
->{
try {
s
.sendMessage(new TextMessage(webSocketMessage
.getPayload().toString()));
} catch (IOException e
) {
e
.printStackTrace();
}
});
});
}
@Override
public void handleTransportError(WebSocketSession session
, Throwable exception
) {
StaticLog
.error(session
+",发生错误");
}
public static void send(int projectId
,String message
) {
CopyOnWriteArraySet
<WebSocketSession> set
= SERVER_MAP
.get(projectId
);
set
.forEach(x
->{
try {
x
.sendMessage(new TextMessage(message
));
StaticLog
.info("{} sendMessage: {}",projectId
,message
);
} catch (IOException e
) {
e
.printStackTrace();
}
});
}
}
websocket拦截器
package com
.jx
.smart
.fly
.common
.websocket
;
import cn
.hutool
.core
.util
.StrUtil
;
import cn
.hutool
.log
.StaticLog
;
import com
.jx
.smart
.fly
.module
.mapper
.LaborProjectConfigMapper
;
import com
.jx
.smart
.common
.model
.labor
.attendance
.project
.LaborProjectConfigModel
;
import org
.springframework
.http
.server
.ServerHttpRequest
;
import org
.springframework
.http
.server
.ServerHttpResponse
;
import org
.springframework
.http
.server
.ServletServerHttpRequest
;
import org
.springframework
.web
.socket
.WebSocketHandler
;
import org
.springframework
.web
.socket
.server
.HandshakeInterceptor
;
import java
.util
.Map
;
public class WebSocketInterceptor implements HandshakeInterceptor {
private LaborProjectConfigMapper laborProjectConfigMapper
;
public WebSocketInterceptor(){
}
public WebSocketInterceptor(LaborProjectConfigMapper laborProjectConfigMapper
){
this.laborProjectConfigMapper
= laborProjectConfigMapper
;
}
@Override
public boolean beforeHandshake(ServerHttpRequest serverHttpRequest
, ServerHttpResponse serverHttpResponse
, WebSocketHandler webSocketHandler
, Map
<String, Object> map
) throws Exception
{
if (serverHttpRequest
instanceof ServletServerHttpRequest){
String url
= serverHttpRequest
.getURI().toString();
String projectId
= url
.substring(url
.lastIndexOf("/")+1);
if (StrUtil
.isNotBlank(projectId
)){
LaborProjectConfigModel model
= laborProjectConfigMapper
.selectById(Integer
.parseInt(projectId
));
if (model
!= null
){
return true;
}else {
StaticLog
.error("非法请求 : projectId = {}",projectId
);
}
}else {
StaticLog
.error("projectId不能为空");
}
}
return false;
}
@Override
public void afterHandshake(ServerHttpRequest serverHttpRequest
, ServerHttpResponse serverHttpResponse
, WebSocketHandler webSocketHandler
, Exception e
) {
}
}
前端
这里需要后端去配合,发送心跳,后端需要回心跳包
<template>
</template>
<script>
import audio from '../../assets/music/791865496.mp3';
export default {
name: "Audio",
data(){
return {
ws:null,
audio:null,
playing:false,
task1:null,
task2:null,
count:0
}
},
methods:{
initWebSocket:function () {
if(typeof(WebSocket) === "undefined"){
alert("您的浏览器不支持websocket")
}else {
this.ws = new WebSocket("ws:127.0.0.1:2021/websocket/ai");
this.ws.onopen = this.open;
this.ws.onerror = this.error;
this.ws.onmessage = this.getMessage;
this.ws.onclose = this.close;
}
},
open: function () {
console.log("[ws] 连接成功");
},
error: function () {
console.log("[ws] 连接错误");
},
getMessage: function (msg) {
let obj = JSON.parse(msg.data);
if (obj === "heart") {
window.clearInterval(this.task2);
this.task2 = null;
this.count = 0;
console.log("[ws] 收到心跳");
}else {
this.playAudio();
}
},
send: function (message) {
if(this.ws.readyState === WebSocket.OPEN){
this.ws.send(JSON.stringify(message));
}
},
close: function () {
console.log("[ws] 已经关闭");
},
heart:function () {
console.log("[ws] 发送心跳");
this.count++;
this.send("heart");
},
reconnection:function () {
if (this.ws.readyState === WebSocket.CLOSED){
console.log("[ws] 正在尝试重连");
this.initWebSocket();
}
},
initAudio:function(){
this.audio = new Audio(audio);
this.audio.onended = this.onEnded;
this.audio.onplay = this.onPlay;
},
playAudio:function () {
if(!this.playing){
this.audio.play();
}
},
onPlay:function () {
this.playing = true;
},
onEnded:function () {
this.playing = false;
}
},
watch:{
"count":function (e) {
if (e >= 10 && this.task2 == null){
this.task2 = window.setInterval(this.reconnection, 3000);
}
}
},
created: function () {
this.initAudio();
this.initWebSocket();
this.task1 = window.setInterval(this.heart, 3000);
},
destroyed :function () {
this.ws.close();
window.clearInterval(this.task1);
window.clearInterval(this.task2);
}
}
</script>
<style scoped>
</style>