OJ判題系統第6期之判題邏輯開發——設計思路、實現步驟、代碼實現(策略模式)

在看這期之前,建議先看前五期:

Java 原生實現代碼沙箱(OJ判題系統第1期)——設計思路、實現步驟、代碼實現-CSDN博客

Java 原生實現代碼沙箱之Java 程序安全控制(OJ判題系統第2期)——設計思路、實現步驟、代碼實現-CSDN博客

Java 原生實現代碼沙箱之代碼沙箱 Docker 實現(OJ判題系統第3期)——設計思路、實現步驟、代碼實現-CSDN博客

OJ判題系統第4期之判題機模塊架構——設計思路、實現步驟、代碼實現(工廠模式、代理模式的實踐)-CSDN博客?

OJ判題系統第5期之判題服務開發——設計思路、實現步驟、代碼實現-CSDN博客?

判題邏輯的主要指責

定義

  • 判題邏輯?是具體判斷用戶提交的代碼是否正確的核心算法或規則集。它專注于解析沙箱返回的結果,并根據預定義的標準(如測試用例、時間限制、內存限制等)判斷代碼的正確性。
  • 這是一個低層次的模塊,主要關注具體的判題細節。

主要職責

  1. 解析沙箱輸出:從沙箱返回的結果中提取關鍵信息(如輸出、錯誤信息、耗時、內存占用等)。
  2. 比對測試用例:將沙箱的輸出與題目提供的標準答案進行比對,判斷每個測試用例是否通過。
  3. 生成判題報告:根據比對結果生成詳細的判題報告(如哪些測試用例通過了,哪些失敗了,失敗的原因是什么)。
  4. 性能評估:根據資源消耗情況(如時間、內存)評估代碼的效率。

策略模式優化

什么是策略模式(Strategy Pattern)?

策略模式是一種行為型設計模式,它定義了一系列算法或策略,并將每一個算法封裝起來,使它們可以互相替換,獨立于使用它們的客戶端。

簡單理解:

  • 把不同的“處理方式”封裝成一個個獨立的類。
  • 客戶端在運行時決定使用哪一種策略。
  • 這樣可以讓程序更靈活、更易擴展、更易維護。

問題背景:判題邏輯復雜,存在多種判斷方式?

在你的在線判題系統中,可能會遇到以下幾種情況:

情況描述
Java 執行較慢Java 程序啟動沙箱需要額外耗時(如 10 秒),總執行時間不能只看用戶代碼運行時間
Python 內存限制寬松不同語言對內存的消耗不同,判題標準也要變化
C++ 要求輸出完全一致對輸出格式要求嚴格,必須完全匹配才算通過
時間/內存限制動態調整根據題目難度、語言類型等自動調整閾值

? 如果不用策略模式,會出現什么問題?

  • 判題邏輯中會充斥大量?if...else?或?switch...case
  • 新增一個語言或規則時,要修改原有邏輯,違反開閉原則
  • 各種語言規則混在一起,可讀性差,容易出錯
  • 難以復用、難以測試、難以維護

解決方案:使用策略模式統一管理判題規則?

🔧 設計思路

我們將“如何根據沙箱執行結果和語言特性來判定是否通過”的邏輯抽象為一個接口,然后為每種語言提供一個具體的實現類。

這樣做的好處是:

  • 每個語言的判題規則彼此隔離,互不干擾
  • 可以隨時新增、修改某種語言的判題規則,不影響其他邏輯
  • 在運行時可以根據提交的語言類型動態選擇對應的策略

總結一句話?

策略模式就像給系統裝上了一個“可插拔的大腦”,你可以根據不同情況(比如語言類型)自動選擇最合適的判題規則,而無需改動主流程代碼。

策略模式的優勢總結?

優勢描述
? 解耦將判題邏輯與業務流程分離
? 易擴展新增語言只需添加策略類,符合開閉原則
? 易維護每種語言的規則獨立,便于閱讀和調試
? 動態切換支持運行時根據條件選擇不同策略
? 清晰結構每個策略職責單一,符合單一職責原則

