WebSocket-java篇

問題引入

消息推送的方式

我們要實現,服務器把消息推送到客戶端,可以輪訓,長輪訓

還有sse

WebSocket理論

WebSocket 的由來與核心價值

  • 誕生背景:解決 HTTP 協議在實時通信中的固有缺陷(單向請求-響應模式)

  • 核心驅動力

    • 替代低效輪詢(Polling)和長輪詢(Comet)

    • 滿足實時應用需求(聊天、金融行情、游戲等)

  • 核心優勢

    • 全雙工通信:客戶端/服務器可同時發送數據

    • 低延遲:從 HTTP 的數百 ms 降至 10-50ms

    • 高效傳輸:頭部開銷僅 2-14 字節(vs HTTP 的數百字節)

  • 標準化:2011 年 RFC 6455 成為正式標準

WebSocket 協議核心組成

組成部分作用必要性
握手階段通過 HTTP 協議升級協商(101 Switching Protocols)切換到 WebSocket 協議兼容現有網絡基礎設施(代理、防火墻)
數據幀傳輸應用數據(文本/二進制)封裝數據,支持分片傳輸大文件
控制幀管理連接狀態(Ping/Pong 保活、Close 關閉)維持連接健康,避免資源泄漏
掩碼機制客戶端發送數據時進行 XOR 掩碼加密防止惡意代理緩存污染(安全關鍵)
Opcode標識幀類型(文本/二進制/控制幀)正確解析消息內容
Payload Length動態長度標識(7/16/64位)支持從短消息到 GB 級大文件傳輸

Spring Boot 深度集成方案

基礎架構

核心組件詳解

  1. Client(客戶端)

    • 作用:發起連接、訂閱頻道、收發消息

    • 為什么需要:作為通信的終端用戶界面

    • 解決問題

      • 提供用戶交互入口

      • 實現跨平臺通信(Web/App/桌面)

    • 技術實現

      const socket = new WebSocket("ws://yourdomain/ws-endpoint");
      socket.onmessage = (event) => {console.log("收到消息:", event.data);
      };

  2. Endpoint(連接端點)

    • 作用:處理握手請求,建立持久連接

    • 為什么需要:作為WebSocket連接的入口網關

    • 解決問題

      • 協議升級(HTTP→WebSocket)

      • 連接生命周期管理

      • 跨域處理(CORS)

    • Spring Boot實現

      @Configuration
      @EnableWebSocketMessageBroker
      public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {registry.addEndpoint("/ws-endpoint").setAllowedOrigins("*").withSockJS(); // 瀏覽器兼容方案}
      }

  3. WebSocket Connection(連接管道)

    • 作用維護全雙工通信通道

    • 為什么需要:突破HTTP的無狀態限制

    • 解決問題

      • 避免頻繁握手(單次握手持久連接)

      • 支持雙向實時通信

      • 降低延遲(從HTTP的300ms+降至30ms內)

  4. Message Broker(消息代理)

    • 作用:消息路由、分發、存儲

    • 為什么需要:解耦生產者和消費者

    • 解決問題

      • 海量連接下的消息分發

      • 分布式系統擴展

      • 消息持久化與重試

    • 配置示例

      @Override
      public void configureMessageBroker(MessageBrokerRegistry registry) {// 使用外部消息中間件registry.enableStompBrokerRelay("/topic", "/queue").setRelayHost("rabbitmq-host").setRelayPort(61613);
      }

  5. 頻道系統(路由核心)

    頻道類型前綴作用解決的問題消息流向
    廣播頻道/topic公共消息廣播1:N 消息分發 (如聊天室公告)發布者 → 所有訂閱者
    私有隊列/queue點對點通信1:1 精準投遞 (如訂單通知)發布者 → 特定訂閱者
    用戶頻道/user用戶級隔離多設備同步 (如微信網頁/App同時在線)發布者 → 用戶所有會話
  6. @MessageMapping Controller(業務處理器)

    • 作用:處理業務邏輯,生成響應

    • 為什么需要:分離通信協議與業務邏輯

    • 解決問題

      • 業務邏輯集中管理

      • 消息驗證與轉換

      • 數據庫/服務集成

    • 示例

      @MessageMapping("/trade")
      @SendTo("/topic/stock-updates")
      public StockUpdate handleTrade(Order order) {// 1. 驗證訂單// 2. 執行交易// 3. 生成市場數據更新return tradingService.execute(order);
      }

