第十篇:Spring Boot整合WebSocket
阿新 • • 發佈:2018-12-29
WebSocket是通過一個Socket來實現雙工非同步通訊的。直接使用WebSocket或者SockJS協議顯得特別繁瑣。使用它的子協議STOMP,它是一個更高級別的協議,STOMP協議使用一個基於幀格式來定義訊息,與HTTP的Request和Response類似。
環境依賴
Spring Boot對使用WebSocket提供了支援,配置原始碼在org.springframework.boot.autoconfigure.websocket包下。
<dependency>
<groupId>org.springframework.boot</ groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
順便說一句,springboot的高階元件會自動引用基礎的元件,像spring-boot-starter-websocket就引入了spring-boot-starter-web和spring-boot-starter,所以不要重複引入。
配置Websocket
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter (){
return new ServerEndpointExporter();
}
}
處理WebSocket
@ServerEndpoint("/websocket")
@Component
public class WebSocketService {
private final Logger log = LoggerFactory.getLogger(this.getClass());
private static int COUNT = 0;
private static CopyOnWriteArraySet<WebSocketService> websocket = new CopyOnWriteArraySet<WebSocketService>();
private Session session;
/*
建立連線的時候呼叫
*/
@OnOpen
public void onOpen(Session session) {
this.session = session;
websocket.add(this);
addOnlineCount();
log.info("當前線上人數:" + COUNT);
try {
sendMessage("連線成功");
} catch (IOException e) {
e.printStackTrace();
}
}
@OnClose
public void onclose() {
websocket.remove(this);
subOnlineCount();
log.info("有一連線關閉!當前線上人數為" + getOnlineCount());
}
/*
接收到客戶端的資訊
*/
@OnMessage
public void shoudaoMessage(String message, Session session) {
log.info("server 收到的資訊是:" + message);
//群發訊息
for (WebSocketService item : websocket) {
try {
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 發生錯誤時呼叫
*/
@OnError
public void onError(Session session, Throwable error) {
log.error("發生錯誤");
error.printStackTrace();
}
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/**
* 群發自定義訊息
*/
public static void sendInfo(String message) throws IOException {
for (WebSocketService item : websocket) {
try {
item.sendMessage(message);
} catch (IOException e) {
continue;
}
}
}
public static synchronized int getOnlineCount() {
return COUNT;
}
public static synchronized void addOnlineCount() {
WebSocketService.COUNT++;
}
public static synchronized void subOnlineCount() {
WebSocketService.COUNT--;
}
}
新建HTML檔案
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Title</title>
</head>
<body>
<input id="text" type="text" /><button onclick="send()">Send</button>
<button onclick="closeWebSocket()">Close</button>
<div id="message">
</div>
</body>
<script>
var websocket = null;
if('WebSocket' in window){
websocket = new WebSocket("ws://localhost:8080/websocket");
// 建立成功後的回撥函式
websocket.onopen = function (ev) {
setMessageInnerHTML("open");
}
websocket.onclose=function(){
setMessageInnerHTML("close");
}
websocket.onmessage=function (ev) {
setMessageInnerHTML(ev.data);
}
//監聽視窗關閉事件,當視窗關閉時,主動去關閉websocket連線,防止連線還沒斷開就關閉視窗,server端會拋異常。
window.onbeforeunload = function(){
websocket.close();
}
}else {
alert("瀏覽器不支援");
}
//將訊息顯示在網頁上
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>
伺服器推送
@RestController
public class WebSocketSendMessageController {
@Autowired
private WebSocketService socketService;
@GetMapping("/send")
public String sendMessage(){
try {
socketService.sendInfo("大家好");
} catch (IOException e) {
e.printStackTrace();
return "fail";
}
return "succcess";
}
}
測試
用瀏覽器開啟剛剛新建的html檔案
可以在多個視窗開啟,看看控制檯日誌資訊
傳送訊息
伺服器推送訊息
可以看到客戶端接受到了訊息