Tauri 跨平台开发指南及实战:用前端技术征服桌面应用(合集-万字长文)

厌倦了笨重的Electron应用?想要构建体积小、性能高、安全可靠的跨平台桌面应用?Tauri将是你的不二之选!本教程带你从入门到精通,掌握这个下一代桌面应用开发框架,并通过实战APK分析工具项目,将理论知识转化为实际应用。无论你是前端开发者还是Rust爱好者,这篇万字长文都将助你快速驾驭Tauri的强大能力!

目录

  • 什么是 Tauri
  • Tauri vs Electron
  • 环境准备
  • 创建首个 Tauri 应用
  • Tauri 架构详解
  • 前后端通信
  • 文件系统访问
  • 安全策略
  • 打包与发布
  • 实战项目:APK 分析工具
  • 性能优化
  • 常见问题与解决方案
  • 扩展资源

什么是 Tauri

Tauri 是一个构建跨平台桌面应用的现代化框架,它允许开发者使用 Web 技术(HTML、CSS、JavaScript/TypeScript)来构建应用的 UI,同时使用 Rust 作为后端来保证性能和安全性。与传统的 Electron 不同,Tauri 应用通常更小、更快、更安全。

Tauri 的核心理念是:

  • 安全优先:精细的权限系统和严格的 CSP(内容安全策略)
  • 性能至上:基于 Rust 构建的高性能后端
  • 资源效率:更小的应用大小和更低的内存占用
  • 隐私保护:默认不收集任何数据

自 Tauri 2.0 起,该框架已经成熟并得到了广泛应用,支持 Windows、macOS 和 Linux 平台,并提供了丰富的 API 和插件生态系统。

Tauri vs Electron

特性TauriElectron
底层架构Rust + 系统 WebViewChromium + Node.js
应用大小小(~3-10MB)大(~120MB+)
内存占用
安全性高(精细权限控制)中等
生态系统增长中成熟
学习曲线陡峭(需要了解 Rust)平缓(纯 JavaScript)
开发体验需要管理前后端接口单一运行时
支持平台Windows, macOS, LinuxWindows, macOS, Linux

环境准备

在开始使用 Tauri 前,需要配置好开发环境:

1. 安装 Rust

# Windows/macOS/Linux
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh# 或在 Windows 上通过安装程序
# 访问 https://www.rust-lang.org/tools/install 下载安装程序

验证安装:

rustc --version
cargo --version

2. 安装系统依赖

Windows

  • 安装 Visual Studio 构建工具
  • 选择"C++ 构建工具"
  • 安装 WebView2

macOS

xcode-select --install

Linux (Ubuntu/Debian)

sudo apt update
sudo apt install libwebkit2gtk-4.0-dev \build-essential \curl \wget \libssl-dev \libgtk-3-dev \libayatana-appindicator3-dev \librsvg2-dev

3. 安装 Node.js 和包管理器

推荐使用 Node.js 16+ 和 pnpm:

# 安装 nvm (Node Version Manager)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash# 安装并使用 Node.js
nvm install 18
nvm use 18# 安装 pnpm
npm install -g pnpm

4. 安装 Tauri CLI

cargo install tauri-cli
# 或
npm install -g @tauri-apps/cli

创建首个 Tauri 应用

使用 Tauri CLI 创建项目

# 交互式创建新项目
pnpm create tauri-app my-app# 按提示选择前端框架和配置
cd my-app

项目结构

my-app/
├── src/                 # 前端代码
│   ├── App.vue          # Vue 主组件
│   └── main.js          # 入口点
├── src-tauri/           # Rust 后端代码
│   ├── src/             # Rust 源码
│   │   └── main.rs      # 程序入口
│   ├── Cargo.toml       # Rust 依赖配置
│   ├── tauri.conf.json  # Tauri 配置
│   └── build.rs         # 构建脚本
└── package.json         # 前端依赖

开发与调试