架構演進價值

  1. 協議層優化

    • 替代方案對比:

      方案延遲開銷雙向通信頻道支持
      HTTP輪詢300ms+??
      WebSocket基礎50ms???
      WS+STOMP30ms????
  2. 工程化價值

  3. 業務場景適配

    • 廣播場景:/topic/news(新聞推送)

    • 私有場景:/queue/user-123/notifications(個人通知)

    • 混合場景:/topic/room-{id} + /user/queue/private(在線教育平臺)

總結:為什么需要此架構

  1. 連接管理 通過Endpoint統一處理握手/斷開,解決連接生命周期管理混亂問題

  2. 消息路由 頻道系統實現發布-訂閱模式,解決海量消息精準投遞問題

  3. 業務解耦 控制器隔離業務邏輯與通信協議,解決代碼維護困難問題

  4. 水平擴展 消息代理支持集群部署,解決單點性能瓶頸問題

  5. 安全管控 頻道級權限控制,解決敏感數據泄露風險

終極價值:此架構在協議層實現高效實時通信,在架構層通過頻道機制解決復雜業務場景的消息路由問題,在工程層通過Spring Boot實現企業級標準化,是構建現代實時應用的基石。

原理流程

在我的E盤的WebSocket文件夾

消息執行流程(Flow)概覽

建立連接(connect,連接)

Client(客戶端)發起到 /ws-endpoint 的 WebSocket 握手(handshake,握手),Endpoint(端點)完成升級后建立 WebSocket Connection(WebSocket 連接)。

訂閱頻道(subscribe,訂閱)

Client 通過 STOMP 向 broker 發送 SUBSCRIBE Frame(訂閱幀),表示“我要訂閱 /topic/greetings”。

發送消息到 Controller(SEND Frame)

Client 發送 SEND Frame(發送幀),destination(目的地)為 /app/hello

Broker 根據 setApplicationDestinationPrefixes("/app"),將消息路由(route,路由)給匹配 @MessageMapping("/hello") 的方法

Controller(控制器)處理

GreetingController.handleHello(...) 被調用(invoke,調用),執行業務邏輯,返回 Greeting 對象。

Broker(代理)轉發

因為方法上有 @SendTo("/topic/greetings"),返回值被封裝成 MESSAGE Frame(消息幀)發送給 Broker(消息代理)。

Broker 將該消息分發(dispatch,分發)給所有訂閱(subscription,訂閱)了 /topic/greetings 的客戶端 session。

Client(客戶端)接收(receive,接收)

Client 在訂閱回調(callback,回調)中拿到服務器推送(push,推送)的消息并渲染到頁面。

這就是完整的一次流程。

API

客戶端

websocket對象創建

let ws = new WebSocket(URL);

URL說明

格式:協議://ip地址:端口/訪問路徑 協議:協議名稱為 ws

websocket對象相關事件

事件事件處理程序描述
openws.onopen連接建立時觸發
messagews.onmessage客戶端接收到服務器發送的數據時觸發
closews.onclose連接關閉時觸發

websocket對象提供的方法

方法名稱描述
send()通過websocket對象調用該方法發送數據給服務端

簡單示例

<script>
let ws = new WebSocket("ws://localhost/chat");
ws.onopen = function() {
};ws.onmessage = function(evt) {// 通過 evt.data 可以獲取服務器發送的數據
};ws.onclose = function() {
};
</script>

服務端

Tomcat的7.0.5版本開始支持WebSocket,并且實現了Java WebSocket規范。

Java WebSocket應用由一系列的Endpoint組成。Endpoint是一個java對象,代表WebSocket鏈接的一端,對于服務端,我們可以視為處理具體WebSocket消息的接口。

我們可以通過兩種方式定義Endpoint:

  • 第一種是編程式,即繼承類javax.websocket.Endpoint并實現其方法。

  • 第二種是注解式,即定義一個POJO,并添加@ServerEndpoint相關注解。

Endpoint實例在WebSocket握手時創建,并在客戶端與服務端鏈接過程中有效,最后在鏈接關閉時結束。在Endpoint接口中明確了與其生命周期相關的方法,規范實現者確保生命周期的各個階段調用實例的相關方法。生命周期方法如下:

