AI實現超級客戶端打印 支持APP 網頁 小程序 調用本地客戶端打印

核心思路都是:需要一個安裝在用戶電腦上的“中間人”程序(本地客戶端)來接管打印任務,然后通過某種通信方式命令這個客戶端進行打印。

下面我將分平臺詳細闡述各種實現思路、優缺點和適用場景。

一、核心思路與公共組件:本地客戶端

無論哪種方式,都需要一個部署在用戶打印電腦上的本地程序。這個程序的核心職責是:

監聽來自網絡的打印命令。

獲取打印數據和參數(如份數、雙面打印等)。

調用系統打印接口,完成實際打印。

這個本地客戶端通常可以用以下技術開發:

Electron (Node.js, 跨平臺)

二、各平臺調用方案

這是最主流和推薦的方案WebSocket,適用性最廣,尤其是對于瀏覽器環境。

工作原理:

注冊與連接:本地客戶端啟動后,向一個已知的服務器(或直接在本地)建立一個WebSocket連接或開始HTTP長輪詢,并告知服務器“我在這臺電腦上,準備好接收打印任務了”。通常需要客戶端上報一個唯一標識(如MAC地址、登錄用戶名等)。

發送打印任務:APP、網頁或小程序將打印數據(JSON、HTML、PDF文件流等)和打印機參數通過API發送到業務服務器。

服務器轉發:業務服務器根據一定的路由規則(如:用戶A的打印任務要發到他指定的電腦B),通過WebSocket或HTTP將任務推送給正在監聽的目標客戶端。

客戶端執行打印:目標本地客戶端收到任務后,解析數據,調用本地打印機驅動完成打印。

優點:

跨平臺兼容:對APP、網頁、小程序一視同仁,它們只與業務服務器交互,無需關心客戶端具體實現。

穿透性強:只要能上網,無論APP/網頁/小程序在哪里,都能將任務發送到指定地點的打印機。

集中管理:方便在服務端做任務隊列、日志記錄、權限控制等。

缺點:

依賴網絡:必須保證本地客戶端和業務服務器的網絡連通性。

架構復雜:需要額外開發和維護一個業務服務器作為中轉。

適用場景:

企業級應用、ERP、SaaS系統。

需要遠程打印或打印任務需要集中管理的場景。

方案二:自定義URL協議 (PC端網頁常用)
工作原理:

注冊協議:在安裝本地客戶端時,在系統注冊一個自定義URL協議(例如:diygwprint://)。

網頁觸發:在網頁中通過JavaScript代碼觸發這個鏈接(如:window.location.href = 'diygwprint://print?data=...')。

客戶端響應:系統會喚起注冊了該協議的本地客戶端,并將URL中的參數傳遞給它。

客戶端處理:客戶端解析URL參數(如base64編碼的打印數據),執行打印。

優點:

簡單直接:對于本地環境,實現起來非常快速。

無中間服務器:無需業務服務器中轉,延遲低。

缺點:

僅限PC瀏覽器:APP和小程序無法直接使用此方式。

數據量限制:URL長度有限制,不適合傳輸大量數據(如圖片、復雜的HTML)。

安全性:需要防范惡意網站隨意調用。

體驗問題:瀏覽器通常會彈出“是否允許打開此應用”的提示,體驗不完美。

適用場景:

簡單的PC端網頁調用本地客戶端場景,傳輸的數據量較小。

作為WebSocket方案的補充或備選方案。


四、打印數據格式建議
傳遞給本地客戶端的數據最好結構化且通用:

JSON + 模板:發送JSON數據和模板名稱,客戶端根據模板渲染后打印。靈活且數據量小。

HTML:直接發送HTML字符串,客戶端使用內置瀏覽器控件(如C#的WebBrowser)打印。開發簡單,但樣式控制可能不一致。

PDF:服務器端或前端生成PDF文件流/URL,客戶端下載并打印。效果最精確,跨平臺一致性最好,強烈推薦。

五、實戰流程示例 (以最推薦的WebSocket方案為例)
開發本地客戶端:

用Electron寫一個Windows程序。

集成WebSocket客戶端庫,連接至業務服務器的WebSocket服務。

實現登錄認證、心跳保持、接收打印指令({command: ‘print’, data: {...}, printer: ‘...’})。

接收到指令后,解析數據,調用System.Drawing.Printing命名空間下的類進行打印。

開發業務服務器:

提供WebSocket服務端。

提供RESTful API供APP/網頁/小程序提交打印任務。

實現任務路由和轉發邏輯。

const { ipcRenderer } = require('electron');class ElectronHistoryManager {constructor() {this.currentTab = 'history';this.currentPage = 1;this.pageSize = 20;this.totalPages = 1;this.allHistory = [];this.allQueue = [];this.filteredData = [];this.filters = {status: '',date: '',printer: '',search: ''};this.init();}async init() {await this.loadData();this.setupEventListeners();this.renderData();this.updateStats();}setupEventListeners() {// 搜索輸入框事件document.getElementById('searchInput').addEventListener('input', (e) => {this.filters.search = e.target.value;this.applyFilters();});// 篩選器事件document.getElementById('statusFilter').addEventListener('change', (e) => {this.filters.status = e.target.value;this.applyFilters();});document.getElementById('dateFilter').addEventListener('change', (e) => {this.filters.date = e.target.value;this.applyFilters();});document.getElementById('printerFilter').addEventListener('change', (e) => {this.filters.printer = e.target.value;this.applyFilters();});// 模態框點擊外部關閉document.getElementById('contentModal').addEventListener('click', (e) => {if (e.target.id === 'contentModal') {this.closeModal();}});}async loadData() {try {const result = await ipcRenderer.invoke('get-print-history');if (result.success) {this.allHistory = result.history || [];this.allQueue = result.queue || [];this.updatePrinterFilter();} else {console.error('獲取打印歷史失敗:', result.error);this.showError('獲取打印歷史失敗: ' + result.error);}} catch (error) {console.error('加載數據失敗:', error);this.showError('加載數據失敗: ' + error.message);}}updatePrinterFilter() {const printerSelect = document.getElementById('printerFilter');const allData = [...this.allHistory, ...this.allQueue];const printers = [...new Set(allData.map(job => job.printerName).filter(Boolean))];// 清空現有選項(保留"全部打印機")printerSelect.innerHTML = '<option value="">全部打印機</option>';// 添加打印機選項printers.forEach(printer => {const option = document.createElement('option');option.value = printer;option.textContent = printer;printerSelect.appendChild(option);});}updateStats() {const totalJobs = this.allHistory.length;const completedJobs = this.allHistory.filter(job => job.status === 'completed').length;const failedJobs = this.allHistory.filter(job => job.status === 'failed').length;const queueJobs = this.allQueue.length;document.getElementById('totalJobs').textContent = totalJobs;document.getElementById('completedJobs').textContent = completedJobs;document.getElementById('failedJobs').textContent = failedJobs;document.getElementById('queueJobs').textContent = queueJobs;}switchTab(tab) {this.currentTab = tab;this.currentPage = 1;// 更新標簽樣式document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));event.target.classList.add('active');// 顯示對應內容document.getElementById('historyTab').style.display = tab === 'history' ? 'block' : 'none';document.getElementById('queueTab').style.display = tab === 'queue' ? 'block' : 'none';this.applyFilters();}applyFilters() {const sourceData = this.currentTab === 'history' ? this.allHistory : this.allQueue;this.filteredData = sourceData.filter(job => {// 文本搜索if (this.filters.search) {const searchTerm = this.filters.search.toLowerCase();const searchableText = [job.id || '',job.printerName || '',job.content || '',job.userId || '',job.status || ''].join(' ').toLowerCase();if (!searchableText.includes(searchTerm)) {return false;}}// 狀態篩選if (this.filters.status && job.status !== this.filters.status) {return false;}// 日期篩選if (this.filters.date) {const jobDate = new Date(job.createdAt).toISOString().split('T')[0];if (jobDate !== this.filters.date) {return false;}}// 打印機篩選if (this.filters.printer && job.printerName !== this.filters.printer) {return false;}return true;});this.currentPage = 1;this.calculatePagination();this.renderData();}calculatePagination() {this.totalPages = Math.ceil(this.filteredData.length / this.pageSize);if (this.totalPages === 0) this.totalPages = 1;}renderData() {const loadingState = document.getElementById('loadingState');const emptyState = document.getElementById('emptyState');const pagination = document.getElementById('pagination');// 隱藏加載狀態loadingState.style.display = 'none';if (this.filteredData.length === 0) {emptyState.style.display = 'block';pagination.style.display = 'none';return;}emptyState.style.display = 'none';// 計算當前頁的數據const startIndex = (this.currentPage - 1) * this.pageSize;const endIndex = startIndex + this.pageSize;const pageData = this.filteredData.slice(startIndex, endIndex);// 渲染表格const tbody = this.currentTab === 'history' ? document.getElementById('historyTableBody') : document.getElementById('queueTableBody');tbody.innerHTML = '';pageData.forEach(job => {const row = this.createDataRow(job);tbody.appendChild(row);});// 更新分頁this.updatePagination();pagination.style.display = 'flex';}createDataRow(job) {const row = document.createElement('tr');const formatDate = (dateString) => {const date = new Date(dateString);return date.toLocaleString('zh-CN');};const getStatusClass = (status) => {const statusMap = {'success': 'status-completed','completed': 'status-completed','error': 'status-failed','failed': 'status-failed','pending': 'status-pending','queued': 'status-pending','printing': 'status-printing','cancelled': 'status-cancelled'};return statusMap[status] || 'status-pending';};const getStatusText = (status) => {const statusMap = {'success': '已完成','completed': '已完成','error': '失敗','failed': '失敗','pending': '等待中','queued': '已加入隊列','printing': '打印中','cancelled': '已取消'};return statusMap[status] || status;};if (this.currentTab === 'history') {row.innerHTML = `<td>${job.id}</td><td>${formatDate(job.createdAt)}</td><td>${job.printerName || '-'}</td><td><div class="content-preview" onclick="showContentDetail('${job.id}')" title="點擊查看完整內容">${job.content ? job.content.substring(0, 50) + (job.content.length > 50 ? '...' : '') : '-'}</div></td><td><span class="status ${getStatusClass(job.status)}">${getStatusText(job.status)}</span>${job.error ? `<br><small style="color: #dc3545;">${job.error}</small>` : ''}</td><td>${job.copies || 1}</td><td>${job.userId || '-'}</td><td><div class="actions">${(job.status === 'completed' || job.status === 'success' || job.status === 'failed' || job.status === 'error' || job.status === 'cancelled') ? `<button class="btn btn-success btn-sm" onclick="reprintJob('${job.id}')">重打</button>` : ''}</div></td>`;} else {row.innerHTML = `<td>${job.id}</td><td>${formatDate(job.createdAt)}</td><td>${job.printerName || '-'}</td><td><div class="content-preview" onclick="showContentDetail('${job.id}')" title="點擊查看完整內容">${job.content ? job.content.substring(0, 50) + (job.content.length > 50 ? '...' : '') : '-'}</div></td><td><span class="status ${getStatusClass(job.status)}">${getStatusText(job.status)}</span></td><td>${job.copies || 1}</td><td>${job.retryCount || 0}</td><td><div class="actions">${(job.status === 'pending' || job.status === 'queued' || job.status === 'printing') ? `<button class="btn btn-danger btn-sm" onclick="cancelJob('${job.id}')">取消</button>` : ''}</div></td>`;}return row;}updatePagination() {const pageInfo = document.getElementById('pageInfo');pageInfo.textContent = `第 ${this.currentPage} 頁,共 ${this.totalPages} 頁`;// 更新按鈕狀態const prevBtn = document.querySelector('.pagination button:first-child');const nextBtn = document.querySelector('.pagination button:last-child');prevBtn.disabled = this.currentPage === 1;nextBtn.disabled = this.currentPage === this.totalPages;}previousPage() {if (this.currentPage > 1) {this.currentPage--;this.renderData();}}nextPage() {if (this.currentPage < this.totalPages) {this.currentPage++;this.renderData();}}showContentDetail(jobId) {const allData = [...this.allHistory, ...this.allQueue];const job = allData.find(j => j.id === jobId);if (job && job.content) {document.getElementById('contentDetail').textContent = job.content;document.getElementById('contentModal').style.display = 'block';}}closeModal() {document.getElementById('contentModal').style.display = 'none';}async reprintJob(jobId) {const job = this.allHistory.find(j => j.id === jobId);if (!job) {this.showError('找不到指定的打印任務');return;}if (confirm(`確定要重新打印任務 ${jobId} 嗎?`)) {try {const result = await ipcRenderer.invoke('reprint-job', {content: job.content,printerName: job.printerName,copies: job.copies,userId: job.userId,clientId: job.clientId});if (result.success) {this.showSuccess('重打任務已提交');await this.refreshData();} else {this.showError('重打任務提交失敗: ' + result.error);}} catch (error) {console.error('重打任務失敗:', error);this.showError('重打任務失敗: ' + error.message);}}}async cancelJob(jobId) {if (confirm(`確定要取消打印任務 ${jobId} 嗎?`)) {try {const result = await ipcRenderer.invoke('cancel-job', jobId);if (result.success) {this.showSuccess('打印任務已取消');await this.refreshData();} else {this.showError('取消打印任務失敗: ' + result.error);}} catch (error) {console.error('取消打印任務失敗:', error);this.showError('取消打印任務失敗: ' + error.message);}}}async clearHistory() {if (confirm('確定要清除所有歷史記錄嗎?此操作不可恢復。')) {try {const result = await ipcRenderer.invoke('clear-history');if (result.success) {this.showSuccess('歷史記錄已清除');await this.refreshData();} else {this.showError('清除歷史記錄失敗: ' + result.error);}} catch (error) {console.error('清除歷史記錄失敗:', error);this.showError('清除歷史記錄失敗: ' + error.message);}}}clearFilters() {this.filters = {status: '',date: '',printer: '',search: ''};document.getElementById('searchInput').value = '';document.getElementById('statusFilter').value = '';document.getElementById('dateFilter').value = '';document.getElementById('printerFilter').value = '';this.applyFilters();}async refreshData() {document.getElementById('loadingState').style.display = 'block';document.getElementById('historyTab').style.display = 'none';document.getElementById('queueTab').style.display = 'none';document.getElementById('emptyState').style.display = 'none';await this.loadData();this.applyFilters();this.updateStats();// 恢復標簽顯示if (this.currentTab === 'history') {document.getElementById('historyTab').style.display = 'block';} else {document.getElementById('queueTab').style.display = 'block';}}showSuccess(message) {// 簡單的成功提示const toast = document.createElement('div');toast.style.cssText = `position: fixed;top: 20px;right: 20px;background: #28a745;color: white;padding: 15px 20px;border-radius: 4px;z-index: 10000;box-shadow: 0 2px 10px rgba(0,0,0,0.2);`;toast.textContent = message;document.body.appendChild(toast);setTimeout(() => {document.body.removeChild(toast);}, 3000);}showError(message) {// 簡單的錯誤提示const toast = document.createElement('div');toast.style.cssText = `position: fixed;top: 20px;right: 20px;background: #dc3545;color: white;padding: 15px 20px;border-radius: 4px;z-index: 10000;box-shadow: 0 2px 10px rgba(0,0,0,0.2);`;toast.textContent = message;document.body.appendChild(toast);setTimeout(() => {document.body.removeChild(toast);}, 5000);}
}// 全局函數
function switchTab(tab) {if (window.historyManager) {window.historyManager.switchTab(tab);}
}function applyFilters() {if (window.historyManager) {window.historyManager.applyFilters();}
}function clearFilters() {if (window.historyManager) {window.historyManager.clearFilters();}
}function refreshData() {if (window.historyManager) {window.historyManager.refreshData();}
}function clearHistory() {if (window.historyManager) {window.historyManager.clearHistory();}
}function previousPage() {if (window.historyManager) {window.historyManager.previousPage();}
}function nextPage() {if (window.historyManager) {window.historyManager.nextPage();}
}function reprintJob(jobId) {if (window.historyManager) {window.historyManager.reprintJob(jobId);}
}function cancelJob(jobId) {if (window.historyManager) {window.historyManager.cancelJob(jobId);}
}function showContentDetail(jobId) {if (window.historyManager) {window.historyManager.showContentDetail(jobId);}
}function closeModal() {if (window.historyManager) {window.historyManager.closeModal();}
}// 標題欄控制功能
let isMaximized = false;function minimizeWindow() {ipcRenderer.send('history-window-minimize');
}function toggleMaximize() {ipcRenderer.send('history-window-toggle-maximize');
}function closeWindow() {ipcRenderer.send('history-window-close');
}// 監聽窗口狀態變化
ipcRenderer.on('window-maximized', () => {isMaximized = true;updateTitlebarDrag();
});ipcRenderer.on('window-unmaximized', () => {isMaximized = false;updateTitlebarDrag();
});// 更新標題欄拖動狀態
function updateTitlebarDrag() {const titlebar = document.querySelector('.custom-titlebar');if (titlebar) {titlebar.style.webkitAppRegion = isMaximized ? 'no-drag' : 'drag';}
}// 創建全局實例
document.addEventListener('DOMContentLoaded', () => {window.historyManager = new ElectronHistoryManager();// 設置標題欄雙擊事件const titlebar = document.querySelector('.custom-titlebar');if (titlebar) {titlebar.addEventListener('dblclick', (e) => {// 排除控制按鈕區域if (!e.target.closest('.titlebar-controls')) {toggleMaximize();}});}
});

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

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

相關文章

Java集合(Collection、Map、轉換)

? 推薦使用 ? 已過時 1. Collection Collection 是集合框架的根接口之一&#xff0c;它是所有單列集合&#xff08;如 List、Set、Queue 等&#xff09;的公共父接口。Collection 接口定義了集合的基本操作&#xff0c;比如添加、刪除、遍歷等。 Collection ├── List │ …

全國網絡安全知識競賽有哪些

全國范圍內有多種類型的網絡安全知識競賽&#xff0c;涵蓋國家級、行業級、高校、青少年和企業等多個維度。以下是主要的網絡安全知識競賽分類及詳細介紹&#xff1a;一、國家級網絡安全競賽"強網杯"全國網絡安全挑戰賽主辦單位&#xff1a;中央網信辦、河南省人民政…

系統架構設計師備考第1天——系統架構概述

一、架構本質與角色定位架構 系統的骨架 ? 核心作用&#xff1a; 決定系統的健壯性、生命周期、擴展性銜接需求與實現&#xff0c;保障早期質量 &#x1f468;&#x1f4bb; 架構師核心能力&#xff1a;能力維度具體要求技術掌控力精通基礎技術&#xff0c;洞悉局部瓶頸決策設…

c#實現鼠標mousemove事件抽稀,避免大數據阻塞網絡

這個封裝類可以獨立于具體的網絡傳輸邏輯&#xff0c;為任何需要減少鼠標移動數據量的應用提供靈敏度和數據量優化。 核心優化功能 1. 靈敏度調整 // 減少微小移動的數據發送 (2, 1) 0.5 → (1, 0) // 忽略微小移動2. 移動累積 // 累積多次小移動&#xff0c;批量發送 (1, 0) …

機器學習 [白板推導](十三)[條件隨機場]

? 17. 條件隨機場&#xff08;Conditional Random Field&#xff0c;CRF&#xff09; 17.1. 背景 機器學習分類模型中&#xff0c;有硬分類和軟分類兩種主流思想&#xff0c;其中硬分類模型有支持向量機SVM&#xff08;最大化幾何間隔&#xff09;、感知機PLA&#xff08;誤…

調味品生產過程優化中Ethernet/IP轉ProfiNet協議下施耐德 PLC 與歐姆龍 PLC 的關鍵通信協同案例

案例背景在食品飲料行業&#xff0c;生產過程的精準控制對于保證產品質量和安全至關重要。某知名食品飲料企業的生產線上&#xff0c;前處理、灌裝和包裝環節采用了基于 ProfiNet 主站的施耐德 M340 系列 PLC 進行控制&#xff0c;以確保生產過程的穩定性和精確性。而原料倉儲和…

Elasticsearch vs 單表LIKE查詢性能對比

關鍵因素影響 1、索引結構&#xff1a; .Elasticsearch使用倒排索引&#xff0c;特別適合文本搜索 .傳統數據庫即使有索引&#xff0c;對LIKE %keyword%這種模式也無法有效利用 2、查詢復雜度&#xff1a; .簡單查詢&#xff1a;ES快5-10倍 .復雜組合查詢&#xff1a;ES可能快1…

如何通過WordPress聯盟營銷獲取潛在客戶

您是否經營著一個銷售周期較長的業務&#xff1f; 那么你就會知道&#xff0c;從首次訪問者那里獲得立即銷售的機會是很少見的。 當然&#xff0c;您的潛在客戶在進行重大投資之前需要時間進行研究、比較各種方案并建立信任。這時&#xff0c;聯盟營銷線索挖掘就成為您的秘密…

git實戰(8)git高階命令分析【結合使用場景】

以下是 Git 高階命令分享&#xff0c;涵蓋高效協作、歷史重構、問題排查等場景&#xff0c;助你成為 Git 高手&#xff1a; 一、歷史重構與清理 1. 交互式變基&#xff08;改寫歷史&#xff09; git rebase -i HEAD~3 # 修改最近3次提交操作選項&#xff1a; reword&#xff1…

生成一個豎直放置的div,寬度是350px,上面是標題固定高度50px,下面是自適應高度的div,且有滾動條

<!-- 我要生成一個豎直放置的div&#xff0c;寬度是350px&#xff0c;上面是標題固定高度50px&#xff0c;下面是自適應高度的div&#xff0c;且有滾動條。 --><style>html,body{/* height:100vh; */margin:10px; padding:10px;} </style><div style"…

題解:P13754 【MX-X17-T3】Distraction_逆序對_前綴和_Ad-hoc_算法競賽C++

Beginning 這道題思維難度很大&#xff0c;有兩個難點其實都不好解決&#xff0c;但因為其代碼太過弱智所以只是綠題。 本題解詳細地分析了做題時的歷程與思路&#xff0c;所以希望大家可以仔細地完整閱讀。 Analysis 首先先大體觀察一下題目的性質&#xff1a;nnn 是排列&…

Android Studio下載gradle文件很慢的捷徑之路

小伙伴們是不是也經常遇到導入新的項目時&#xff0c;AS一直卡在gradle的下載中。下面介紹一種簡單暴力的方式來處理這個問題。 首先我們到gradle的官網下載自己想要的gradle版本。我這里以gradle7.5為例。點擊下載gradle-7.5-bin.zip的壓縮包。下載完成后無需解壓。直接到C:\U…

【C++】全局變量/靜態變量的初始化時機

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄一、全局變量下斷點調試1. int a 10; —— 不能卡住斷點2. static int b; —— 不能卡住斷點3. MyClass c; —— 可以卡住斷點4. static MyClass d; —— 可以卡住斷…

水體反光 + 遮擋難題破解!陌訊多模態融合算法在智慧水務的實測優化

一、智慧水務行業檢測痛點&#xff08;數據支撐 場景難點&#xff09; 根據《2023 年中國智慧水務發展報告》&#xff0c;當前水務監控系統在核心業務場景中面臨兩大效率瓶頸&#xff0c;直接影響水廠運維與供水安全&#xff1a; 高誤報率導致運維資源浪費&#xff1a;水廠沉…

C++的指針和引用:

目錄 引用&#xff1a; 注意&#xff1a; 左值引用和右值引用&#xff1a; 左值引用&#xff1a; 右值引用&#xff1a; 指針&#xff1a; 指針與引用的區別&#xff1a; 引用&#xff1a; 在C中&#xff0c;?引用?是一種為已存在變量創建別名的機制&#xff0c;它允…

圖像處理中的偽影

目錄 一、塊效應偽影 / 塊狀偽影 二、 去除塊狀偽影 三、振鈴偽影 一、塊效應偽影 / 塊狀偽影 塊狀偽影(Blocking Artefacts)是對經過變換編碼的圖像進行重建時&#xff0c;圖像中可能會出現壓縮過程產生的可見偽影。基于塊的變換編碼中&#xff0c;一種常見偽影是 “塊效應…

Java:對象的淺拷貝與深拷貝

目錄 一、概念 二、實現方式 2.1 淺拷貝&#xff08;不推薦&#xff09; 2.2 深拷貝 2.2.1 方法一&#xff1a;重寫 clone() 方法并遞歸克隆&#xff08;常用&#xff09; 2.2.2 方法二&#xff1a;通過序列化實現&#xff08;更強大&#xff0c;但更重&#xff09; 2.2…

佰鈞成 社招 一面

1. “評估需求、排期”的工作流程&#xff1f; “我的工作流程一般是這樣的&#xff1a; 需求評審&#xff1a; 首先會和產品、后端同學一起過需求&#xff0c;確保我完全理解了業務背景和要實現的價值&#xff0c;而不僅僅是功能點。技術方案設計&#xff1a; 之后&#xff0c…

最短路徑問題(圖論)

1 Floyd 作用&#xff1a; 求圖中所有頂點之間的最短路徑&#xff0c;包括有向圖或者無向圖&#xff0c;權重正負皆可&#xff0c;用來一次性求所有點之間的最短路徑。 思路是 通過逐步擴大中間層&#xff0c;使得最短路徑不斷被更新&#xff0c;直到中間層擴大到n位置&#…

2025年8月新算法—云漂移優化算法(Cloud Drift Optimization Algorithm, CDO)

1、簡介 這項研究介紹了云漂移優化&#xff08;數位長&#xff09;算法&#xff0c;這是一種創新的自然啟發的元啟發式方法來解決復雜的優化問題。CDO模仿受大氣力影響的云粒子的動態行為&#xff0c;在探索和利用之間取得了微妙的平衡。它具有自適應權重調整機制&#xff0c;可…