spring集成webscoket
spring集成webscoket
1.后端代码
消息编码类
public class EquipEncoder implements javax.websocket.Encoder.Text<Object> {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void init(EndpointConfig arg0) {
// TODO Auto-generated method stub
}
@Override
public String encode(Object o) throws EncodeException {
return JSON.toJSONString(o);
}
}
消息解码类
public class EquipEncoder implements javax.websocket.Encoder.Text<Object> {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void init(EndpointConfig arg0) {
// TODO Auto-generated method stub
}
@Override
public String encode(Object o) throws EncodeException {
return JSON.toJSONString(o);
}
}
上面两个类测试下来好像没什么用处
websocket配置类
@Component
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
核心代码,onMessage接收前端发来的消息,sendToOne发送消息给前端,wid为前后端websocket连接的唯一标识(每个连接标识都必须唯一,可采取前端生成时间戳的方式,相同的会被后面的顶掉)
@Slf4j
@Component
@ServerEndpoint(value = "/websocket/{wid}", encoders = {EquipEncoder.class}, decoders = {EquipDecoder.class})
public class WebSocket {
private Session session;
/**
* 用来记录当前在线连接数
*/
private static AtomicInteger onlineCnt = new AtomicInteger();
//定义 ConcurrentHashMap 存储用户编号和用户会话
private static ConcurrentHashMap<String, Session> sessionPools = new ConcurrentHashMap<String, Session>();
/**
* 连接建立成功调用的方法
*
* @param session
*/
@OnOpen
public void onOpen(Session session, @PathParam(value = "wid") String wid) {
log.info("有新的连接,wid={},session:{}", wid, session);
if (sessionPools.containsKey(wid)) {
sessionPools.remove(wid);
sessionPools.put(wid, session);
} else {
sessionPools.put(wid, session);
addOnlineCount();
}
log.info("总连接数:{}", onlineCnt);
}
/**
* 连接断开调用的方法
*/
@OnClose
public void onClose(@PathParam(value = "wid") String wid) {
if (sessionPools.containsKey(wid)) {
sessionPools.remove(wid);
subOnlineCount();
}
log.info("有新的断开:{}", wid);
log.info("总连接数:{}", onlineCnt);
}
/**
* 收到客户端消息后调用的方法
*
* @param message
* @param wid
*/
@OnMessage
public void onMessage(String message, @PathParam(value = "wid") String wid) {
log.info("收到客户端={},消息:{}", wid, message);
JSONObject jsonObject = JSONObject.parseObject(message);
//如果有flag说明是心跳检测机制
if (jsonObject.containsKey("heart")) {
sendToOne(message, wid);
} else {//没有说明是前端给后端发消息
System.out.println("收到前端发送过来的消息:" + message);
}
}
/**
* 发送字符串
*
* @param message
*/
public void sendToOne(String message, @PathParam(value = "wid") String wid) {
Session session = sessionPools.get(wid);
if (StringUtils.isNotNull(session)) {
try {
session.getBasicRemote().sendText(message);
log.info("message:{},wid:{}", message, wid);
} catch (IOException e) {
log.error("sendToOne error,wid:{},message:{}", wid, message, e);
}
}
}
/**
* 全部发送
*
* @param message
*/
public void sendAll(String message) {
for (Session session : sessionPools.values()) {
try {
sendMessage(session, message);
log.info("session:{},message:{}", session, message);
} catch (Exception e) {
log.error("sendAll error");
continue;
}
}
}
/**
* 发送消息方法
*
* @param session 客户端与socket建立的会话
* @param message 消息
* @throws IOException
*/
public void sendMessage(Session session, String message) throws IOException {
if (StringUtils.isNotNull(session)) {
session.getBasicRemote().sendText(message);
}
}
/**
* 发送对象
*
* @param obj
*/
public void send(Object obj, @PathParam(value = "wid") String wid) {
Session session = sessionPools.get(wid);
if (StringUtils.isNotNull(session)) {
try {
session.getBasicRemote().sendObject(obj);
} catch (IOException e) {
log.error("sendToOne error,wid:{},message:{}", wid, obj.toString(), e);
} catch (EncodeException e) {
log.error("sendToOne error,wid:{},message:{}", wid, obj.toString(), e);
}
}
}
/**
* 增加在线数量
*/
private static void addOnlineCount() {
onlineCnt.incrementAndGet();
}
/**
* 减少在线数量
*/
private static void subOnlineCount() {
onlineCnt.decrementAndGet();
}
}
测试类
@Slf4j
@Api(tags = "websocket相关")
@RestController
@RequestMapping("/manage/websocket")
public class WebsocketTestController {
@Autowired
private WebSocket webSocket;
@ApiOperation(value = "发送给指定连接", notes = "发送给指定连接")
@PostMapping("/sendToOne/{wid}")
public void sendToOne(@RequestBody JSONObject message, @PathVariable(value = "wid") String wid) {
webSocket.sendToOne(message.toString(), wid);
}
}
2.前端代码
<template>
<div class="login">
{{ value }}
</div>
</template>
<script>
const heartCheck = {
timeout: 60 * 1000,
timer: null,
serverTimer: null,
reset() {
this.timer && clearTimeout(this.timer);
this.serverTimer && clearTimeout(this.serverTimer);
},
start(ws) {
this.reset();
this.timer = setTimeout(() => {
// onmessage拿到返回的心跳就说明连接正常
ws.send(JSON.stringify({ heart: 1 }));
this.serverTimer = setTimeout(() => {
// 如果超过一定时间还没响应(响应后触发重置),说明后端断开了
ws.close();
}, this.timeout);
}, this.timeout);
},
};
export default {
name: "Login",
data() {
return {
value: null,
};
},
created() {
this.initWebSocket();
},
methods: {
//******************websocket相关*****************************//
reconnect() {
if (this.lockReconnect || this.maxReconnect <= 0) {
return;
}
setTimeout(() => {
// this.maxReconnect-- // 不做限制 连不上一直重连
console.log("首页ws尝试重连");
this.initWebSocket();
}, 15 * 1000);
},
initWebSocket() {
try {
if ("WebSocket" in window) {
let SESSION_FLAG = "currentTimestamp";
let currentTimestamp = this.$cache.session.get(SESSION_FLAG);
if (!currentTimestamp) {
//
this.$cache.session.set(SESSION_FLAG, new Date().getTime());
currentTimestamp = sessionStorage.getItem(SESSION_FLAG);
console.log(
"===初次登陆为ws创建全局事件戳,用于当前ws===",
currentTimestamp
);
}
var wsUrl =
"ws://localhost:8080/websocket/wjAlarm123" + currentTimestamp;
console.log("wsUrl==>" + wsUrl);
this.socket = new WebSocket(wsUrl);
} else {
console.log("您的浏览器不支持websocket");
}
this.socket.onopen = this.websocketonopen;
this.socket.onerror = this.websocketonerror;
this.socket.onmessage = this.websocketonmessage;
this.socket.onclose = this.websocketclose;
} catch (e) {
this.reconnect();
console.log("首页WebSocket发生错误", e);
}
},
websocketonopen() {
console.log("首页WebSocket连接成功", this.socket.readyState);
heartCheck.start(this.socket);
// this.socket.send('发送数据')
this.websocketsend();
},
websocketonerror(e) {
console.log("首页WebSocket连接发生错误", e);
// this.reconnect()
},
//方法接收后台发过来的数据
websocketonmessage(e) {
var msgData = JSON.parse(e.data);
if (msgData) {//msgData不为null的意思
// 消息获取成功,重置心跳
heartCheck.start(this.socket);
}
console.log("接收到消息");
//如果不是心跳检测包
if (!msgData.heart) {
console.log("websocketonmessage==msgData==", msgData);
this.value = msgData;
}
},
websocketclose(e) {
console.log("首页connection closed (" + e.code + ")");
this.reconnect();
},
//前台给后台发送数据
websocketsend() {
let data = { heart: 1 };
this.socket.send(JSON.stringify(data));
},
destroyed() {
heartCheck.reset();
this.socket.close();
},
},
};
</script>
<style rel="stylesheet/scss" lang="scss">
</style>