方法描述注解
onOpen()當開啟一個新的會話時調用,該方法是客戶端與服務端握手成功后調用的方法@OnOpen
onClose()當會話關閉時調用@OnClose
onError()當連接過程異常時調用@OnError

服務端如何接收客戶端發送的數據呢?

  • 編程式 通過添加 MessageHandler 消息處理器來接收消息

  • 注解式 在定義 Endpoint 時,通過 @OnMessage 注解指定接收消息的方法

服務端如何推送數據給客戶端呢?

發送消息則由 RemoteEndpoint 完成,其實例由 Session 維護

發送消息有 2 種方式發送消息

  • 通過 session.getBasicRemote 獲取同步消息發送的實例,然后調用其 sendXxx() 方法發送消息

  • 通過 session.getAsyncRemote 獲取異步消息發送實例,然后調用其 sendXxx() 方法發送消息

@ServerEndpoint("/chat")
@Component
public class ChatEndpoint {@OnOpen// 連接建立時被調用public void onOpen(Session session, EndpointConfig config) {}@OnMessage// 接收到客戶端發送的數據時被調用public void onMessage(String message) {}@OnClose// 連接關閉時被調用public void onClose(Session session) {}
}

WebSocket 消息分發的三種常見模式

session.getAsyncRemote()(getBasicRemote).sendXxx() 方法本身并不直接區分這些模式,而是通過 目標地址(如 Session、Broadcast)應用層邏輯 來實現不同的消息分發方式。

WebSocket 消息分發的三種常見模式

1. 單播(Unicast)
  • 點對點發送:消息直接發送給某個特定的客戶端(Session)。

  • 實現方式:通過目標客戶端的 session.getAsyncRemote().sendText()

  • 示例:

    // 向特定客戶端發送消息
    targetSession.getAsyncRemote().sendText("Private message");

2. 廣播(Broadcast)
  • 一對多發送:消息發送給所有連接的客戶端(或特定分組)。

  • 實現方式:遍歷所有 Session 或使用 @ServerEndpoint 的全局集合。

  • 示例:

    // 廣播給所有客戶端
    for (Session session : allSessions) {session.getAsyncRemote().sendText("Broadcast message");
    }
  • 注意Java WebSocket API 本身不提供原生廣播方法,需自行維護 Session 集合。

3. 組播(Multicast)
  • 分組發送:消息發送給訂閱了特定主題(Topic)或頻道的客戶端。

  • 實現方式:通過應用層維護分組映射(如 Map<String, Set<Session>>)。

  • 示例:

    // 向訂閱了 "news" 頻道的客戶端發送消息
    for (Session session : channelSubscribers.get("news")) {session.getAsyncRemote().sendText("News update");
    }

總結
模式目標范圍實現關鍵適用場景
單播單個 Session直接調用目標 Session私聊、定向通知
廣播所有 Session遍歷全局 Session 集合公告、全局狀態更新
組播分組 Session維護分組映射(Topic → Sessions)頻道訂閱、房間聊天

WebSocket 的靈活性在于:sendXxx() 是工具,分發模式由開發者通過 Session 代碼管理邏輯實現

在線聊天室實現

具體代碼在learnWebSocket里面

流程分析