# 启动开发模式
pnpm run tauri dev# 构建生产版本
pnpm run tauri build

Tauri 架构详解

Tauri 采用前后端分离的架构:

  1. 前端:使用 Web 技术(Vue、React、Svelte 等)构建 UI
  2. 后端:使用 Rust 构建本地功能和系统集成
  3. 核心:WebView 窗口管理和 IPC(进程间通信)系统

关键概念:

  • Window:应用窗口管理
  • Command:暴露给前端的 Rust 函数
  • Event:前后端之间的消息传递系统
  • State:多窗口共享的状态管理
  • Plugin:扩展 Tauri 功能的模块

前后端通信

定义 Rust 命令

src-tauri/src/main.rs 中:

#[tauri::command]
fn hello(name: &str) -> String {format!("Hello, {}!", name)
}fn main() {tauri::Builder::default().invoke_handler(tauri::generate_handler![hello]).run(tauri::generate_context!()).expect("error while running tauri application");
}

从前端调用 Rust 函数

import { invoke } from '@tauri-apps/api/core';// 调用 Rust 命令
async function greet() {const response = await invoke('hello', { name: 'Tauri' });console.log(response); // "Hello, Tauri!"
}

在 Rust 中访问前端状态

#[tauri::command]
async fn save_settings(window: tauri::Window, settings: String) -> Result<(), String> {// 操作窗口window.set_title(&format!("New settings: {}", settings)).map_err(|e| e.to_string())?;// 执行其他操作Ok(())
}

事件系统

Rust 发送事件

#[tauri::command]
fn start_process(window: tauri::Window) -> Result<(), String> {// 启动长时间运行的任务std::thread::spawn(move || {// 执行任务window.emit("process-update", Some(42)).expect("failed to emit event");});Ok(())
}

前端监听事件

import { listen } from '@tauri-apps/api/event';// 监听事件
const unlisten = await listen('process-update', (event) => {console.log('Got update:', event.payload);
});// 停止监听
unlisten();

文件系统访问

Tauri 提供了安全的文件系统访问 API,在 Tauri 2.0 中通过插件提供:

import { writeTextFile, readTextFile } from '@tauri-apps/plugin-fs';// 读取文件
async function readFile() {try {const contents = await readTextFile('example.txt');console.log(contents);} catch (err) {console.error('Failed to read file:', err);}
}// 写入文件
async function writeFile() {try {await writeTextFile('output.txt', 'Hello, Tauri!');console.log('File written successfully');} catch (err) {console.error('Failed to write file:', err);}
}

安全策略

Tauri 实现了多层安全保护:

  1. 权限系统:精细控制应用可以访问的资源

tauri.conf.json 中配置:

{"tauri": {"allowlist": {"fs": {"scope": {"allow": ["$APP/*"],"deny": ["$APP/config.json"]}},"shell": {"execute": false,"sidecar": false,"open": true}}}
}
  1. CSP:内容安全策略控制资源加载
{"tauri": {"security": {"csp": "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'"}}
}
  1. 沙箱隔离:限制应用能力

打包与发布

配置应用信息

src-tauri/tauri.conf.json 中:

{"package": {"productName": "My Tauri App","version": "1.0.0"},"build": {"distDir": "../dist","devPath": "http://localhost:5173","beforeDevCommand": "pnpm dev","beforeBuildCommand": "pnpm build"},"tauri": {"bundle": {"identifier": "com.mycompany.myapp","icon": ["icons/32x32.png","icons/128x128.png","icons/128x128@2x.png"]}}
}

构建生产版本

pnpm run tauri build

构建产物位于 src-tauri/target/release/bundle/,包括:

  • Windows: .exe, .msi
  • macOS: .app, .dmg
  • Linux: .AppImage, .deb, .rpm

自动更新

tauri.conf.json 中配置:

{"tauri": {"updater": {"active": true,"endpoints": ["https://releases.myapp.com/{{target}}/{{current_version}}"],"dialog": true,"pubkey": "YOUR_PUBLIC_KEY"}}
}

实战项目:APK 分析工具

本节将介绍如何使用 Tauri 构建一个实际的 APK 分析工具,与本项目 apkparse-tauri 类似。
项目地址:ApkParse Github

架构设计

APK 分析工具由以下部分组成:

  1. 前端:Vue 3 + TypeScript UI
  2. 后端:Rust 处理 APK 解析
  3. 核心功能:文件解析、权限分析、签名验证

项目创建

# 创建 Tauri + Vue 项目
pnpm create tauri-app apk-analyzer
cd apk-analyzer

Rust 后端实现

src-tauri/src/ 中创建 APK 解析器:

// src-tauri/src/apk_parser.rs
use serde::{Serialize, Deserialize};
use std::path::Path;
use std::io::Read;
use std::fs::File;
use zip::ZipArchive;#[derive(Debug, Serialize, Deserialize)]
pub struct ApkInfo {pub package_name: String,pub version_name: String,pub version_code: String,pub permissions: Vec<String>,
}pub struct ApkParser;impl ApkParser {pub fn parse(path: &Path) -> Result<ApkInfo, String> {// 打开 APK 文件 (实际上是 ZIP 文件)let file = File::open(path).map_err(|e| format!("Failed to open APK: {}", e))?;let mut archive = ZipArchive::new(file).map_err(|e| format!("Invalid APK format: {}", e))?;// 提取 AndroidManifest.xml// 注意:实际实现需要解析二进制 AndroidManifest.xml// 这里简化处理// 模拟解析结果Ok(ApkInfo {package_name: "com.example.app".to_string(),version_name: "1.0.0".to_string(),version_code: "1".to_string(),permissions: vec!["android.permission.INTERNET".to_string(),"android.permission.READ_EXTERNAL_STORAGE".to_string(),],})}
}

定义 Tauri 命令:

// src-tauri/src/commands.rs
use crate::apk_parser::{ApkParser, ApkInfo};
use std::path::Path;#[tauri::command]
pub fn parse_apk(path: String) -> Result<ApkInfo, String> {let path = Path::new(&path);ApkParser::parse(path)
}

注册命令:

// src-tauri/src/main.rs
mod apk_parser;
mod commands;use commands::parse_apk;fn main() {tauri::Builder::default().invoke_handler(tauri::generate_handler![parse_apk]).run(tauri::generate_context!()).expect("error while running tauri application");
}

前端实现

创建上传组件:

<!-- src/components/ApkUploader.vue -->
<template><div class="uploader"@dragover.prevent@drop.prevent="onFileDrop"@click="openFileDialog"><div class="upload-area"><div v-if="!isUploading"><p>拖放 APK 文件或点击选择</p></div><div v-else><p>分析中...</p></div></div></div>
</template><script setup>
import { ref } from 'vue';
import { invoke } from '@tauri-apps/api/tauri';
import { open } from '@tauri-apps/plugin-dialog';const isUploading = ref(false);
const emit = defineEmits(['result']);async function openFileDialog() {try {const selected = await open({multiple: false,filters: [{name: 'APK Files',extensions: ['apk']}]});if (selected) {processApkFile(selected);}} catch (err) {console.error('Failed to open file dialog:', err);}
}async function onFileDrop(e) {const files = e.dataTransfer.files;if (files.length > 0) {const fileInfo = files[0];// 在 Tauri 中,我们需要获取真实路径// 浏览器 API 受限,需要通过 Tauri 路径转换if ('path' in fileInfo) {processApkFile(fileInfo.path);}}
}async function processApkFile(path) {isUploading.value = true;try {// 调用 Rust 命令解析 APKconst result = await invoke('parse_apk', { path });emit('result', result);} catch (err) {console.error('Failed to parse APK:', err);} finally {isUploading.value = false;}
}
</script><style scoped>
.uploader {border: 2px dashed #ccc;border-radius: 8px;padding: 40px;text-align: center;cursor: pointer;transition: all 0.3s ease;
}.uploader:hover {border-color: #4a86e8;background-color: rgba(74, 134, 232, 0.05);
}
</style>

创建结果显示组件:

<!-- src/components/AnalysisResult.vue -->
<template><div v-if="apkInfo" class="result-container"><h2>APK 分析结果</h2><div class="info-section"><h3>基本信息</h3><p><strong>包名:</strong>{{ apkInfo.package_name }}</p><p><strong>版本:</strong>{{ apkInfo.version_name }} ({{ apkInfo.version_code }})</p></div><div class="permissions-section"><h3>权限 ({{ apkInfo.permissions.length }})</h3><ul><li v-for="(perm, index) in apkInfo.permissions" :key="index">{{ formatPermissionName(perm) }}</li></ul></div></div>
</template><script setup>
import { defineProps } from 'vue';const props = defineProps({apkInfo: Object
});function formatPermissionName(permission) {// 简化权限名称显示return permission.split('.').pop() || permission;
}
</script><style scoped>
.result-container {padding: 20px;background: #f9f9f9;border-radius: 8px;margin-top: 20px;
}.info-section, .permissions-section {margin-bottom: 20px;
}h3 {border-bottom: 1px solid #eee;padding-bottom: 8px;
}ul {list-style-type: none;padding: 0;
}li {padding: 6px 0;border-bottom: 1px dashed #eee;
}
</style>

主应用组件:

<!-- src/App.vue -->
<template><div class="container"><h1>APK 分析工具</h1><p class="description">上传 Android APK 文件进行分析</p><ApkUploader @result="handleResult" /><AnalysisResult :apk-info="apkInfo" /></div>
</template><script setup>
import { ref } from 'vue';
import ApkUploader from './components/ApkUploader.vue';
import AnalysisResult from './components/AnalysisResult.vue';const apkInfo = ref(null);function handleResult(result) {apkInfo.value = result;
}
</script><style>
body {font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;margin: 0;padding: 0;background: #fafafa;color: #333;
}.container {max-width: 800px;margin: 0 auto;padding: 40px 20px;
}h1 {text-align: center;margin-bottom: 10px;
}.description {text-align: center;color: #666;margin-bottom: 30px;
}
</style>

实现完整功能

对于完整的 APK 分析工具,还需添加以下功能:

  1. Rust 扩展功能

    • 处理二进制 AndroidManifest.xml
    • 提取签名信息
    • 分析 APK 组件
    • 计算哈希值
  2. UI 增强

    • 添加详细分析页面
    • 实现结果导出功能
    • 添加历史记录
  3. 安全功能

    • 权限风险评估
    • 恶意软件检测集成
    • 证书验证

性能优化

Rust 性能优化

  1. 并行处理:使用 Rust 的并行处理能力
use rayon::prelude::*;fn process_large_dataset(data: &[u8]) -> Vec<u8> {data.par_chunks(1024).map(|chunk| process_chunk(chunk)).collect()
}
  1. 异步命令:避免 UI 冻结
#[tauri::command]
async fn long_task() -> Result<String, String> {// 执行耗时操作tokio::time::sleep(std::time::Duration::from_secs(2)).await;Ok("Done".to_string())
}

前端优化

  1. 虚拟列表:处理大量数据
<template><div class="list-container" ref="container"><divv-for="item in visibleItems":key="item.id":style="{ top: `${item.position}px` }"class="list-item">{{ item.content }}</div></div>
</template><script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue';const props = defineProps({items: Array
});const container = ref(null);
const scrollTop = ref(0);
const itemHeight = 50;
const visibleCount = ref(10);onMounted(() => {const el = container.value;if (el) {el.addEventListener('scroll', handleScroll);visibleCount.value = Math.ceil(el.clientHeight / itemHeight) + 2;}
});onUnmounted(() => {const el = container.value;if (el) {el.removeEventListener('scroll', handleScroll);}
});function handleScroll(e) {scrollTop.value = e.target.scrollTop;
}const visibleItems = computed(() => {const start = Math.floor(scrollTop.value / itemHeight);return props.items.slice(start, start + visibleCount.value).map((item, index) => ({...item,position: (start + index) * itemHeight}));
});
</script><style scoped>
.list-container {height: 400px;overflow-y: auto;position: relative;
}.list-item {position: absolute;left: 0;right: 0;height: 50px;
}
</style>
  1. 懒加载组件:减少初始加载时间
import { defineAsyncComponent } from 'vue';const HeavyComponent = defineAsyncComponent(() => import('./components/HeavyComponent.vue')
);
  1. Web Workers:移除主线程阻塞
// worker.js
self.onmessage = (e) => {const result = heavyComputation(e.data);self.postMessage(result);
};function heavyComputation(data) {// 执行耗时计算return processedData;
}// 使用 Worker
const worker = new Worker('worker.js');
worker.onmessage = (e) => {console.log('Result from worker:', e.data);
};
worker.postMessage(data);

常见问题与解决方案

1. 路径问题

问题:跨平台路径不一致

解决方案:使用 Tauri 的路径 API

import { appConfigDir, join } from '@tauri-apps/api/path';async function getConfigPath() {const configDir = await appConfigDir();return await join(configDir, 'config.json');
}

2. 窗口管理

问题:创建和管理多窗口

解决方案

import { WebviewWindow } from '@tauri-apps/api/window';// 创建窗口
const webview = new WebviewWindow('settings', {url: 'settings.html',title: '设置',width: 800,height: 600
});// 监听窗口事件
webview.once('tauri://created', () => {console.log('Settings window created');
});webview.once('tauri://error', (e) => {console.error('Settings window error:', e);
});

3. 状态共享

问题:不同窗口间状态共享

解决方案:使用 Rust 状态管理

// 定义全局状态
struct AppState {config: Mutex<Config>,
}// 在 main.rs 中管理状态
fn main() {let state = AppState {config: Mutex::new(Config::default()),};tauri::Builder::default().manage(state).invoke_handler(tauri::generate_handler![get_config, update_config]).run(tauri::generate_context!()).expect("error while running tauri application");
}// 在命令中访问状态
#[tauri::command]
fn get_config(state: tauri::State<AppState>) -> Result<Config, String> {let config = state.config.lock().map_err(|e| e.to_string())?;Ok(config.clone())
}#[tauri::command]
fn update_config(state: tauri::State<AppState>, new_config: Config) -> Result<(), String> {let mut config = state.config.lock().map_err(|e| e.to_string())?;*config = new_config;Ok(())
}

扩展资源

  • Tauri 官方文档
  • Rust 编程语言
  • Tauri GitHub 仓库
  • Awesome Tauri
  • Tauri Discord 社区

本教程通过理论讲解和实战示例介绍了 Tauri 框架,从基础概念到构建实际应用。随着生态系统的不断发展,Tauri 正成为构建高性能、安全且体积小的桌面应用程序的首选工具之一。

通过跟随本教程中的实战部分,你已经了解了如何构建一个基本的 APK 分析工具。要了解更多复杂功能的实现,可以参考本项目的完整源代码,该项目展示了更多高级特性和最佳实践。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/78751.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode 热题 100】矩阵置零 / 螺旋矩阵 / 旋转图像 / 搜索二维矩阵 II

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;LeetCode 热题 100 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 矩阵矩阵置零螺旋矩阵旋转图像搜索二维矩阵 II 矩阵 矩阵置零 矩阵置零 用两个数组分别标记行和列&#xff0c;判断…

JavaScript进阶(三十一): === 与 == 比较运算符

文章目录 一、前言二、严格相等运算符 ()三、宽松相等运算符 ()四、推荐做法五、特殊情况 一、前言 在 JavaScript 中&#xff0c; 和 都是比较运算符&#xff0c;但它们在比较时有重要区别&#xff1a; 二、严格相等运算符 () 不进行类型转换只有当两个操作数的值和类型都…

HTML与安全性:XSS、防御与最佳实践

HTML 与安全性&#xff1a;XSS、防御与最佳实践 前言 现代 Web 应用程序无处不在&#xff0c;而 HTML 作为其基础结构&#xff0c;承载着巨大的安全责任。跨站脚本攻击&#xff08;XSS&#xff09;仍然是 OWASP Top 10 安全威胁之一&#xff0c;对用户数据和网站完整性构成严…

安达发|破解医疗器械多BOM困局:APS生产计划排产软件解决方案

在医疗器械设备制造行业&#xff0c;生产计划与排程&#xff08;Advanced Planning and Scheduling, APS&#xff09;系统的应用至关重要。由于医疗器械行业具有严格的法规要求&#xff08;如FDA、ISO 13485&#xff09;、复杂的多级BOM&#xff08;Bill of Materials&#xff…

组件轮播与样式结构重用实验

任务一&#xff1a;使用“Swiper 轮播组件”对自行选择的图片和文本素材分别进行轮播&#xff0c;且调整对应的“loop”、“autoPlay”“interval”、“vertical”属性&#xff0c;实现不同的轮播效果&#xff0c;使用Swiper 样式自定义&#xff0c;修改默认小圆点和被选中小圆…

【Stable Diffusion】文生图进阶指南:采样器、噪声调度与迭代步数的解析

在Stable Diffusion文生图(Text-to-Image)的创作过程中,采样器(Sampler)、噪声调度器(Schedule type)和采样迭代步数(Steps)是影响生成效果的核心参数。本文将从技术原理、参数优化到实践应用,深入剖析DPM++ 2M采样器、Automatic噪声调度器以及采样步数的设计逻辑与协…

第一天 车联网定义、发展历程与生态体系

前言 车联网&#xff08;Internet of Vehicles, IoV&#xff09;作为物联网&#xff08;IoT&#xff09;在汽车领域的延伸&#xff0c;正在彻底改变人们的出行方式。无论是自动驾驶、远程诊断&#xff0c;还是实时交通优化&#xff0c;车联网技术都扮演着核心角色。本文将从零…

foc控制 - clarke变换和park变换

1. foc控制框图 下图是foc控制框图&#xff0c;本文主要是讲解foc控制中的larke变换和park变换clarke变换将 静止的 a b c abc abc坐标系 变换到 静止的 α β αβ αβ坐标系&#xff0c;本质上还是以 定子 为基准的坐标系park变换 则将 α β αβ αβ坐标系 变换到 随 转…

软件系统容量管理:反模式剖析与模式应用

在数字化时代&#xff0c;软件系统的重要性日益凸显。随着业务的不断拓展和用户数量的持续增长&#xff0c;软件系统的容量管理成为保障其高效运行的关键因素。《发布&#xff01;软件的设计与部署》第二部分围绕容量展开深入探讨&#xff0c;系统地阐述了容量的定义、范围&…

23种设计模式-行为型模式之解释器模式(Java版本)

Java 解释器模式&#xff08;Interpreter Pattern&#xff09;详解 &#x1f9e0; 什么是解释器模式&#xff1f; 解释器模式是一种行为型设计模式&#xff0c;主要用于解释和执行语言的语法规则。它定义了一个解释器来处理特定的语言句法&#xff0c;并通过一个抽象语法树来…

基于Springboot + vue + 爬虫实现的高考志愿智能推荐系统

项目描述 本系统包含管理员和学生两个角色。 管理员角色&#xff1a; 个人中心管理&#xff1a;管理员可以管理自己的个人信息。 高校信息管理&#xff1a;管理员可以查询、添加或删除高校信息&#xff0c;并查看高校详细信息。 学生管理&#xff1a;管理员可以查询、添加或…

五种机器学习方法深度比较与案例实现(以手写数字识别为例)

正如人们有各种各样的学习方法一样&#xff0c;机器学习也有多种学习方法。若按学习时所用的方法进行分类&#xff0c;则机器学习可分为机械式学习、指导式学习、示例学习、类比学习、解释学习等。这是温斯顿在1977年提出的一种分类方法。 有关机器学习的基本概念&#xff0c;…

Blender插件 三维人物角色动作自动绑定 Auto-Rig Pro V3.68.44 + Quick Rig V1.26.16

Auto-Rig Pro是一个集角色绑定、动画重定向和Unity、Unreal Engine的Fbx导出于一体的全能解决方案。最初作为我个人的内部角色绑定工具开发&#xff0c;我几年前将其发布&#xff0c;并自那时起增加了许多新功能。 Blender插件介绍 Auto-Rig Pro插件简介 Auto-Rig Pro是一个强…

网络基础概念:从菜鸟到入门

前言&#xff1a;快递小哥的故事 想象一下你要给朋友寄个礼物&#xff0c;这个过程其实和网络通信非常相似&#xff1a; 1. 你需要知道朋友的”地址“&#xff08;IP地址&#xff09; 2. 要注明是送到他家大门还是物业代收&#xff08;端口号&#xff09; 3. 要选择快递公司并…

23种设计模式-行为型模式之中介者模式(Java版本)

Java 中介者模式&#xff08;Mediator Pattern&#xff09;详解 &#x1f9e0; 什么是中介者模式&#xff1f; 中介者模式是一种行为型设计模式&#xff0c;它通过定义一个中介者对象来封装一组对象之间的交互。中介者使得各个对象不需要显式地知道彼此之间的关系&#xff0c…

【Redis】基础4:作为分布式锁

文章目录 1. 一些概念2. MySQL方案2.1 方案一&#xff1a;事务特性2.1.1 存在的问题2.1.2 解决方案 2.2 方案二&#xff1a;乐观锁2.3 方案三&#xff1a;悲观锁 3. Redis3.1 实现原理3.2 实现细节3.2.1 问题1&#xff1a;持有期间锁过期问题3.2.2 问题2&#xff1a;判断和释放…

深度学习---框架流程

核心六步 一、数据准备 二、模型构建 三、模型训练 四、模型验证 五、模型优化 六、模型推理 一、数据准备&#xff1a;深度学习的基石 数据是模型的“燃料”&#xff0c;其质量直接决定模型上限。核心步骤包括&#xff1a; 1. 数据收集与标注 来源&#xff1a;公开数据集…

阿里云 OpenManus 实战:高效AI协作体系

阿里云 OpenManus 实战&#xff1a;高效AI协作体系 写在最前面初体验&#xff1a;快速部署&#xff0c;开箱即用 真实案例分享&#xff1a;从单体开发到智能良好提示词过程展示第一步&#xff1a;为亚马逊美国站生成商品描述第二步&#xff1a;为eBay全球站生成商品描述结果分析…

Kubernetes》》k8s》》explain查 yaml 参数

在创建json 和yaml 时&#xff0c;我们可能不知道具体的参数该怎么写。同样 我们可以通过explain这个 命令来查看 每个参数具体的作用与写法 # 查看 pod类性有哪些参数 kubectl explain pod# 查看pod中 spec下面有哪些参数 kubectl explain pod.spec

从零构建Dagster分区管道:时间+类别分区实战案例

分区是Dagster中的核心抽象概念&#xff0c;它允许我们管理大型数据集、处理增量更新并提高管道性能。本文将详细介绍如何创建和实现基于时间和类别的分区资产。 什么是分区&#xff1f; 分区是将数据集划分为更小、更易管理的部分的技术。在Dagster中&#xff0c;分区可以基于…