?實現步驟

定義判題策略接口,讓代碼更加通用化:

/*** 判題策略*/
public interface JudgeStrategy {/*** 執行判題* @param judgeContext* @return*/JudgeInfo doJudge(JudgeContext judgeContext);
}

定義判題上下文對象,用于定義在策略中傳遞的參數(可以理解為一種 DTO):

/*** 上下文類(Context Class)** JudgeContext 用于封裝和傳遞在不同判題策略中需要用到的所有參數。* 它作為數據容器,確保各個判題策略能夠訪問到所需的信息,而不必直接依賴外部對象。*/
@Data // Lombok 注解,自動生成 getter 和 setter 方法
public class JudgeContext {/*** 沙箱執行結果信息** 包含了用戶提交代碼在沙箱中運行時的各項指標,如耗時、內存占用等。* 這些信息對于判斷代碼的正確性和性能至關重要。*/private JudgeInfo judgeInfo;/*** 測試用例輸入列表** 包含了題目定義的所有測試用例的輸入數據。* 在判題過程中,這些輸入將被傳入用戶提交的代碼,并與輸出結果進行比對。*/private List<String> inputList;/*** 用戶代碼的實際輸出列表** 當用戶提交的代碼在沙箱中運行時,根據不同的測試用例輸入,會生成相應的輸出結果。* 這些輸出結果會被收集起來,用于后續的比對和判斷。*/private List<String> outputList;/*** 題目定義的標準測試用例列表** 每個標準測試用例包含了輸入和期望的輸出。* 判題邏輯需要將用戶的實際輸出與這些期望輸出進行比對,以確定是否通過該測試用例。*/private List<JudgeCase> judgeCaseList;/*** 當前題目對象** 包含了題目的所有相關信息,如題目描述、難度等級、附加說明等。* 雖然在大多數情況下,具體的判題邏輯可能不會直接使用這些信息,但它們可能會在某些特定場景下有用。*/private Question question;/*** 用戶提交記錄對象** 包含了用戶提交的詳細信息,如提交時間、編程語言、用戶代碼等。* 這些信息對于跟蹤和記錄用戶的提交歷史非常重要。*/private QuestionSubmit questionSubmit;
}

實現默認判題策略

DefaultJudgeStrategy.java

/*** 默認判題策略實現類** 該策略用于處理通用語言(如 C++、JavaScript 等)的標準判題邏輯。* 包括:* - 判斷輸出數量是否匹配* - 判斷每個測試用例的輸出是否與預期一致* - 檢查內存和時間是否超出題目限制*/
public class DefaultJudgeStrategy implements JudgeStrategy {/*** 執行判題邏輯的核心方法** @param judgeContext 判題上下文對象,包含所有需要的數據* @return 返回最終的判題結果信息(是否通過、錯誤類型、耗時、內存等)*/@Overridepublic JudgeInfo doJudge(JudgeContext judgeContext) {

從上下文中提取關鍵數據

        // 從上下文中獲取沙箱返回的執行信息(如時間、內存)JudgeInfo judgeInfo = judgeContext.getJudgeInfo();Long memory = judgeInfo.getMemory();   // 用戶程序使用的內存大小(單位:字節)Long time = judgeInfo.getTime();       // 用戶程序運行的時間(單位:毫秒)// 獲取輸入列表和輸出列表List<String> inputList = judgeContext.getInputList();   // 測試用例的輸入數據List<String> outputList = judgeContext.getOutputList(); // 用戶程序的實際輸出結果// 獲取題目信息和測試用例列表Question question = judgeContext.getQuestion();                     // 當前題目對象List<JudgeCase> judgeCaseList = judgeContext.getJudgeCaseList();    // 題目定義的標準測試用例// 初始化判題結果為“接受”狀態JudgeInfoMessageEnum judgeInfoMessageEnum = JudgeInfoMessageEnum.ACCEPTED;// 創建一個新的 JudgeInfo 對象用于封裝最終的判題結果JudgeInfo judgeInfoResponse = new JudgeInfo();judgeInfoResponse.setMemory(memory); // 設置實際使用內存judgeInfoResponse.setTime(time);     // 設置實際運行時間

初步校驗輸出數量是否與輸入一致