package com.learnwebsocket.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** @version v1.0* @ClassName: WebsocketConfig*/
@Configuration
public class WebsocketConfig {/*** 創建一個ServerEndpointExporter對象,這個對象會自動注冊使用了@ServerEndpoint注解的類* @return*/@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

后端

ServerEndpointExporter

首先,由于websocket不直接歸于spring管理,屬于spring的擴展模塊,所以為了把websocket的實例也注冊到spring里面,我們需要一個spring和websocket的連接橋梁。也就是ServerEndpointExporter。這個類負責加載websocket的端點。他同時可以被spring直接管理。

package com.learnwebsocket.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** @version v1.0* @ClassName: WebsocketConfig*/
@Configuration
public class WebsocketConfig {/*** 創建一個ServerEndpointExporter對象,這個對象會自動注冊使用了@ServerEndpoint注解的類* @return*/@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

端點Endpoint

然后。我們需要自己創建一個端點,供ServerEndpointExporter發現管理。

這里面我們需要實現三個方法,這個上面有講。

這里面還有廣播和單播的實現代碼,仔細看看。

還有的就是,由于Endpoint不直接屬于spring,若要給Endpoint去配置一些東西,我們需要手動創建一個類,實現java給我們的接口,來去配置之后給spring管理

package com.learnwebsocket.ws.pojo;import com.alibaba.fastjson.JSON;import com.learnwebsocket.config.GetHttpSessionConfig;
import com.learnwebsocket.utils.MessageUtils;
import org.springframework.stereotype.Component;import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;/*** @version v1.0* @ClassName: ChatEndpoint* @Description: 端點* @Author: 黑馬程序員*/
@ServerEndpoint(value = "/chat",configurator = GetHttpSessionConfig.class)
@Component
public class ChatEndpoint {// 用來保存所有的用戶private static final Map<String,Session> onlineUsers = new ConcurrentHashMap<>();//當前用戶對應的session對象private HttpSession httpSession;/*** 建立websocket連接后,被調用* @param session*/@OnOpenpublic void onOpen(Session session, EndpointConfig config) {//1,將session進行保存this.httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());String user = (String) this.httpSession.getAttribute("user");onlineUsers.put(user,session);//2,廣播消息。需要將登陸的所有的用戶推送給所有的用戶String message = MessageUtils.getMessage(true,null,getFriends());broadcastAllUsers(message);}public Set getFriends() {Set<String> set = onlineUsers.keySet();return set;}// 廣播所有用戶private void broadcastAllUsers(String message) {try {//遍歷map集合Set<Map.Entry<String, Session>> entries = onlineUsers.entrySet();for (Map.Entry<String, Session> entry : entries) {//獲取到所有用戶對應的session對象Session session = entry.getValue();//發送消息session.getBasicRemote().sendText(message);}} catch (Exception e) {//記錄日志}}/*** 瀏覽器發送消息到服務端,該方法被調用** 張三  -->  李四* @param message*/@OnMessagepublic void onMessage(String message) {try {//將消息推送給指定的用戶Message msg = JSON.parseObject(message, Message.class);//獲取 消息接收方的用戶名String toName = msg.getToName();String mess = msg.getMessage();//獲取消息接收方用戶對象的session對象Session session = onlineUsers.get(toName);String user = (String) this.httpSession.getAttribute("user");String msg1 = MessageUtils.getMessage(false, user, mess);session.getBasicRemote().sendText(msg1);} catch (Exception e) {//記錄日志}}/*** 斷開 websocket 連接時被調用* @param session*/@OnClosepublic void onClose(Session session) {//1,從onlineUsers中剔除當前用戶的session對象String user = (String) this.httpSession.getAttribute("user");onlineUsers.remove(user);//2,通知其他所有的用戶,當前用戶下線了String message = MessageUtils.getMessage(true,null,getFriends());broadcastAllUsers(message);}
}

配置類

上面的httpSession來自配置類的,因為登陸后我們把用戶的名字存到了httpSession。但是websocket無法直接獲取httpSession,所以要把它存到websocket配置文件里面。再獲取。

package com.learnwebsocket.config;import javax.servlet.http.HttpSession;
import javax.websocket.HandshakeResponse;
import javax.websocket.server.HandshakeRequest;
import javax.websocket.server.ServerEndpointConfig;/*** @version v1.0* @ClassName: GetHttpSessionConfig*/
public class GetHttpSessionConfig extends ServerEndpointConfig.Configurator {@Overridepublic void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request,HandshakeResponse response) {//獲取HttpSession對象HttpSession httpSession = (HttpSession) request.getHttpSession();//將httpSession對象保存起來sec.getUserProperties().put(HttpSession.class.getName(),httpSession);}
}

前端

先登陸之后,然后向后端的端點請求websocket的連接,之后綁定三個方法。

await axios.get("user/getUsername").then(res => {this.username = res.data;});//創建webSocket對象ws = new WebSocket("ws://localhost:8080/chat");//給ws綁定事件ws.onopen = this.onopen;//接收到服務端推送的消息后觸發ws.onmessage = this.onMessage;ws.onclose = this.onClose;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/95554.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/95554.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/95554.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

用Python從零開始實現神經網絡

反向傳播算法用于經典的前饋人工神經網絡。 它仍然是訓練大型深度學習網絡的技術。 在這個教程中&#xff0c;你將學習如何用Python從頭開始實現神經網絡的反向傳播算法。 完成本教程后&#xff0c;您將了解&#xff1a; 如何將輸入前向傳播以計算輸出。如何反向傳播錯誤和…

算法148. 排序鏈表

題目&#xff1a;給你鏈表的頭結點 head &#xff0c;請將其按 升序 排列并返回 排序后的鏈表 。示例 1&#xff1a;輸入&#xff1a;head [4,2,1,3] 輸出&#xff1a;[1,2,3,4] 示例 2&#xff1a;輸入&#xff1a;head [-1,5,3,4,0] 輸出&#xff1a;[-1,0,3,4,5] 示例 3&a…

在騰訊云CodeBuddy上實現一個AI聊天助手

在騰訊云CodeBuddy上實現一個AI聊天助手項目 在當今數字化時代&#xff0c;AI聊天助手已經成為一種非常流行的應用&#xff0c;廣泛應用于客戶服務、智能助手等領域。今天&#xff0c;我們將通過騰訊云CodeBuddy平臺&#xff0c;實現一個基于Spring Boot和OpenAI API的AI聊天助…

JavaScript Array.prototype.flatMap ():數組 “扁平化 + 映射” 的高效組合拳

在 JavaScript 數組處理中&#xff0c;我們經常需要先對每個元素進行轉換&#xff08;映射&#xff09;&#xff0c;再將結果 “鋪平”&#xff08;扁平化&#xff09;。比如將數組中的每個字符串按空格拆分&#xff0c;然后合并成一個新數組。傳統做法是先用map()轉換&#xf…

區塊鏈與元宇宙:數字資產的守護者

1 區塊鏈支撐元宇宙數字資產的底層邏輯1.1 不可篡改性構建信任基石區塊鏈的不可篡改性為元宇宙數字資產提供了堅實的信任基礎。其核心在于分布式賬本技術&#xff0c;當一筆數字資產交易發生時&#xff0c;會被打包成區塊并廣播至網絡中的所有節點。每個節點都會對這筆交易進行…

Linux軟件編程:進程和線程(進程)

進程一、基本概念進程&#xff1a;是程序動態執行過程&#xff0c;包括創建、調度、消亡程序&#xff1a;存放在外存的一段數據的集合二、進程創建&#xff08;一&#xff09;進程空間分布每個進程運行起來后&#xff0c;操作系統開辟0-4G的虛擬空間進程空間&#xff1a;用戶空…

Mybatis學習筆記(五)

分頁插件與性能優化 分頁插件配置 簡要描述&#xff1a;MybatisPlus分頁插件是基于物理分頁實現的高性能分頁解決方案&#xff0c;支持多種數據庫的分頁語法&#xff0c;能夠自動識別數據庫類型并生成對應的分頁SQL。 核心概念&#xff1a; 物理分頁&#xff1a;直接在SQL層面進…

企業可商用的conda:「Miniforge」+「conda-forge」

文章目錄一、徹底卸載現有 Anaconda/Miniconda二、安裝 Miniforge&#xff08;推薦&#xff09;macOS/Linux檢查Windows檢查三、將通道固定為 conda-forge&#xff08;嚴格優先&#xff09;四、驗證是否仍引用 Anaconda 源五、常見問題&#xff08;FAQ&#xff09;六、參考命令…

Flutter ExpansionPanel組件(可收縮的列表)

可以展開或者收縮的面板組件&#xff0c;收縮面板組件效果由ExpansionPanelList組件和ExpansionPanel組件共同完成。 ExpansionPanelList屬性說明屬性說明children子元素expansionCallback設置回調事件ExpansionPanel屬性說明headerBuilder收縮的標題body內容isExpanded設置內容…

C/C++ 進階:深入解析 GCC:從源碼到可執行程序的魔法四步曲

引言距離上一篇博客更新已經過去了大概一兩周的時間&#xff0c;而對于 Linux 系統的基本指令以及 Shell 編程的學習其實基本講解完畢&#xff0c;Linux基礎一塊的知識就將告一段落了&#xff0c;如果有細節性的知識&#xff0c;我也會及時分享給各位&#xff0c;作為一名正在攀…

云服務器運行持續強化學習COOM框架的問題

1 環境要求 下載地址&#xff1a;https://github.com/TTomilin/COOM tensorflow 2.11以上 python 3.9以上 tensorflow2.12.0&#xff0c;需要安裝tensorflow-probability0.19 2 修改代碼 COOM/wrappers/reward.py 將 from gym import RewardWrapper修改為 from gymnasium impor…

MyBatis Interceptor 深度解析與應用實踐

MyBatis Interceptor 深度解析與應用實踐 一、MyBatis Interceptor概述 1.1 什么是MyBatis Interceptor MyBatis Interceptor&#xff0c;也稱為MyBatis 插件&#xff0c;是 MyBatis 提供的一種擴展機制&#xff0c;用于在 MyBatis 執行 SQL 的過程中插入自定義邏輯。它類似…

【自動化測試】Web自動化測試 Selenium

&#x1f525;個人主頁&#xff1a; 中草藥 &#x1f525;專欄&#xff1a;【Java】登神長階 史詩般的Java成神之路 測試分類 了解各種各樣的測試方法分類&#xff0c;不是為了墨守成規按照既定方法區測試&#xff0c;而是已了解思維為核心&#xff0c;并了解一些專業名詞 根…

2025 電賽 C 題完整通關攻略:從單目標定到 2 cm 測距精度的全流程實戰

摘要 2025 年全國大學生電子設計競賽 C 題要求“僅用一顆固定攝像頭”在 5 s 內完成 100 cm~200 cm 距離、誤差 ≤2 cm 的單目測距&#xff0c;并實時顯示功耗。本文整合國一選手方案、CSDN 高分博文、B 站實測視頻及官方說明&#xff0c;給出從硬件選型→離線標定→在線算法→…

Day 10: Mini-GPT完整手寫實戰 - 從組件組裝到文本生成的端到端實現

Day 10-2: Mini-GPT完整手寫實戰 - 從組件組裝到文本生成的端到端實現 ?? 今日學習目標 掌握GPT架構組裝:將Transformer組件組裝成完整的生成模型 理解生成式預訓練:掌握自回歸語言建模的核心機制 端到端代碼實現:從數據預處理到模型訓練的完整流程 文本生成實戰:訓練Mi…

深入解析Prompt緩存機制:原理、優化與實踐經驗

深入解析Prompt緩存機制&#xff1a;原理、優化與實踐經驗 概述 在大型語言模型應用中&#xff0c;API請求的延遲和成本始終是開發者關注的核心問題。Prompt緩存&#xff08;Prompt Caching&#xff09;技術通過智能地復用重復內容&#xff0c;有效減少了API響應時間和運行成本…

CV 醫學影像分類、分割、目標檢測,之【3D肝臟分割】項目拆解

CV 醫學影像分類、分割、目標檢測&#xff0c;之【3D肝臟分割】項目拆解第1行&#xff1a;from posixpath import join第2行&#xff1a;from torch.utils.data import DataLoader第3行&#xff1a;import os第4行&#xff1a;import sys第5行&#xff1a;import random第6行&a…

Mybatis學習筆記(七)

Spring Boot集成 簡要描述&#xff1a;MyBatis-Plus與Spring Boot的深度集成&#xff0c;提供了自動配置、啟動器等特性&#xff0c;大大簡化了配置和使用。 核心概念&#xff1a; 自動配置&#xff1a;基于條件的自動配置機制啟動器&#xff1a;簡化依賴管理的starter配置屬性…

機器人伴侶的智能升級:Deepoc具身智能模型如何重塑成人伴侶體驗

引言&#xff1a;機器人伴侶市場的技術變革需求隨著人工智能技術的飛速發展和人們情感需求的多元化&#xff0c;機器人成人伴侶市場正在經歷前所未有的增長。傳統機器人伴侶已經能夠滿足基礎的交互需求&#xff0c;但在智能化、情感化和個性化方面仍存在明顯不足。這正是深算紀…

metabase基礎使用技巧 (dashboard, filter)

這是metabase系列分享文章的第2部分。本文將介紹metabase的基礎概念和使用介紹 question question是metabase中提供的通過UI化操作就能實現簡單的 快捷 直接的BI查詢。 點擊右側的New -> Question即可創建Question&#xff0c;可以理解為一個格式化的查詢&#xff1a; 這里…