springboot集成websokcet+uniapp開發聊天原型驗證(一)

1. 整體思路

群組聊天功能實現思路
  • 需要為每個群組維護一個對應的集合(可以是?Set?等數據結構),用來存放該群組內所有在線用戶的?WebSocketSession。當有消息發送到群組時,遍歷該群組對應的集合,向其中的每個在線用戶發送消息。
  • 在消息結構體中新增一個字段用于標識所屬群組,以便后端根據這個字段來進行消息的廣播分發。
離線用戶處理及歷史消息推送思路
  • 對于離線用戶,當他們重新上線時,需要能夠識別出他們之前所在的群組(可以通過用戶登錄等操作記錄其關聯群組信息)。
  • 后端要將該群組在其離線期間產生的歷史消息查詢出來(這可能涉及到數據庫操作,將群組聊天消息存儲到數據庫中以便查詢歷史記錄),然后通過?WebSocket?連接將這些歷史消息逐一發送給重新上線的用戶。

后端代碼修改思路

1. 群組管理與消息處理

  • 群組數據結構:使用合適的數據結構(如?Map)來存儲群組相關信息,以群組 ID 作為鍵,對應的值可以是包含該群組內在線用戶?WebSocketSession?列表以及群組歷史消息列表等信息的對象。
  • 消息格式定義:明確消息的格式,使其能區分是文字消息還是圖片消息,并且包含必要的元數據,比如發送者、群組 ID、消息內容(文字內容或圖片鏈接等)、時間戳等。
  • 消息分發邏輯:當接收到消息時,根據消息中的群組 ID,找到對應的群組在線用戶列表,然后將消息發送給這些用戶。
2. 離線用戶歷史消息處理

  • 用戶與群組關聯記錄:維護用戶與所屬群組的關聯關系,比如使用?Map?存儲用戶 ID 和其所屬群組 ID 列表的對應關系,以便在用戶重新上線時確定需要推送哪些群組的歷史消息。
  • 歷史消息存儲與查詢:將群組內的聊天消息持久化存儲(實際應用中通常是存入數據庫,這里可簡單模擬存儲結構),當離線用戶重新上線時,從存儲結構中查詢出其所屬群組的歷史消息并推送給他。

直接 springboot+websokcet,感覺比原生的websocket簡單一點。

  1. ?集成websokcet
  2. ?配置文件
  3. ?handler
  4. postman測試一下
  5. ?uniapp

pom添加依賴:

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>

application.yml中 端口配置(先復用應用的端口吧)

server:port: 7877tomcat:accept-count: 10000threads:max: 800min-spare: 200compression:enabled: trueservlet:context-path: /chat

配置文件(application.yml)

  • 務器端口及相關配置
    • server.port?配置為?7877,指定了 Spring Boot 應用啟動后監聽的端口號。
    • server.tomcat.accept-count?設置為?10000,它表示當所有的處理線程都在使用時,能夠放到處理隊列中的連接請求數量。server.tomcat.threads.max?設為?800?定義了最大線程數,min-spare?設為?200?則是最小備用線程數,這些配置用于優化 Tomcat 處理請求的線程資源分配。
    • server.compression.enabled?設為?true,開啟了服務器響應內容的壓縮功能,有助于減少網絡傳輸的數據量,提高性能。
    • server.servlet.context-path?配置為?/chat,意味著應用的上下文路徑是?/chat,后續訪問應用中的資源路徑都是基于這個上下文路徑來構建的。

WebSocket 配置類(WebSocketConfig)

  • 這個類實現了?WebSocketConfigurer?接口,用于配置 WebSocket 相關的處理。
  • 在?registerWebSocketHandlers?方法中,將自定義的?MyWebSocketHandler?注冊到了 WebSocket 處理器注冊表?WebSocketHandlerRegistry?中,并且將 WebSocket 的端點路徑設置為?/websocket,同時允許來自任意源(setAllowedOrigins("*"))的連接訪問該 WebSocket 端點。
