小知識,大挑戰!本文正在參與「程式員必備小知識」創作活動
本文已參與「掘力星計劃」,贏取創作大禮包,挑戰創作激勵金,
前言:(本文用于輔助Flutter WebSocket的理解) 在這個假期,我完成了一個小Demo,Flutter 與 Springboot 進行websocket的通訊,為啥想要去做這個Demo呢,主要是在各大平臺以及google搜索后發現,沒有一個詳細的例子來教大家進行一對一、一對多的通訊,大多數都是教你怎么連接,卻沒有教你怎么去進行下一步的功能實作,于是我利用了五天的假期,踩了無數的坑,終于是完成了它,所以,點個贊吧,不容易啊,兄弟們😭
原始碼在文章最后,直接運行就完事,前端界面也寫好了,如果想要移動端的效果的話需要使用Flutter😎
Flutter移動端分析:Flutter WebSocket 即時通訊
先上效果圖(我自己搜索這樣功能性的問題時,沒有效果圖基本上都是不想看的):

這個效果圖為Flutter:

即時通訊最重要的功能是完成了(發送文字資訊)
閱讀本文的注意點:
本文參考https://www.zhihu.com/column/p/32282342,在其基礎上進行二次開發
1.需要一點WebSocket的原理知識
2.springboot使用WebSocket的方法,本章就是最普通的原生方法
WebSocket的原理知識在Flutter WebSocket這篇文章中已經講了,這里就不再重復了
正文:
1.Springboot使用WebSocket的方法
https://juejin.cn/post/6844903976727494669 掘金里已經有大神詳細的講解了
這里推薦spring封裝或者STOMP兩種方式
講幾個注意的點(詳細的步驟掘金里的大神都已經寫過啦~):
- pom.xml 配置websocket
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
如果需要用戶存盤功能可以使用Spring Security,用戶授權非常方便
- STOMP這個協議是非常優秀的,是一種簡單的基于文本的訊息傳遞協議
如果想學習的,我推薦這篇大佬的文章:https://juejin.cn/post/6844903856413868040
2.Springboot實作點對點通信
現在步入正文
-
配置pom.xml
在默認的環境下,加上一個websocket即可,這里使用的是JDK8
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
?
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
-
封裝前端傳入的資訊,以及return的值:
因為使用json進行訊息的發送,所以需要先創建一個訊息物件,包含了訊息發送者,訊息接受者,訊息型別
//資料型別 public class SocketMsg { private int type;//聊天型別0:群聊,1:單聊. private String fromUser;//發送者. private String toUser;//接受者. private String msg;//訊息 ? ...省略了get 和 set方法,不想寫的話可以嘗試lombook } -
WebSocketConfig處理
這里就簡單舉了個例子,文章中其實沒有怎么用到
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
?
@Configuration
public class WebSocketConfig {
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
// ws 傳輸資料的時候,資料過大有時候會接收不到,所以在此處設定bufferSize
container.setMaxTextMessageBufferSize(512000);
container.setMaxBinaryMessageBufferSize(512000);
container.setMaxSessionIdleTimeout(15 * 60000L);
return container;
}
}
-
最重要的內容,邏輯處理部分MyWebSocket來啦!
-
設定websocket連接點映射:
@ServerEndpoint(value = "/websocket/{nickname}")
- 我們需要一個變數來存盤每個客戶端對應的MyWebSocket物件.
private static CopyOnWriteArraySet<MyWebSocket> webSocketSet = new CopyOnWriteArraySet<MyWebSocket>();
一個變數用來記錄sessionId和該session之間的系結關系.
private static Map<String, Session> map = new HashMap<String, Session>();
- 成功建立連接時
@OnOpen
public void onOpen(Session session, @PathParam("nickname") String nickname) {
this.session = session;
this.nickname = nickname;
map.put(session.getId(), session);
webSocketSet.add(this);//加入set中.
this.session.getAsyncRemote().sendText(nickname + "上線了,(我的頻道號是" + session.getId() + ")");
}
- 收到客戶端訊息后呼叫
@OnMessage
public void onMessage(String message, Session session, @PathParam("nickname") String nickname) {
//message 不是普通的string ,而是我們定義的SocketMsg json字串.
try {
SocketMsg socketMsg = new ObjectMapper().readValue(message, SocketMsg.class);
//一對一聊天
if (socketMsg.getType() == 1) {
//只需要找到發送者和接受者即可.
socketMsg.setFromUser(session.getId());//發送者.
//socketMsg.setToUser(toUser);//這個是由客戶端進行設定.
Session fromSession = map.get(socketMsg.getFromUser());
Session toSession = map.get(socketMsg.getToUser());
if (toSession != null) {
//發送訊息
fromSession.getAsyncRemote().sendText(nickname + ":" + socketMsg.getMsg());
toSession.getAsyncRemote().sendText(nickname + ":" + socketMsg.getMsg());
} else {
fromSession.getAsyncRemote().sendText("系統訊息:對方不在線或者您輸入的頻道號有誤");
}
} else {
//群發給每個客戶端
broadcast(socketMsg, nickname);
}
} catch (JsonParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JsonMappingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
- 發生錯誤時
public void one rror(Session session, Throwable error) {
System.out.println("發生錯誤");
error.printStackTrace();
}
-
如果選擇群發時(每個在線的客戶都可以收到資訊)
private void broadcast(SocketMsg socketMsg, String nickname) { for (MyWebSocket item : webSocketSet) { //發送訊息. item.session.getAsyncRemote().sendText(nickname + ":" + socketMsg.getMsg()); } }
-
連接關閉
@OnClose public void onClose(Session session) { webSocketSet.remove(this);//從set中移除. map.remove(session.getId()); }
使用原始碼時注意,本章使用JDK8,websocket的版本可能略有不同,埠為9090,具體的使用方法可以參考Flutter WebSocket的文章最后~
原始碼地址看評論區😘
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/307349.html
標籤:其他