        // 如果輸出數量不等于輸入數量,說明至少有一個測試用例沒有正確輸出if (outputList.size() != inputList.size()) {// 設置為“答案錯誤”judgeInfoMessageEnum = JudgeInfoMessageEnum.WRONG_ANSWER;judgeInfoResponse.setMessage(judgeInfoMessageEnum.getValue());return judgeInfoResponse; // 直接返回錯誤結果}

舉例說明:
假設題目有 3 個測試用例,但用戶只輸出了 2 條結果,說明至少有一個用例未通過,無需繼續比對。

?逐條比對輸出與預期是否一致

        // 遍歷所有測試用例,檢查每一條輸出是否與期望輸出相等for (int i = 0; i < judgeCaseList.size(); i++) {JudgeCase judgeCase = judgeCaseList.get(i); // 獲取第 i 個標準測試用例String expectedOutput = judgeCase.getOutput(); // 期望輸出String actualOutput = outputList.get(i);       // 實際輸出// 如果兩者不一致,則判定為“答案錯誤”if (!expectedOutput.equals(actualOutput)) {judgeInfoMessageEnum = JudgeInfoMessageEnum.WRONG_ANSWER;judgeInfoResponse.setMessage(judgeInfoMessageEnum.getValue());return judgeInfoResponse; // 只要有一個測試用例失敗,就直接返回錯誤}}

檢查是否超過題目設定的資源限制

        // 從題目對象中獲取判題配置(例如內存限制、時間限制)String judgeConfigStr = question.getJudgeConfig(); // JSON 字符串格式的配置JudgeConfig judgeConfig = JSONUtil.toBean(judgeConfigStr, JudgeConfig.class);// 獲取題目要求的最大內存和最大運行時間Long needMemoryLimit = judgeConfig.getMemoryLimit(); // 內存限制(單位:MB)Long needTimeLimit = judgeConfig.getTimeLimit();     // 時間限制(單位:毫秒)// 將 MB 轉換為字節進行比較(注意單位一致性)if (memory > needMemoryLimit * 1024L * 1024L) { // 1 MB = 1024 KB = 1024*1024 bytesjudgeInfoMessageEnum = JudgeInfoMessageEnum.MEMORY_LIMIT_EXCEEDED;judgeInfoResponse.setMessage(judgeInfoMessageEnum.getValue());return judgeInfoResponse;}// 檢查是否超時if (time > needTimeLimit) {judgeInfoMessageEnum = JudgeInfoMessageEnum.TIME_LIMIT_EXCEEDED;judgeInfoResponse.setMessage(judgeInfoMessageEnum.getValue());return judgeInfoResponse;}

全部通過,返回成功結果

        // 所有條件都滿足,設置最終消息為“接受”judgeInfoResponse.setMessage(judgeInfoMessageEnum.getValue());// 返回完整的判題結果return judgeInfoResponse;}
}

總結一下這個類的職責:

步驟功能
1?? 提取參數從?JudgeContext?中提取所有判題所需的信息
2?? 輸出數量校驗判斷輸出數量是否與輸入數量一致
3?? 輸出內容比對比較每個測試用例的實際輸出與期望輸出是否一致
4?? 資源限制判斷判斷是否超出內存或時間限制
5?? 返回結果構建并返回最終的判題結果

定義 JudgeManager

為什么要定義?JudgeManager

1.?集中管理判題邏輯

  • 問題背景: 在沒有?JudgeManager?的情況下,每個地方調用判題邏輯時都需要手動判斷使用哪種策略,這會導致大量的重復代碼,增加維護成本。
  • 解決方案:?JudgeManager?將所有的判題邏輯集中管理,使得外部調用者只需傳遞?JudgeContext?對象即可完成判題操作,無需關心具體的實現細節。

2.?提高代碼的可維護性和擴展性

  • 問題背景: 如果未來需要支持更多的編程語言或引入新的判題規則,直接修改現有代碼容易引發潛在的風險。
  • 解決方案: 使用?JudgeManager?和策略模式,可以輕松地添加新的策略類而不需要修改原有代碼,符合開閉原則(對擴展開放,對修改封閉)。

3.?簡化客戶端調用

  • 問題背景: 客戶端代碼如果直接與各種判題策略打交道,會顯得非常復雜且不易于理解。
  • 解決方案:?JudgeManager?提供了一個統一的接口,客戶端只需要知道如何構建?JudgeContext?并調用?doJudge?方法,極大地簡化了調用過程。

4.?增強系統的靈活性

  • 問題背景: 不同編程語言可能有不同的運行環境要求(如啟動時間、內存限制等),這些差異需要在判題時特別處理。
  • 解決方案:?JudgeManager?可以根據編程語言動態選擇最適合的判題策略,確保每種語言都能得到公平準確的評判。
/*** 判題管理器** JudgeManager 是整個判題系統的核心組件之一,負責根據用戶提交的編程語言,* 動態選擇并調用相應的判題策略(JudgeStrategy)。這有助于將復雜的判題邏輯* 進行模塊化封裝,便于后續維護和擴展。*/
@Service // Spring 注解,標識該類為一個服務層組件
public class JudgeManager {/*** 執行判題操作** 該方法接收一個包含所有必要信息的上下文對象(JudgeContext),* 根據用戶提交的編程語言動態選擇合適的判題策略,并返回最終的判題結果。** @param judgeContext 包含了題目、用戶提交、沙箱執行結果等信息的對象* @return 判題結果信息(如是否通過、錯誤類型、耗時、內存等)*/public JudgeInfo doJudge(JudgeContext judgeContext) {// 從上下文中獲取用戶提交的信息QuestionSubmit questionSubmit = judgeContext.getQuestionSubmit();// 獲取用戶提交的編程語言類型String language = questionSubmit.getLanguage();// 初始化默認的判題策略JudgeStrategy judgeStrategy = new DefaultJudgeStrategy();// 根據編程語言選擇不同的判題策略if ("java".equals(language)) {judgeStrategy = new JavaLanguageJudgeStrategy(); // Java 特有的判題策略}// 調用選定的策略執行判題操作return judgeStrategy.doJudge(judgeContext);}
}

執行判題:

整體流程圖

用戶點擊提交按鈕
│
├─→ 校驗編程語言是否合法
│
├─→ 校驗題目是否存在
│
├─→ 構造提交記錄對象(包含代碼、語言、用戶ID、題目ID)
│
├─→ 插入數據庫,設置初始狀態為 WAITING
│
├─→ 獲取提交記錄 ID
│
├─→ 異步調用 judgeService.doJudge(questionSubmitId)
│
└─→ 返回 questionSubmitId 給前端

具體實現

方法簽名與基本說明

/*** 提交題目** 用戶提交代碼進行判題的核心方法。* 主要流程包括:* 1. 參數校驗(語言合法性、題目是否存在)* 2. 構建提交記錄對象并保存到數據庫* 3. 異步調用判題服務進行判題** @param questionSubmitAddRequest 提交請求參數封裝類* @param loginUser 當前登錄用戶信息* @return 返回提交記錄的 ID,用于后續查詢判題結果*/
@Override
public long doQuestionSubmit(QuestionSubmitAddRequest questionSubmitAddRequest, User loginUser) {

獲取并校驗編程語言是否合法

    // 從請求中獲取用戶提交的編程語言String language = questionSubmitAddRequest.getLanguage();// 使用枚舉工具類判斷該語言是否在支持的語言列表中QuestionSubmitLanguageEnum languageEnum = QuestionSubmitLanguageEnum.getEnumByValue(language);// 如果語言不合法,拋出異常if (languageEnum == null) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "編程語言錯誤");}

為什么需要這一步?

  • 防止用戶輸入非法或不受支持的編程語言(如 Python3、PHP 等非白名單語言)。
  • 增強系統安全性,避免后續處理出現不可控問題。

檢查題目是否存在

    // 獲取題目 IDlong questionId = questionSubmitAddRequest.getQuestionId();// 查詢題目實體是否存在Question question = questionService.getById(questionId);if (question == null) {throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);}

為什么需要這一步?

  • 確保用戶提交的是一個真實存在的題目,防止攻擊者通過偽造 ID 操作不存在的數據。
  • 同時也為后續判題邏輯提供必要的題目信息(如測試用例、限制條件等)。

?構造提交記錄對象,并設置默認狀態

    // 獲取當前用戶的 IDlong userId = loginUser.getId();// 創建一個新的提交記錄對象QuestionSubmit questionSubmit = new QuestionSubmit();questionSubmit.setUserId(userId);               // 設置用戶 IDquestionSubmit.setQuestionId(questionId);       // 設置題目 IDquestionSubmit.setCode(questionSubmitAddRequest.getCode()); // 設置用戶提交的代碼內容questionSubmit.setLanguage(language);           // 設置編程語言// 設置初始狀態為“等待中”questionSubmit.setStatus(QuestionSubmitStatusEnum.WAITING.getValue());// 初始 judgeInfo 字段為空 JSON,表示還未判題questionSubmit.setJudgeInfo("{}");

為什么設置初始狀態?

  • 表示當前提交正在排隊等待判題,前端或其他模塊可以根據此狀態判斷是否已開始執行。
  • 判題完成后會異步更新狀態為“成功”或“失敗”。

將提交記錄保存到數據庫?

    // 嘗試將提交記錄插入數據庫boolean save = this.save(questionSubmit);if (!save){throw new BusinessException(ErrorCode.SYSTEM_ERROR, "數據插入失敗");}

為什么需要持久化?

  • 記錄每一次提交的歷史,便于后續查詢、統計、審計。
  • 即使系統重啟或發生異常,也可以根據數據庫恢復狀態。

獲取提交記錄 ID 并異步觸發判題服務

    // 獲取剛剛插入的提交記錄 IDLong questionSubmitId = questionSubmit.getId();// 異步執行判題邏輯,避免阻塞主線程CompletableFuture.runAsync(() -> {judgeService.doJudge(questionSubmitId);});

為什么要異步執行?

  • 判題是一個耗時操作(可能涉及啟動沙箱、運行代碼、比對輸出等),如果同步執行會影響接口響應速度。
  • 使用?CompletableFuture?實現異步處理,提高系統吞吐量和用戶體驗。

?返回提交記錄 ID

    // 返回提交記錄 ID,供前端或其他服務使用return questionSubmitId;
}

這個 ID 的用途是什么?

  • 前端可以通過這個 ID 輪詢或 WebSocket 監聽判題結果。
  • 判題服務也依賴這個 ID 來查找對應的提交記錄和題目信息。

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

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

相關文章

行業趨勢與技術創新:駕馭工業元宇宙與綠色智能制造

引言 制造業發展的新格局&#xff1a;創新勢在必行 當今制造業正經歷深刻變革&#xff0c;面臨著供應鏈波動、個性化需求增長、可持續發展壓力以及技能人才短缺等多重挑戰。在這樣的背景下&#xff0c;技術創新不再是可有可無的選項&#xff0c;而是企業保持競爭力、實現可持…

高效Python開發:uv包管理器全面解析

目錄 uv簡介亮點與 pip、pip-tools、pipx、poetry、pyenv、virtualenv 對比 安裝uv快速開始uv安裝pythonuv運行腳本運行無依賴的腳本運行有依賴的腳本創建帶元數據的 Python 腳本使用 shebang 創建可執行文件使用其他package indexes鎖定依賴提高可復現性指定不同的 Python 版本…

鴻蒙OSUniApp開發富文本編輯器組件#三方框架 #Uniapp

使用UniApp開發富文本編輯器組件 富文本編輯在各類應用中非常常見&#xff0c;無論是內容創作平臺還是社交軟件&#xff0c;都需要提供良好的富文本編輯體驗。本文記錄了我使用UniApp開發一個跨平臺富文本編輯器組件的過程&#xff0c;希望對有類似需求的開發者有所啟發。 背景…

字符串檢索算法:KMP和Trie樹

目錄 1.引言 2.KMP算法 3.Trie樹 3.1.簡介 3.2.Trie樹的應用場景 3.3.復雜度分析 3.4.Trie 樹的優缺點 3.5.示例 1.引言 字符串匹配&#xff0c;給定一個主串 S 和一個模式串 P&#xff0c;判斷 P 是否是 S 的子串&#xff0c;即找到 P 在 S 中第一次出現的位置。暴力匹…

計算機組成原理:I/O

計算機組成:I/O I/O概述I/O系統構成I/O接口I/O端口兩種編址區分I/O數據傳送控制方式程序查詢方式獨占查詢中斷控制方式硬件判優法(向量中斷法)多重中斷嵌套DMA控制方式三種DMA方式DMA操作步驟內部異常和中斷異常和中斷的關系I/O概述 I/O系統構成 一個最基礎I/O系統的構成:CPU…

ssti模板注入學習

ssti模板注入原理 ssti模板注入是一種基于服務器的模板引擎的特性和漏洞產生的一種漏洞&#xff0c;通過將而已代碼注入模板中實現的服務器的攻擊 模板引擎 為什么要有模板引擎 在web開發中&#xff0c;為了使用戶界面與業務數據&#xff08;內容&#xff09;分離而產生的&…

NVMe簡介2

共分2部分&#xff0c;這里是第2部分。 NVMe數據結構 NVMe協議中規定每個提交命令的大小為64字節&#xff0c;完成命令大小為16字節&#xff0c;NVMe命令分為Admin和IO兩類&#xff0c;NVMe的數據塊組織方式有PRP和SGL兩種。提交命令的格式如圖5所示。 圖5 提交命令數據格 N…

高壓啟動電路--學習記錄

常見反激的啟動電路 優點&#xff1a;電路設計簡單&#xff0c;價格便宜 缺點&#xff1a;損壞大&#xff0c;輸入寬范圍的時候&#xff0c;為了保證低壓能正常啟動&#xff0c;啟動電阻阻值需要選小&#xff0c;那么高壓時損耗會非常大&#xff0c;設計的不好很容易在高壓時損…

VS打印printf、cout或者Qt的qDebug等傳出的打印信息

在vs中打印printf、cout或者Qt的qDebug等常見的打印信息有時也是必要的&#xff0c;簡單的敘述一下過程&#xff1a; 1、在vs中打開你的解決方案。 2、鼠標移動到你的項目名稱上&#xff0c;點擊鼠標右鍵&#xff0c;再點擊屬性&#xff0c;此刻會此項目的屬性頁。 3、在配置…

蒼穹外賣--新增菜品

1.需求分析和設計 產品原型 業務規則&#xff1a; 菜品名稱必須是唯一的 菜品必須屬于某個分類下&#xff0c;不能單獨存在 新增菜品時可以根據情況選擇菜品的口味 每個菜品必須對應一張圖片 接口設計&#xff1a; 根據類型查詢分類(已完成) 文件上傳 新增菜品 根據類型…

如何高效集成MySQL數據到金蝶云星空

MySQL數據集成到金蝶云星空&#xff1a;SC采購入庫-深圳天一-OK案例分享 在企業信息化建設中&#xff0c;數據的高效流轉和準確對接是實現業務流程自動化的關鍵。本文將聚焦于一個具體的系統對接集成案例——“SC采購入庫-深圳天一-OK”&#xff0c;詳細探討如何通過輕易云數據…

【springcloud學習(dalston.sr1)】使用Feign實現接口調用(八)

該系列項目整體介紹及源代碼請參照前面寫的一篇文章【springcloud學習(dalston.sr1)】項目整體介紹&#xff08;含源代碼&#xff09;&#xff08;一&#xff09; &#xff08;一&#xff09;Feign的理解 前面文章【springcloud學習(dalston.sr1)】服務消費者通過restTemplat…

SpringbBoot nginx代理獲取用戶真實IP

為了演示多級代理場景&#xff0c;我們分配了以下服務器資源&#xff1a; 10.1.9.98&#xff1a;充當客戶端10.0.3.137&#xff1a;一級代理10.0.4.105&#xff1a;二級代理10.0.4.129&#xff1a;三級代理10.0.4.120&#xff1a;服務器端 各級代理配置 以下是各級代理的基本配…

實驗九視圖索引

設計性實驗 1. 創建視圖V_A包括學號&#xff0c;姓名&#xff0c;性別&#xff0c;課程號&#xff0c;課程名、成績&#xff1b; 一個語句把學號103 課程號3-105 的姓名改為陸君茹1&#xff0c;性別為女 &#xff0c;然后查看學生表的信息變化&#xff0c;再把上述數據改為原…

typeof運算符和深拷貝

typeof運算符 識別所有值類型識別函數判斷是否是引用類型&#xff08;不可再細分&#xff09; //判斷所有值類型 let a; typeof a //undefined const strabc; typeof str //string const n100; typeof n //number const …

NAT/代理服務器/內網穿透

目錄 一 NAT技術 二 內網穿透/內網打洞 三 代理服務器 一 NAT技術 跨網絡傳輸的時候&#xff0c;私網不能直接訪問公網&#xff0c;就引入了NAT能講私網轉換為公網進行訪問&#xff0c;主要解決IPv4(2^32)地址不足的問題。 1. NAT原理 當某個內網想訪問公網&#xff0c;就必…

Git的安裝和配置(idea中配置Git)

一、Git的下載和安裝 前提條件&#xff1a;IntelliJ IDEA 版本是2023.3 &#xff0c;那么配置 Git 時推薦使用 Git 2.40.x 或更高版本 下載地址&#xff1a;CNPM Binaries Mirror 操作&#xff1a;打開鏈接 → 滾動到頁面底部 → 選擇2.40.x或更高版本的 .exe 文件&#xf…

【教程】Docker更換存儲位置

轉載請注明出處&#xff1a;小鋒學長生活大爆炸[xfxuezhagn.cn] 如果本文幫助到了你&#xff0c;歡迎[點贊、收藏、關注]哦~ 目錄 背景說明 更換教程 1. 停止 Docker 服務 2. 創建新的存儲目錄 3. 編輯 Docker 配置文件 4. 遷移已有數據到新位置 5. 啟動 Docker 服務 6…

PostgreSQL 配置設置函數

PostgreSQL 配置設置函數 PostgreSQL 提供了一組配置設置函數&#xff08;Configuration Settings Functions&#xff09;&#xff0c;用于查詢和修改數據庫服務器的運行時配置參數。這些函數為數據庫管理員提供了動態管理數據庫配置的能力&#xff0c;無需重啟數據庫服務。 …

sql server 2019 將單用戶狀態修改為多用戶狀態

記錄兩種將單用戶狀態修改為多用戶狀態&#xff0c;我曾經成功過的方法&#xff0c;供參考 第一種方法 USE master; GO -- 終止所有活動連接 DECLARE kill_connections NVARCHAR(MAX) ; SELECT kill_connections KILL CAST(session_id AS NVARCHAR(10)) ; FROM sys.dm_ex…