package com.edwin.java.config;import com.edwin.java.config.interceptor.GroupChatInterceptor;
import com.edwin.java.util.MyWebSocketHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {/*** registerWebSocketHandlers 是一個函數或方法,通常用于在 Web 應用程序中注冊 WebSocket 處理程序。* WebSocket 是一種基于 TCP 的協議,可以實現客戶端和服務器之間的雙向通信,可以用于實時應用程序,如聊天應用、游戲、實時更新等。在 Java Web 應用程序中,可以使用 Spring 框架提供的 WebSocket 支持來處理 WebSocket 連接。* registerWebSocketHandlers 方法是 Spring WebSocket 的一個 API,它允許開發人員在應用程序中注冊 WebSocket 處理程序,并將其映射到特定的 URI。在調用 registerWebSocketHandlers 方法時,需要傳遞一個 WebSocketHandler 實例和一個 URI 路徑作為參數。當客戶端請求與該 URI 路徑對應的 WebSocket 連接時,Spring 將調用相應的 WebSocket 處理程序來處理連接。*/@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {//參數1:注冊我們自定義的MyWebSocketHandler類//參數2:路徑【UniApp中建立連接的路徑】如:我的ip是192.168.1.8:8099則UniApp需要輸入的url是ws://192.168.1.8:8099/websocket//參數3:setAllowedOrigins("*")設置允許全部來源【在WebSocket中,瀏覽器會發送一個帶有Origin頭部的HTTP請求來請求建立WebSocket連接。服務器可以使用setAllowedOrigins方法來設置允許的來源,即允許建立WebSocket連接的域名或IP地址。這樣,服務器就可以限制建立WebSocket連接的客戶端,避免來自不信任的域名或IP地址的WebSocket連接。】registry.addHandler(new MyWebSocketHandler(), "/websocket").setAllowedOrigins("*").addInterceptors(new GroupChatInterceptor());;}}

WebSocket 處理器類(MyWebSocketHandler)

  • 連接建立
    • afterConnectionEstablished?方法在 WebSocket 連接建立后被調用,會記錄連接成功的日志信息,并將對應的?WebSocketSession?添加到?sessions?列表中,用于后續管理連接會話。
  • 消息處理
    • handleMessage?方法接收到消息時,會記錄消息內容日志,然后遍歷所有已連接的會話,嘗試向每個客戶端發送一條固定格式的消息(這里只是簡單示例性質的消息)。
    • handleTextMessage?方法針對文本消息做更具體的處理,會對收到的請求消息進行轉義和記錄日志,然后構造響應消息并發送回對應的客戶端會話。
  • 定時消息發送
    • 通過?@Scheduled(fixedRate = 10000)?注解定義了一個定時任務,每隔?10000?毫秒(即 10 秒)會遍歷所有連接會話,如果會話處于打開狀態,就向其發送一條包含當前時間的廣播消息。
  • 連接關閉及其他
    • afterConnectionClosed?方法在 WebSocket 連接關閉時被調用,負責從?sessions?列表中移除對應的會話,并記錄連接關閉的日志。
    • supportsPartialMessages?方法返回?false,表示不支持部分消息處理。
    • handleTransportError?方法用于處理 WebSocket 傳輸過程中的錯誤,會記錄相應的錯誤日志。
package com.edwin.java.util;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import org.springframework.web.util.HtmlUtils;import java.io.IOException;
import java.time.LocalTime;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;
import com.fasterxml.jackson.databind.ObjectMapper;@Component
public class MyWebSocketHandler extends TextWebSocketHandler {private static final Logger LOGGER = LoggerFactory.getLogger(MyWebSocketHandler.class);// 用于存儲群組信息,鍵為群組ID,值包含在線用戶會話列表和歷史消息列表private Map<String, GroupInfo> groupInfos = new HashMap<>();// 用于存儲用戶與群組的關聯關系,鍵為用戶ID,值為群組ID列表private Map<String, List<String>> userGroups = new HashMap<>();private ObjectMapper objectMapper = new ObjectMapper();private final List<WebSocketSession> sessions = new CopyOnWriteArrayList<>();/*** afterConnectionEstablished 是一個 WebSocket API 中的回調函數,它是在建立 WebSocket 連接之后被調用的。* 當 WebSocket 連接建立成功后,瀏覽器會發送一個握手請求給服務器端,如果服務器成功地接受了該請求,那么連接就會被建立起來*/@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {LOGGER.info("WebSocket已連接: {}", session.getId());// 假設從WebSocket連接的屬性或者請求參數中獲取用戶ID和群組ID列表(實際需按業務邏輯調整獲取方式)String userId = (String) session.getAttributes().get("userId");List<String> groupIds = (List<String>) session.getAttributes().get("groupIds");if (userId!= null && groupIds!= null) {userGroups.put(userId, groupIds);for (String groupId : groupIds) {groupInfos.computeIfAbsent(groupId, k -> new GroupInfo()).addSession(session);}}}/*** handleMessage 是 WebSocket API 中的回調函數,它是用來處理從客戶端接收到的 WebSocket 消息的。* 當客戶端通過 WebSocket 連接發送消息到服務器端時,服務器端會自動調用 handleMessage 函數并傳遞收到的消息作為參數,你可以在該函數中處理這個消息,并根據需要向客戶端發送一些響應消息。*/@Overridepublic void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {LOGGER.info("WebSocket收到的消息: {}", message.getPayload());// 將消息反序列化,假設消息是JSON格式,這里解析為Message對象(下面定義)Message msg = objectMapper.readValue(message.getPayload().toString(), Message.class);String groupId = msg.getGroupId();GroupInfo groupInfo = groupInfos.get(groupId);if (groupInfo == null) {// 如果群組信息不存在,則創建新的群組信息,并添加當前用戶的WebSocketSessiongroupInfo = new GroupInfo();groupInfo.addSession(session);groupInfos.put(groupId, groupInfo);// 同時,假設這里從WebSocket連接的屬性或者請求參數中獲取用戶ID(實際需按業務邏輯調整獲取方式)String userId = (String) session.getAttributes().get("userId");List<String> groupIds = userGroups.computeIfAbsent(userId, k -> new ArrayList<>());groupIds.add(groupId);}// 將消息添加到群組歷史消息列表groupInfo.addHistoryMessage(msg);// 向群組內所有在線用戶發送消息List<WebSocketSession> sessions = groupInfo.getSessions();for (WebSocketSession s : sessions) {try {s.sendMessage(new TextMessage(objectMapper.writeValueAsString(msg)));} catch (IOException e) {LOGGER.error("無法發送WebSocket消息", e);}}}@Overridepublic void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {handleMessage(session, message);}@Scheduled(fixedRate = 10000)void sendPeriodicMessages() throws IOException {// 這里可擴展定時向群組推送系統消息等功能,暫不做詳細修改for (GroupInfo groupInfo : groupInfos.values()) {List<WebSocketSession> sessions = groupInfo.getSessions();for (WebSocketSession s : sessions) {if (s.isOpen()) {String broadcast = "server periodic message " + LocalDateTime.now();LOGGER.info("Server sends: {}", broadcast);s.sendMessage(new TextMessage(broadcast));}}}}// 處理用戶重新上線,推送歷史消息的方法public void handleUserReconnect(String userId, WebSocketSession session) {List<String> groupIds = userGroups.get(userId);if (groupIds!= null) {for (String groupId : groupIds) {GroupInfo groupInfo = groupInfos.get(groupId);if (groupInfo!= null) {List<Message> historyMessages = groupInfo.getHistoryMessages();for (Message historyMessage : historyMessages) {try {session.sendMessage(new TextMessage(objectMapper.writeValueAsString(historyMessage)));} catch (IOException e) {LOGGER.error("無法發送歷史消息給重新上線用戶", e);}}}}}}/*** afterConnectionClosed 是 WebSocket API 中的回調函數,它是在 WebSocket 連接關閉后被調用的。* 當客戶端或服務器端主動關閉 WebSocket 連接時,afterConnectionClosed 回調函數會被調用,你可以在該函數中執行一些資源釋放、清理工作等操作,比如關閉數據庫連接、清理緩存等。*/@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {LOGGER.info("WebSocket已斷開連接: {}", session.getId());// 移除用戶會話在各個群組中的關聯String userId = (String) session.getAttributes().get("userId");List<String> groupIds = userGroups.get(userId);if (groupIds!= null) {for (String groupId : groupIds) {GroupInfo groupInfo = groupInfos.get(groupId);if (groupInfo!= null) {groupInfo.removeSession(session);}}userGroups.remove(userId);}}/*** supportsPartialMessages 是 WebSocket API 中的方法,它用來指示 WebSocket 消息是否支持分段傳輸。* WebSocket 消息可以分段傳輸,也就是說一個消息可以被分成多個部分依次傳輸,這對于大型數據傳輸和流媒體傳輸非常有用。當消息被分成多個部分傳輸時,WebSocket 會自動將這些部分合并成完整的消息。* supportsPartialMessages 方法用來指示服務器是否支持分段消息傳輸,如果支持,則可以在接收到部分消息時開始處理消息,否則需要等待接收到完整消息后才能開始處理。*/@Overridepublic boolean supportsPartialMessages() {return false;}/*** handleTransportError 是 WebSocket API 中的回調函數,它用來處理 WebSocket 傳輸層出現錯誤的情況。*當 WebSocket 傳輸層出現錯誤,比如網絡中斷、協議錯誤等,WebSocket 會自動調用 handleTransportError 函數,并傳遞相應的錯誤信息。在該函數中,我們可以處理這些錯誤,比如關閉 WebSocket 連接、記錄錯誤日志等。*/@Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {LOGGER.error("WebSocket錯誤", exception);}// 在MyWebSocketHandler類內部定義private class GroupInfo {// 存儲群組內所有在線用戶的WebSocketSession列表private List<WebSocketSession> sessions = new ArrayList<>();// 存儲群組的歷史消息列表,消息以自定義的Message對象形式存儲(前面代碼中已定義Message類)private List<Message> historyMessages = new ArrayList<>();// 添加一個用戶的WebSocketSession到群組的在線用戶列表中public void addSession(WebSocketSession session) {sessions.add(session);}// 從群組的在線用戶列表中移除指定用戶的WebSocketSessionpublic void removeSession(WebSocketSession session) {sessions.remove(session);}// 向群組的歷史消息列表中添加一條消息public void addHistoryMessage(Message message) {historyMessages.add(message);}// 獲取群組內所有在線用戶的WebSocketSession列表public List<WebSocketSession> getSessions() {return sessions;}// 獲取群組的歷史消息列表public List<Message> getHistoryMessages() {return historyMessages;}}// 定義消息類,包含必要的消息屬性,可根據實際需求擴展private static class Message {private String type; // 消息類型,如 "text" 或 "image"private String groupId; // 群組IDprivate String sender; // 發送者(可根據實際情況完善,比如用戶ID等)private String content; // 消息內容,文字或圖片鏈接等// private LocalDateTime timestamp = LocalDateTime.now(); // 時間戳// 生成必要的Getter和Setter方法(可使用Lombok簡化代碼,此處為清晰展示手動編寫)public String getType() {return type;}public void setType(String type) {this.type = type;}public String getGroupId() {return groupId;}public void setGroupId(String groupId) {this.groupId = groupId;}public String getSender() {return sender;}public void setSender(String sender) {this.sender = sender;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}//        public LocalDateTime getTimestamp() {
//            return timestamp;
//        }
//
//        public void setTimestamp(LocalDateTime timestamp) {
//            this.timestamp = timestamp;
//        }}}

?postman驗證:

注意,路徑中要加chat ,因為application.yml中配置了

uniapp端頁面:

<template><view class="chat-room"><!-- 聊天記錄 --><scroll-view scroll-y="true" class="message-list"><view v-for="(message, index) in messages" :key="index" class="message-item"><view v-if="message.type === 'text'" class="text-message"><!--    <view class="avatar">{{ message.senderAvatar }}</view> --><view class="text">{{ message.content }}</view></view><view v-else-if="message.type === 'image'" class="image-message"><image :src="message.content" class="message-image" @click="previewImage(message.content)"></image></view></view></scroll-view><!-- 輸入框 --><view class="input-area"><input v-model="inputContent" placeholder="輸入內容" class="input" /><button @click="sendMessage">發送</button></view></view>
</template><script>
export default {data() {return {messages: [], // 聊天記錄inputContent: '', // 輸入框內容socketOpen: false, // WebSocket連接狀態socket: null, // WebSocket對象};},methods: {// 初始化WebSocket連接initWebSocket() {uni.setStorageSync('userId',1);  // only testuni.setStorageSync('groupIds',2);  // only testconst userId = uni.getStorageSync('userId');const groupIds = uni.getStorageSync('groupIds');console.log(groupIds);// /wechat/client/chatthis.socket = uni.connectSocket({url: 'ws://127.0.0.1:7877/chat/websocket',data: {userId: userId,groupIds: groupIds},success: () => {console.log('WebSocket連接成功');this.socketOpen = true;},fail: () => {console.error('WebSocket連接失敗');},});// 監聽WebSocket消息this.socket.onMessage((res) => {const message = JSON.parse(res.data);this.messages.push(message); // 將新消息添加到聊天記錄中this.$forceUpdate(); // 強制更新視圖,確保新消息顯示});// 監聽WebSocket連接關閉this.socket.onClose(() => {console.log('WebSocket連接關閉');this.socketOpen = false;});},// 發送消息
sendMessage() {if (this.inputContent.trim() === '') {uni.showToast({title: '請輸入內容',icon: 'none',});return;}const message = {type: 'text', // 消息類型,可以是text或image,這里發送文字消息示例,發送圖片時修改相應字段groupId: uni.getStorageSync('groupIds'), // 從本地存儲獲取當前所在群組ID(需按實際情況調整獲取方式)sender: uni.getStorageSync('userId'), // 從本地存儲獲取用戶ID(需按實際情況調整獲取方式)content: this.inputContent};// 通過WebSocket發送消息(或HTTP請求,根據后端接口決定)if (this.socketOpen) {this.socket.send({data: JSON.stringify(message)});} else {//todo}
},// 預覽圖片previewImage(url) {uni.previewImage({current: url, // 當前顯示圖片的http鏈接urls: [url], // 需要預覽的圖片http鏈接列表});},},mounted() {// 頁面加載時初始化WebSocket連接this.initWebSocket();// 可以從服務器獲取歷史聊天記錄并初始化messages數組(根據需求實現)},
};
</script><style>
.chat-room {padding: 10px;
}.message-list {height: 500px; /* 根據需要調整高度 */border-bottom: 1px solid #ccc;padding-right: 10px; /* 留出空間給滾動條 */overflow-y: auto;
}.message-item {margin-bottom: 10px;display: flex;align-items: center;
}.avatar {width: 40px;height: 40px;border-radius: 50%;margin-right: 10px;
}.text-message .text {background-color: #fff;padding: 5px 10px;border-radius: 5px;max-width: 60%; /* 根據需要調整寬度 */word-wrap: break-word; /* 防止長文本溢出 */
}.image-message .message-image {width: 100px;height: 100px;object-fit: cover;border-radius: 5px;
}.input-area {display: flex;margin-top: 10px;
}.input {flex: 1;padding: 5px;border: 1px solid #ccc;border-radius: 5px;
}button {padding: 5px 10px;margin-left: 10px;border: none;background-color: #1aad19;color: #fff;border-radius: 5px;
}
</style>

原型效果:

?

后期再補充~~~~~

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

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

相關文章

Reed-Muller(RM)碼之編碼

點個關注吧! 看了一些中文的博客,RM碼沒有很詳細的資料,所以本文嘗試給出推導原理。 推導 RM碼由 ( r , m ) ( r , m ) (r,m

List直接使用removeAll報錯

List直接使用removeAll報錯 需要先將list轉換才能使用 原因是&#xff1a; removeAll 方法在 Java 中用于從當前列表中刪除另一個列表中存在的所有元素。如果直接對 List 接口的一個實現使用 removeAll 方法拋出異常&#xff0c;可能的原因有&#xff1a; 不同的List實現&am…

Linux -- 線程的優點、pthread 線程庫

目錄 線程的優點 pthread 線程庫 前言 認識線程庫 簡單驗證線程的獨立棧空間 線程的優點 與進程之間的切換相比&#xff0c;線程之間的切換需要操作系統做的工作要少得多。 調度進程時&#xff0c;CPU 中有一個 cache&#xff08;緩存&#xff0c;提高運行效率&#xff0…

【magic-dash】01:magic-dash創建單頁面應用及二次開發

文章目錄 一、magic-dash是什么1.1 安裝1.2 使用1.2.1 查看內置項目模板1.2.2 生成指定項目模板1.2.3 查看當前magic-dash版本1.2.4 查看命令說明1.2.5 內置模板列表二、創建虛擬環境并安裝magic-dash三、magic-dash單頁工具應用開發3.1 創建單頁面項目3.1.1 使用命令行創建單頁…

從零開始使用MaxKB打造本地大語言模型智能問答系統與遠程交互

文章目錄 前言1. 下載運行Ollama2. 安裝大語言模型3. 安裝Cpolar工具4. 配置公網地址5. 固定公網地址6. MaxKB 添加Olama7.創建問答應用 前言 目前大語言模型&#xff08;LLM&#xff09;已經成為了人工智能領域的一顆璀璨明星&#xff0c;從自然語言處理到智能問答系統&#…

深度解析 Pytest 中的 conftest.py

關注開源優測不迷路 大數據測試過程、策略及挑戰 測試框架原理&#xff0c;構建成功的基石 在自動化測試工作之前&#xff0c;你應該知道的10條建議 在自動化測試中&#xff0c;重要的不是工具 在使用 Pytest 進行測試的過程中&#xff0c;conftest.py 文件扮演著極為重要的角色…

【python】銀行客戶流失預測預處理部分,獨熱編碼·標簽編碼·數據離散化處理·數據篩選·數據分割

數據預處理 通過網盤分享的文件&#xff1a;銀行流失預測數據和代碼 鏈接: https://pan.baidu.com/s/1loiB8rMvZArfjJccu4KW6w?pwdpfcs 提取碼: pfcs 非數值特征處理 目的&#xff1a;將非數值特征轉換為數值型&#xff0c;以便模型能夠處理。方法&#xff1a; 地理位置&am…

回歸預測 | MATLAB實現CNN-LSSVM卷積神經網絡結合最小二乘支持向量機多輸入單輸出回歸預測

回歸預測 | MATLAB實現CNN-LSSVM卷積神經網絡結合最小二乘支持向量機多輸入單輸出回歸預測 目錄 回歸預測 | MATLAB實現CNN-LSSVM卷積神經網絡結合最小二乘支持向量機多輸入單輸出回歸預測預測效果基本介紹程序設計參考資料 預測效果 基本介紹 回歸預測 | MATLAB實現CNN-LSSVM…

slam學習筆記7---狀態量求導相關數學公式

前言&#xff1a;本來打算只是歸納一下數學求導相關公式&#xff0c;后面也寫了旋轉求導相關內容&#xff0c;哈哈。感覺有點發散把握不住呀。水平有限&#xff0c;歡迎評論區點出。 一、基本初等函數求導公式 ( C ) ′ 0 , C (C)0,C (C)′0,C為常數 ( x μ ) ′ μ x μ ?…

32單片機串口數據接收、空閑IDLE中斷詳解

一、前提說明 一開始寫單片機程序的時候不太清楚空閑中斷這個東西&#xff0c;每次用串口接收數據&#xff0c;都要再開一個定時器&#xff0c;在定時器內進行倒計時&#xff0c;每次接收數據就重置計時時間&#xff0c;計時結束就觸發中斷&#xff0c;再判斷所有接收的數據&am…

深入探討 Go 中的高級表單驗證與翻譯:Gin 與 Validator 的實踐之道20241223

深入探討 Go 中的高級表單驗證與翻譯&#xff1a;Gin 與 Validator 的實踐之道 在現代后端開發中&#xff0c;表單驗證是保證數據完整性和服務穩定性的核心環節。如何優雅、高效地實現表單驗證&#xff0c;同時提供人性化的錯誤提示&#xff0c;是每位開發者的必修課。在本文中…

掌握 Ansys ACP 中的參考方向:簡化復雜的復合材料設計

概括 在復合材料分析領域&#xff0c;精度至關重要&#xff0c;尤其是在定義纖維方向和鋪層時。Ansys ACP&#xff08;Ansys Composite PrepPost&#xff09;提供了強大的工具來建立參考方向&#xff0c;這是實現精確結構模擬的關鍵步驟。在本博客中&#xff0c;我們將揭開在 …

Vue2學習(一)——Vue簡介、Vue指令與指令修飾符

一、Vue簡介 Vue是一套用于構建用戶界面的漸進式框架。 所謂漸進式就是循序漸進&#xff0c;不一定非得把Vue中的所有API都學完才能開發Vue&#xff0c;可以學一點開發一點。 Vue2官網地址&#xff1a;https://v2.cn.vuejs.org/ Vue3官網地址&#xff1a;https://cn.vuejs…

Redis--通用命令學習

目錄 一、引言 二、基礎命令 1.set 2.get 3.keys 3.1 keys &#xff1f; 3.2 keys * 3.3 keys [abe] 3.4 keys [^] 3.5 keys [a-b] 4.exists 5.delete 6.expire 7.ttl 8.type 三、Redis中的過期策略&#xff08;面試題&#xff09; 1.惰性刪除 2.定期刪除 …

Linux程序設計(第四版)| 學習筆記

上次學習Linux相關內容還是上學的時候為了應付考試&#xff0c;最近有項目涉及Linux&#xff0c;重新學習以下。 很多年前關于Linux的總結 一、入門 1.概念 (1) UNIX 1)定義&#xff1a;指的是一種遵循特定規范的計算機操作系統。 2)特點&#xff1a;簡單性、集中性、可重用…

PostgreSQL 的歷史

title: PostgreSQL 的歷史 date: 2024/12/23 updated: 2024/12/23 author: cmdragon excerpt: PostgreSQL 是一款功能強大且廣泛使用的開源關系型數據庫管理系統。其歷史可以追溯到1986年,當時由加州大學伯克利分校的一個研究團隊開發。文章將深入探討 PostgreSQL 的起源、…

Ubuntu22.04 LTS 安裝nvidia顯卡驅動

準備跑老師給定的Github上的多模態源碼,但是用了這么久ubuntu還沒有嘗試過安裝nvidia驅動,好在也是一次成功,于是記錄下來。 借鑒的是Ubuntu22.04安裝顯卡驅動(高速、避錯版)-CSDN博客這篇文章,按照流程來基本沒有問題,不過個人覺得有些步驟比較冗余,所以記錄下來 主要…

WPS工具欄灰色怎么辦

WPS離線不登錄&#xff0c;開啟工具欄等相關功能 當你在使用WPS的過程中&#xff0c;若因網絡問題或其他特殊原因&#xff0c;導致無法登錄使用WPS時&#xff0c;可根據以下步驟開啟離線兼容模式&#xff0c;開啟此模式后&#xff0c;可在未登錄的狀態下&#xff0c;激活并使用…

國標GB28181-2022平臺EasyGBS:安防監控中P2P的穿透方法

在安防監控領域&#xff0c;P2P技術因其去中心化的特性而受到關注&#xff0c;尤其是在遠程視頻監控和數據傳輸方面。P2P技術允許設備之間直接通信&#xff0c;無需通過中央服務器&#xff0c;這在提高效率和降低成本方面具有明顯優勢。然而&#xff0c;P2P技術在實際應用中也面…

Mac Android studio 升級LadyBug 版本,所產生的bug

當Build 出現&#xff0c;這樣的文字以后&#xff1a; Your build is currently configured to use incompatible Java 21.0.3 and Gradle 7.3.3. Cannot sync the project. We recommend upgrading to Gradle version 8.9. The minimum compatible Gradle version is 8.5. …