所需依賴
<!-- websocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.7.0</version>
</dependency>
實體類
import lombok.Data;
@Data
public class NoticeWebsocketResp {
//通知類型
private String noticeType;
//通知内容
private Object noticeInfo;
}
保持連接配接的Bean
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();
}
}
配置類
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
@Component
@ServerEndpoint(value = "/SetRulesLogsend/{buildingId}")
public class SetRulesLogSocket { //記錄連接配接的用戶端
public static Map<String, Session> clients = new ConcurrentHashMap<>();
/**
* buildingId關聯sid(解決同一使用者id,在多個web端連接配接的問題)
*/
public static Map<String, Set<String>> conns = new ConcurrentHashMap<>();
private String sid = null;
private String buildingId;
/**
* 連接配接成功後調用的方法
* @param session
* @param buildingId
*/
@OnOpen
public void onOpen(Session session, @PathParam("buildingId") String buildingId) {
this.sid = UUID.randomUUID().toString();
this.buildingId = buildingId;
clients.put(this.sid, session);
Set<String> clientSet = conns.get(buildingId);
if (clientSet==null){
clientSet = new HashSet<>();
conns.put(buildingId,clientSet);
}
clientSet.add(this.sid);
log.info(this.sid + "連接配接開啟!");
}
/**
* 連接配接關閉調用的方法
*/
@OnClose
public void onClose() {
log.info(this.sid + "連接配接斷開!");
clients.remove(this.sid);
}
/**
* 判斷是否連接配接的方法
* @return
*/
public static boolean isServerClose() {
if (SetRulesLogSocket.clients.values().size() == 0) {
log.info("已斷開");
return true;
}else {
log.info("已連接配接");
return false;
}
}
/**
* 發送給所有使用者
* @param noticeType
*/
public static void sendMessage(String noticeType){
NoticeWebsocketResp noticeWebsocketResp = new NoticeWebsocketResp();
noticeWebsocketResp.setNoticeType(noticeType);
sendMessage(noticeWebsocketResp);
}
/**
* 發送給所有使用者
* @param noticeWebsocketResp
*/
public static void sendMessage(NoticeWebsocketResp noticeWebsocketResp){
String message = JSONObject.toJSONString(noticeWebsocketResp);
for (Session session1 : SetRulesLogSocket.clients.values()) {
try {
session1.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 根據buildingId-id發送給某一個使用者
* **/
public static void sendMessageBybuildingId(String buildingId, NoticeWebsocketResp noticeWebsocketResp) {
if (!StringUtils.isEmpty(buildingId)) {
String message = JSONObject.toJSONString(noticeWebsocketResp);
Set<String> clientSet = conns.get(buildingId);
if (clientSet != null) {
Iterator<String> iterator = clientSet.iterator();
while (iterator.hasNext()) {
String sid = iterator.next();
Session session = clients.get(sid);
if (session != null) {
try {
session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
/**
* 收到用戶端消息後調用的方法
* @param message
* @param session
*/
@OnMessage
public void onMessage(String message, Session session) {
log.info("收到來自項目"+this.buildingId+"的資訊:"+message);
}
/**
* 發生錯誤時的回調函數
* @param error
*/
@OnError
public void onError(Throwable error) {
log.info("錯誤");
error.printStackTrace();
}
}
測試類
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.iot.base.entity.SetRulesLog;
import com.iot.base.service.ISetRulesLogService;
import com.iot.common.api.ApiResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Slf4j
@RestController
public class wsController {
@Autowired
private ISetRulesLogService setRulesLog;
@Autowired
private SetRulesLogSocket socket;
@GetMapping("/test")
public ApiResult test() {
//擷取需要的資料通過sendMessageBybuildingId類發送給對應的會話
List<SetRulesLog> list = setRulesLog.list(Wrappers.<SetRulesLog>lambdaQuery().eq(SetRulesLog::getReadStatus, 0));
Map<String, List<SetRulesLog>> collect = list.stream().collect(Collectors.groupingBy(SetRulesLog::getBuildId));
collect.forEach((k,v)->{
NoticeWebsocketResp noticeWebsocketResp = new NoticeWebsocketResp();
noticeWebsocketResp.setNoticeType(k);
noticeWebsocketResp.setNoticeInfo(v);
socket.sendMessageBybuildingId(k,noticeWebsocketResp);
});
return ApiResult.ok();
}
}
前端代碼
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>My WebSocket</title>
<style>
#message{
margin-top: 40px;
border: 1px solid gray;
padding:20px;
}
</style>
</head>
<body>
<button onclick="conectWebSocket()">連接配接WebSocket</button>
<button onclick="closeWebSocket()">斷開連接配接</button>
<hr />
<br />
消息:<input id="text" type="text" />
<button onclick="send()">發送消息</button>
<div id="message"></div>
</body>
<script type="text/javascript">
var websocket = null;
function conectWebSocket(){
//判斷目前浏覽器是否支援WebSocket
if ('WebSocket'in window) {
// 連接配接資訊 我的兩個測試頁面隻有該處不同
//websocket = new WebSocket("ws://localhost:8082/SetRulesLogsend/7");
websocket = new WebSocket("ws://localhost:8082/SetRulesLogsend/8");
} else {
alert('Not support websocket')
}
//連接配接發生錯誤的回調方法
websocket.onerror = function() {
setMessageInnerHTML("error");
};
//連接配接成功建立的回調方法
websocket.onopen = function(event) {
setMessageInnerHTML("Loc MSG: 成功建立連接配接");
}
//接收到消息的回調方法
websocket.onmessage = function(event) {
setMessageInnerHTML(event.data);
}
//連接配接關閉的回調方法
websocket.onclose = function() {
setMessageInnerHTML("Loc MSG:關閉連接配接");
}
//監聽視窗關閉事件,當視窗關閉時,主動去關閉websocket連接配接,防止連接配接還沒斷開就關閉視窗,server端會抛異常。
window.onbeforeunload = function() {
websocket.close();
}
}
//将消息顯示在網頁上
function setMessageInnerHTML(innerHTML) {
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
//關閉連接配接
function closeWebSocket() {
websocket.close();
}
//發送消息
function send() {
var message = document.getElementById('text').value;
websocket.send(message);
}
</script>
</html>
測試結果: