Mac 快捷键与使用技巧 修饰键速查 符号 键名 角色 ⌘ Command 系统级快捷键（最常用） ⌥ Option 辅助/扩展功能、特殊字符输入 ⌃ Control 终端里的主力、模拟右键 ⇧ Shift 扩展选择、反向操作 记忆诀窍：在终端里用 Control（跟 Linux 习惯一致），其他地方用 Command。 一、系统级 快捷键 作用 ⌘ + Space 聚焦搜索（Spotlight），秒开应用/算数/查汇率 ⌘ + Tab 切换应用 ⌘ + ` 同一应用内切换窗口（Tab 上方那个键） ⌘ + W 关闭当前窗口/标签页 ⌘ + Q 完全退出应用 ⌘ + H 隐藏当前应用 ⌘ + M 最小化窗口 ⌘ + , 打开偏好设置（几乎所有应用通用） ⌘ + ⌥ + Esc 强制退出应用 ⌘ + ⇧ + 3 全屏截图 ⌘ + ⇧ + 4 区域截图（按空格后可截窗口） ⌘ + ⇧ + 5 截图工具栏（含录屏） 二、文本编辑（macOS 全系统通用） 这些是 Emacs 风格的快捷键，任何文本框都能用，包括浏览器地址栏、IDE、微信。 快捷键 作用 ⌃ + A 跳到行首 ⌃ + E 跳到行尾 ⌃ + K 删除光标到行尾 ⌃ + U 删除整行 ⌃ + W 向前删除一个词 ⌃ + H 删除光标前一个字符 ⌃ + D 删除光标后一个字符 ⌃ + F / B 前进/后退一个字符 ⌃ + N / P 下一行/上一行 ⌥ + ←/→ 按单词跳转 ⌥ + Delete 删除前一个单词 ⌘ + ←/→ 跳到行首/行尾 ⌘ + ↑/↓ 跳到文档开头/结尾 ⇧ + 方向键 选中文本（配合上面任意跳转即可精确选中） 重点记住：⌃A/E 行首行尾、⌥←/→ 按词跳、⌘←/→ 行首行尾。 三、Finder（文件管理器） 快捷键 作用 ⌘ + N 新 Finder 窗口 ⌘ + ⇧ + G 前往文件夹（输入路径） ⌘ + ⇧ + H 前往用户主目录 ⌘ + ⇧ + . 显示/隐藏隐藏文件 ⌘ + Delete 删除文件到废纸篓 ⌘ + I 查看文件信息 ⌘ + ⌥ + Space 在当前目录打开终端（需先在 Finder 偏好设置里加） 空格 快速预览文件（Quick Look） 回车 重命名文件（不是打开！） 技巧：把常用文件夹拖到 Finder 侧边栏，从终端 open . 用 Finder 打开当前目录。 四、终端 快捷键 作用 ⌃ + A / E 行首 / 行尾 ⌃ + K / U 删到行尾 / 删整行 ⌃ + W 删前一个词 ⌃ + C 终止当前命令 ⌃ + D 退出 shell（或发送 EOF） ⌃ + R 反向搜索历史命令 ⌃ + L 清屏（等同于 clear） ⌥ + 点击 光标快速定位 ⌘ + D 分屏（iTerm2 和系统终端都支持） ⌘ + T 新建标签页 ⌘ + 数字 切换标签页 ⌘ + Enter 全屏终端 五、浏览器（Safari / Chrome / Edge 通用） 快捷键 作用 ⌘ + T 新建标签页 ⌘ + W 关闭当前标签页 ⌘ + ⇧ + T 恢复刚关闭的标签页 ⌘ + 数字 切换到第 N 个标签页 ⌘ + 9 切换到最后一个标签页 ⌘ + L 聚焦地址栏 ⌘ + R 刷新 ⌘ + ⇧ + R 强制刷新（清除缓存） ⌘ + ←/→ 前进/后退 ⌘ + D 添加书签 ⌘ + ⌥ + ←/→ 切换标签页 六、截图（macOS 自带） 快捷键 作用 ⌘ + ⇧ + 3 全屏截图 ⌘ + ⇧ + 4 区域截图 ⌘ + ⇧ + 4 再按空格 截取单个窗口（带阴影） ⌘ + ⇧ + 5 截图工具栏（可录屏） ⌘ + ⇧ + 6 截 Touch Bar（如有） 截图时按住 ⌥ 取消吸附边缘 截图时按住 ⇧ 锁定水平/垂直方向 截图默认保存到桌面。改路径：⌘ + ⇧ + 5 → 选项 → 存储位置。 七、窗口管理 macOS 窗口管理偏弱，推荐装 Rectangle（免费开源），也可以记原生能力： 快捷键 作用 ⌘ + ⌃ + F 全屏/退出全屏 长按窗口左上角绿色按钮 分屏（选择左右位置） ⌘ + ~ 同应用窗口间切换 八、开发相关技巧 访达里直接到终端：在 Finder 中右键文件夹 → 服务 → 新建位于文件夹位置的终端窗口（如没有去系统设置 → 键盘 → 快捷键 → 服务里开启） 终端里直接到访达：open . 用 Finder 打开当前目录，open 文件名 用默认应用打开 复制文件路径：Finder 中右键文件，按住 ⌥ 键，"拷贝"会变成"拷贝路径名" 粘贴纯文本：⌘ + ⇧ + ⌥ + V（去掉格式） 重命名：选中文档按回车即可重命名（新手常误以为要右键） Spotlight 直接算数：⌘ + Space 后输入 3.14*2，省掉计算器 Spotlight 查单词：⌘ + Space 后输入英文单词，直接出词典定义 三指拖移：系统设置 → 辅助功能 → 指针控制 → 触控板选项 → 开启三指拖移（拖窗口不用按住点击） 轻点点击：系统设置 → 触控板 → 轻点来点按（省力，不用按下去） Hot Corners（触发角）：系统设置 → 桌面与程序坞 → 触发角 → 把鼠标甩到屏幕四角触发操作（比如锁屏、显示桌面） 九、Command / Control / Option 怎么区分 场景 主力键 说明 复制粘贴等日常操作 ⌘ Command macOS 的操作键，等价于 Windows 的 Ctrl 终端（Terminal / iTerm2） ⌃ Control 和 Linux 一致，⌘ 在终端里是标签页/窗口操作 特殊字符输入 ⌥ Option 比如 ⌥ + 2 = ™，⌥ + G = © 右键菜单 ⌃ Control + 点击 单指点按触控板等于右键 隐藏/显示文件 ⌘ ⇧ . 在 Finder 和打开文件对话框中都有效 Emacs 风格文本跳转 ⌃ Control ⌃A/E/K 在任何文本框都通用 一句话：GUI 里 ⌘ 是王者，终端里 ⌃ 是王者，⌥ 是补刀。 十、终端小贴士（给 Java 程序员） # 回到上级目录 cd - # sudo 用 Touch ID（不用输密码） sudo sed -i '' '2s/^/auth sufficient pam_tid.so\n/' /etc/pam.d/sudo # 管道到剪贴板 cat somefile | pbcopy # 剪贴板输出 pbpaste # 查看本机 IP ipconfig getifaddr en0 # 查看端口占用 lsof -i :8080 # 递归查找文件内容（比 find + grep 更好用） grep -r "某个注解" --include="*.java" . 刚开始不用全记，先记住 ⌘Space、⌘Tab、⌃A/E、⌥←/→ 这几个使用频率最高的，其他用到再查就行。
title: agent-browser - AI 专用浏览器自动化工具 date: 2026-01-24 tags: 技术学习 浏览器自动化 Vercel Rust AI工具 Agent status: learning source: 归档/Clippings/完爆 Playwright？Vercel 开源 agent-browser，Context 节省 93%.md github: https://github.com/vercel-labs/agent-browser author: Chris Tate (Vercel Labs) agent-browser - AI 专用浏览器自动化工具 Vercel Labs 开源的浏览器自动化 CLI，专为 AI Agent 设计。核心思路是返回可访问性树（Accessibility Tree） 代替完整 HTML，大幅降低 Token 消耗。 核心优势 节省 93% Context：相比 Playwright MCP 语义化交互：返回可访问性树而非 HTML，AI 更好理解 Ref 引用系统：自动为元素打标签（@e1、@e2），AI 可直接引用 Rust CLI + Node 守护进程：首次启动 ~2s，后续命令 <100ms 核心工作流 # 1. 打开网页 agent-browser open example.com # 2. 获取 Snapshot（可访问性树 + 引用） agent-browser snapshot -i # - heading "Welcome" [ref=e1] # - button "Sign In" [ref=e4] # 3. 用 Ref 操作（不需要 CSS 选择器） agent-browser fill @e2 "user@example.com" agent-browser click @e4 安装 npm install -g agent-browser agent-browser install # 下载 Chromium 与 Claude Code 集成 已安装到 ~/.claude/skills/agent-browser/，Claude 会自动在需要的场景加载。也可手动调用使用。 对比 特性 agent-browser Playwright MCP 输出 可访问性树（~7% Tokens） 完整 HTML（100%） 选择器 Ref + 语义 + CSS CSS/Text/XPath 性能 Rust CLI + Node 守护进程 纯 Node AI 友好度 ⭐⭐⭐⭐⭐ ⭐⭐⭐ 原理 传统方式：返回完整 HTML（几千行）→ AI 自行解析 DOM agent-browser：返回可访问性树 → "这里有个按钮叫 Submit" AI 不需要在装饰性 HTML 中找关键信息，语义化输出让 Context 更聚焦。 场景 AI Agent 控制浏览器 表单自动填写 / 数据抓取 / 自动化测试 Electron 桌面应用自动化（VS Code、Slack 等） 学习总结 核心理念：不给 AI 看代码，给 AI 看"语义"。93% 的 Context 节省来自这个思路转变。 适用：AI Agent 场景强烈推荐；传统自动化测试 Playwright 生态更成熟，按需选择。 相关资源 GitHub：https://github.com/vercel-labs/agent-browser 本地 Skill 位置：~/.claude/skills/agent-browser/
Claude Code 快速上手指南 是什么 Claude Code 是 Anthropic 官方的命令行 AI 编程助手。直接在终端里和它对话，让它帮你写代码、改 bug、重构、查代码库。 # 安装 & 启动 npm install -g @anthropic-ai/claude-code claude 基本用法 直接输入自然语言就行，比如： > 帮我看看这个项目的目录结构 > 修复 utils.py 里的那个 bug > 给 login 接口加参数校验 它有权限控制，执行危险操作（删文件、推送代码）前会问你确认。 常用斜杠命令 命令以 / 开头，随时可输入： 命令 作用 /help 查看所有可用命令 /status 查看版本、模型、登录状态 /clear 清空对话，重新开始 /compact 压缩对话上下文，释放空间（对话太长时用） /cost 查看本次会话花了多少钱 /model 切换模型（Opus / Sonnet / Haiku） /init 在当前项目生成 CLAUDE.md 配置文件 /memory 编辑 CLAUDE.md，给项目添加持久记忆 /config 设置主题、输出格式等偏好 /permissions 管理工具权限规则 /diff 查看当前未提交的改动 /review 审查 PR /doctor 诊断安装是否正常 /resume 恢复之前的对话 快捷键 快捷键 作用 Esc 中断当前生成 Ctrl+C 取消当前输入 Ctrl+D 退出 Claude Code Tab 自动补全 ↑ / ↓ 浏览历史输入 Shift+Tab 切换权限模式 Ctrl+G 用外部编辑器写 prompt（写长需求时好用） Skills（技能） Skills 是可扩展的自定义命令，本质上是放在特定目录下的 SKILL.md 文件。Claude Code 自带了一些内置 skill（如 /review、/simplify），你也可以安装社区或自己写。 查看 & 使用 /skills — 列出当前所有可用 skills 直接输入 /<skill名称> 即可调用，比如 /review 某些 skill 会根据对话上下文自动触发，无需手动输入 安装 Skills 的三种方式 方式一：GitHub 下载，手动粘贴 从 GitHub 上把 skill 文件夹下载下来，直接复制到 skills 目录即可： # 全局安装（所有项目可用） cp -r 下载的skill文件夹 ~/.claude/skills/ # 项目级安装（仅当前项目，可 Git 提交共享给团队） cp -r 下载的skill文件夹 .claude/skills/ 方式二：npx skills 命令行安装（社区生态） 社区维护的命令行工具，一条命令搞定安装和管理： # 安装社区 skill npx skills add vercel/frontend-design # 从 GitHub 仓库中安装特定 skill npx skills add anthropics/skills --skill document-skills # 静默安装（跳过交互确认） npx skills add <仓库> --skill <名称> -g -y # 管理已安装的 skills npx skills list # 查看已安装 npx skills update # 更新 npx skills remove <名> # 删除 -g 表示安装到全局（所有项目可用），不加则仅当前项目。安装时会提示选择 AI 工具（选中 Claude Code 即可）。 技能市场：skills.sh — 5 万+ 可复用技能 方式三：自己手写 每个 skill 就是一个文件夹，核心是里面的 SKILL.md 文件： ~/.claude/skills/my-skill/ ├── SKILL.md # 必需：技能定义 ├── scripts/ # 可选：辅助脚本 └── resources/ # 可选：资源文件 SKILL.md 格式示例： --- name: my-skill description: 一句话描述，用于 Claude 自动匹配触发 --- ## 使用步骤 1. 第一步做什么 2. 第二步做什么 写好放到 ~/.claude/skills/（全局）或 .claude/skills/（仅当前项目），重启 Claude Code 即可使用。 注意事项 项目级 > 全局级：同名 skill，项目级优先 Skills 是"教模型怎么做事"（行为规范），MCP 是"给模型工具"（能力供给），两者不同但互补 从非可信来源安装前，建议看一眼 SKILL.md 内容，确认没有恶意指令 几个核心概念（一句话版） CLAUDE.md — 项目级配置文件，告诉 Claude 这个项目的约定和规则，类似 .cursorrules Memory — 自动记忆你的偏好和项目上下文，下次对话也能用 Hooks — 在特定事件（工具调用前后）自动执行的脚本 MCP Servers — 连接外部工具（数据库、API 等）的协议，扩展 Claude 的能力 settings.json — 权限、环境变量等底层配置 新手建议 不知道问什么就 /help，上面列了所有命令 对话太长时 /compact，不然会变慢变贵 项目根目录跑一下 /init，生成 CLAUDE.md 后 Claude 会更懂你的项目 写长需求用 Ctrl+G，打开编辑器慢慢写比在终端里敲舒服 大胆用自然语言描述，不需要写得很精确，它理解能力很强 @文件名 可以在 prompt 里直接引用文件，比如 @src/main.py 帮我重构这个文件
planning-with-files - 复刻 Manus 上下文工程的开源插件
title: planning-with-files - 复刻 Manus 上下文工程的开源插件 date: 2026-02-02 tags: 技术学习 Agent Claude-Code 上下文工程 Manus 开源项目 status: learning source: 归档/Clippings/暴涨11.7k Star！复刻Manus上下文工程的开源Skills，Claude code等多个平台即插即用.md github: https://github.com/OthmanAdi/planning-with-files planning-with-files - 复刻 Manus 上下文工程的开源插件 开源插件，复刻了 Manus 的上下文工程方法论——用磁盘文件代替上下文窗口做"工作记忆"，解决 AI 智能体失忆、迷航、重复犯错三大痛点。GitHub 11.7k+ Stars。 核心思想 任何重要信息都应写入磁盘，而非依赖易失且有限的上下文窗口。 LLM 上下文窗口 = 内存（易失、有限） 磁盘文件 = 硬盘（持久、无限） 三文件架构 文件 作用 更新时机 task_plan.md 阶段划分、进度状态、错误记录 每个阶段完成后 findings.md 调研结果、关键发现 查看/搜索/浏览操作后 progress.md 会话日志、测试结果 整个过程中持续记录 六大原则 先计划后执行：复杂任务必须先有 task_plan.md 及时写入发现：每 2 次查看/搜索/浏览后，立即写入 findings.md 决策前回顾目标：关键决策前重新读取 task_plan.md 阶段完成必更新：标记完成状态、记录错误和修改的文件 记录所有错误：持久化错误日志，避免重复踩坑 绝不重复失败：同一操作失败后换方案，记录尝试历史 安装 已通过 ~/.claude/skills/planning-with-files/ 安装。包含中文 SKILL.md、辅助脚本和模板文件。 也可在 Claude Code 内通过命令安装： /plugin marketplace add OthmanAdi/planning-with-files /plugin install planning-with-files@planning-with-files 使用场景 多步骤任务（3 步以上） 研究型任务（信息收集、分析、整理） 涉及大量工具调用的复杂工作流 研究或开发，需要断点续做的场景 学习总结 Manus 的方法论本质是用工程约束弥补模型缺陷——不追求让 AI 更聪明，而是让它更可靠地执行流程。三个文件看似简单，但 hooks 机制在每次工具调用前后自动读/写计划文件，形成了"读→做→写→审"的执行闭环，这是真正有效的关键。 参考资源 GitHub：https://github.com/OthmanAdi/planning-with-files 本地 Skill 位置：~/.claude/skills/planning-with-files/
Cursor 插件、环境安装 1）Chinese (Simplified) Language Pack，中文界面插件。 2）Extension Pack for Java 只要安装了 “Extension Pack for Java”，其它插件（Maven、Debugger、Language Support、Test Runner、Project Manager 等）都是它自动帮你装好的，不需要你一个个手动点安装。 这样打开项目文件夹（包含 pom.xml 的根目录）时： 它会自动检测项目类型 → 加载 Maven → 解析依赖。底部出现 Java: Ready、Building [Done]，说明依赖已经下载并索引完毕。默认使用的是系统环境变量MAVEN_HOME的地址。 或者在这里指定： 自动选择jdk版本： 查看pom中配置，Cursor 会用这个版本作为编译目标。 <properties> <java.version>1.8</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> 运行时版本由“系统环境或 Cursor 配置”决定，系统变量里的 JAVA_HOME，就是 你系统默认使用的 JDK。随便打开一个终端 java -version ，可以看到使用的是jdk17。 3） Spring Boot Extension Pack 左侧多出一个 Spring Boot Dashboard； 自动识别所有带 @SpringBootApplication 的项目； 可以直接在面板里点击 ▶️ 启动； application.yml会出现智能提示，比如： spring.datasource.url spring.datasource.username spring.datasource.password 4）IntelliJ IDEA Keybindings 装上它之后，你在 Cursor 里按的快捷键和 IDEA 几乎一样； 5）“Want to launch Cursor from the command line? You can add the code or cursor commands now, or later with Ctrl+Shift+P and typing ‘install code command’.” 这是一个 可选的小功能提示，翻译：“想要从命令行启动 Cursor 吗？你可以现在添加 code 或 cursor 命令，也可以之后按 Ctrl + Shift + P，输入 install code command 来添加。” 作用：直接通过命令行（例如 PowerShell、CMD、终端），打开项目或文件。 cursor . 表示： 用 Cursor 打开当前文件夹（.） 或者：cursor C:\project\group-buying-sys 表示： 用 Cursor 打开指定路径下的项目。 如何查看配置？ Ctrl+shift+P 快捷键，输入 open user settings 可以打开用户配置。 输入 project setting 可以打开项目配置文件 或者左下角JAVA PROJECTS，点击Configure JAVA Runtime： 运行JAVA项目 Maven编译 运行 1）打开启动类，点击run/debug 2） 编辑器界面 ┌────────────────────────────────────────────┐ │ 顶部菜单栏（File / 编辑 / 选择 / 查看...）│ ├────────────────────────────────────────────┤ │ 左侧侧边栏（文件树 / 项目 / Git 等） │ ├────────────────────────────────────────────┤ │ 中间主编辑区（代码编辑） │ ├────────────────────────────────────────────┤ │ 右侧 AI 面板（Cursor 智能助手 / Chat） │ ├────────────────────────────────────────────┤ │ 底部状态栏（分支 / 文件类型 / 行列信息等） │ └────────────────────────────────────────────┘ 如何使用 Cursor 的 AI 功能 功能 作用 快捷键（默认） 🧠 Inline Edit 选中一段代码 → Ctrl + K（或右键 “Ask Cursor”）→ 输入自然语言指令（如“优化正则表达式”） Ctrl + K 🤖 Agent 面板 打开一个“聊天窗口”，直接和 Cursor 对话（如“帮我写个登录验证函数”） Ctrl + I ✨ Tab 补全 在代码中输入时，Cursor 自动预测后续内容 Tab 🔁 重新生成建议 当灰色提示出现但不理想时，按 `Alt + ``（或右键 “Regenerate”） `Alt + `` 选择一段代码+CTRL+K 修改指定的代码，直接在代码编辑区弹出修改窗口调用大模型。CTRL+ENTER 或者鼠标点击 应用修改 CTRL+N 或者 **鼠标点击 **拒绝修改 CTRL+I 1）图中设置的Auto表示自动选择模型； 2）@ 可以添加文件、文件夹到当前对话上下文，如果你在代码编辑区选择一段代码再 CTRL+I 或者 CTRL+L，也会自动将它添加进来。还可以直接拖拽资源管理器中的文件到AI对话框中。 3）+Browser 模式可以让模型看到整个项目文件 任务 你可以直接问 Cursor 找函数定义 “verifyPassword 函数定义在哪个文件？” 查找引用 “verifyCode 被调用了多少次？” 理解架构 “帮我总结整个项目的模块结构。” 改代码 “把所有 JS 文件里的 var 改成 let。” 生成文档 “根据这个项目代码生成一份 README。” 4）对话模式 Agent模式，默认的对话模式，功能最全，AI 不仅能回答，还会“主动思考、规划和执行”。可以理解为：“帮我干活”的模式。 Plan 模式，它可以浏览整个项目文件，但不会直接改代码，而是会：把你的需求拆分成多个步骤；告诉你“下一步该干什么”；有时生成一份修改计划或脚本方案。 Ask 模式：问答模式，和网页版使用大模型一样。 TAB 一般注释起手，如果出现灰色预测文字时，直接 Tab 就能接受 AI 自动补全 ，按ESC可以拒绝这个建议；否则就是普通的缩进。 触发逻辑 传统 IDE（比如 VS Code、IntelliJ） 的补全是词法或语法级触发： 你输入 “pri” → 提示 “print()”； 它只是基于关键字匹配。 而 Cursor 的补全 是“语义级”的： AI 根据上下文 推断你下一步可能在做什么。 它会综合考虑： 当前光标前后的代码； 注释 / 函数签名； 文件名； 项目中的其他定义； 甚至最近你在这个 Tab 里做的事。 阶段 触发动作 AI 响应 检测阶段 监听输入变化（按键、换行、注释等） 分析上下文语义树（AST） 预测阶段 生成“意图向量” 模型推断用户下一步目标 展示阶段 在光标后显示灰色 ghost text 等待你按 Tab 接受 触发时机 类型 触发条件 示例 行为 函数触发 输入 function / def function check... 预测参数和函数体 控制语句触发 输入 if / for 等 if (phone) 预测条件或逻辑块 注释触发 输入 //、#、/** // 校验邮箱格式 按注释生成实现 模板触发 class / import / try class User 预测类体、导入内容 上下文模仿 类似已有代码块 第二个函数定义 模仿风格 文件结构触发 同名模块、utils utils. 补出函数名 空行预测 新行、缩进后 空一行 猜测下一个合逻辑语句 Index&Docs Codebase Indexing（代码索引）： Cursor 会扫描整个项目文件夹； 提取文件路径、函数定义、类名、依赖关系； 生成语义向量（embeddings）并存储（只保存索引，不上传源代码）。 界面说明：索引完成度100%；已被索引的文件数量为 78； Index New Folders： 当你创建或添加新文件夹时，Cursor 是否自动索引它。 Ignore Files in .cursorignore： 告诉 Cursor 哪些文件不要被索引。类似.gitignore Docs（文档索引）： 可以手动添加官方文档、API 文档、开发指南，让它当作参考知识。 添加一个 README.md 或内部 API 规范； 或添加外部文档（如一个 SDK 的文档网站）； 之后在 Chat 里用 @doc 引用 如何撤销修改 在AI编辑窗口提问，应用修改，点击Accept 应用完之后，若想回退版本，可以点击提问右边的回撤箭头。 整体思路（重要） 1）先打开项目，然后用browser模式，让AI对这个项目生成一个 .cursorignore 文件，自动忽略哪些文件无需添加进上下文。 2）打开设置，Index&docs，重新索引一下。 3）把项目相关的需求文档、接口文档、技术文档，全部录入到docs中，作为知识库以作备用。这与项目代码文件夹解耦的。 4）在项目根目录下创建 .cursorrules 文件，不需要 @ 引用，自动生效。 .cursorrules 就是 Cursor 的 AI 指令与代码风格规则文件，用来告诉 AI：在这个项目里写代码、命名、注释、格式化时都按照这些规则来做。是一个 系统级提示词 。 eg: ai_behavior: - 所有回答必须使用中文 - 代码中添加必要的注释 style: indentation: 4 spaces naming_convention: variables: camelCase AI 背后接收到的系统指令：你是一个 Java 开发助手。 遵循以下项目规则： 所有回答必须使用中文。 代码中添加必要的注释。 使用 4 空格缩进。 变量名使用 camelCase。 用户请求： 「写一个计算阶乘的 Java 函数」。
Kubernetes (K8S) Kubernetes 是一个开源的容器编排平台，用于自动化部署、扩缩容（Pod 数量多了/少了自动调整）和自愈（坏掉的 Pod 会被自动重建） 基本架构 一个 Kubernetes 集群 (Cluster) = 控制平面 + 工作节点 的组合。要使用K8S，要先搭建集群，deployment.yaml 和 service.yaml 要提交到 K8S 集群，由它调度和运行。 控制平面 (Control Plane) 负责管理整个集群，不直接跑应用。 组件 作用 比喻 API Server 接收命令（kubectl）、提供统一接口 前台服务员 etcd 存储集群所有状态（配置、Pod 列表等） 账本/数据库 Scheduler 决定 Pod 跑在哪个 Node 上 领班 Controller Manager 保证实际状态符合预期（补 Pod、重建失败的 Pod） 经理 工作节点 (Worker Nodes) 实际跑应用容器。 组件 作用 Kubelet 负责跟 API Server 沟通，并启动/管理容器 容器运行时 运行容器（Docker、containerd） Kube-Proxy 管理网络规则，实现 Service 的负载均衡 graph TD A[控制平面] --> B[Node 1] A --> C[Node 2] A --> D[Node 3] B --> E[Pod] B --> F[Pod] C --> G[Pod] D --> H[Pod] K8S 核心概念 Pod 最小运行单元，一个 Pod 里可以有 1 个或多个容器。 共享网络和存储空间 Deployment 管 Pod 的「副本数」和「版本」。 支持滚动更新、回滚 Service 提供稳定的网络入口（因为 Pod IP 会变）。 负载均衡到一组 Pod。 ConfigMap & Secret ConfigMap：存储配置信息（非敏感）。 Secret：存储敏感信息（密码、Token），会加密。 基本使用方式 Deployment（定义 Pod 模板 + 副本数） apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: replicas: 3 # 要 3 个 Pod selector: matchLabels: app: my-app template: # Pod 模板 metadata: labels: app: my-app #给 Pod 打标签，Service 用 selector 找到这些 Pod 做负载均衡 spec: containers: - name: my-app #Pod名 image: my-registry/my-app:v1 # ← 指向 CI 推送后的镜像（仓库/名称:标签） ports: - containerPort: 8080 #容器对外提供服务的端口 Pod名可能是：my-app-6f7c9d7c5d-abcde，它里面的容器名：my-app 映射关系： kind: Deployment → 创建一个「Pod 管理器」 replicas: 3 → 保证始终有 3 个 Pod template → Pod 的样子（运行哪个镜像、开哪个端口） Service（提供统一访问入口） apiVersion: v1 kind: Service metadata: name: my-service spec: selector: app: my-app # 找到所有带 app=my-app 标签的 Pod ports: - port: 80 # Service 入口端口 targetPort: 8080 # Pod 里容器的端口 type: LoadBalancer # 暴露给外部访问 映射关系： selector → 绑定到 Deployment 创建的 Pod，根据 Pod 的标签（my-app） ports → 用户访问 80 端口，会转发到 Pod 的 8080 type: LoadBalancer → 提供一个外部 IP 供用户访问 典型工作流程 sequenceDiagram 开发者->>Git: 提交代码 Git->>CI/CD: 触发构建 CI/CD->>镜像仓库: 构建Docker镜像 CI/CD->>K8S: kubectl apply K8S->>K8S: 创建/更新Pod K8S->>K8S: 健康检查 K8S->>用户: 服务可用 sequenceDiagram 开发者->>API Server: kubectl apply -f xxx.yaml API Server->>etcd: 写入期望状态 API Server->>Scheduler: 请求调度 Scheduler->>Node: 分配 Pod 到合适的节点 Node->>Kubelet: 启动容器 Controller Manager->>Cluster: 监控状态并修复 Service->>用户: 提供统一访问入口 👉 过程总结： 提交 YAML → API Server 接收并存到 etcd。 Scheduler 决定 Pod 去哪个 Node。 Node 上的 Kubelet 把容器启动。 Controller Manager 盯着数量，缺了就补。 Service 统一出口，用户不用关心 Pod IP。 常用操作 前提是1：集群必须已经搭好（minikube/kind/k3s/云厂商的 K8S）。 2：kubectl 已经配置好 kubeconfig 3：镜像能拉取到 如果是公有镜像（比如 Docker Hub），直接写就行。 如果是私有仓库，需要配 imagePullSecrets。 # 部署应用 kubectl apply -f deployment.yaml kubectl apply -f service.yaml # 查看集群资源 kubectl get pods -o wide kubectl get deployments kubectl get services # 扩缩容 kubectl scale deployment/my-app --replicas=5 # 滚动更新 kubectl set image deployment/my-app my-app=my-registry/my-app:v2 # 回滚 kubectl rollout undo deployment/my-app
CI/CD 自动部署项目 使用Gitea Actions 1）启用Gitea Actions： 编辑你的Gitea服务器配置文件 app.ini（通常位于 /etc/gitea/或 Gitea 安装目录），添加： [actions] ENABLED = true 然后重启Gitea服务。 2）在部署服务器上安装Runner： # 1. 下载并安装 act_runner (需要sudo) sudo wget https://gitea.com/gitea/act_runner/releases/download/v0.2.10/act_runner-0.2.10-linux-amd64 -O /usr/local/bin/act_runner sudo chmod +x /usr/local/bin/act_runner # 2. 为Runner创建专用工作目录（推荐使用绝对路径） sudo mkdir -p /opt/gitea-runner sudo chown $USER:$USER /opt/gitea-runner # 将目录所有权给当前用户 cd /opt/gitea-runner # 3. 注册Runner（重要：必须添加labels标签） act_runner register --no-interactive \ --instance https://你的gitea域名.com \ --token <你的令牌> \ --name my-runner \ --labels self-hosted,linux # 这个标签必须与工作流文件中的runs-on匹配 # 4. 启动Runner（后台运行） nohup act_runner daemon > runner.log 2>&1 & # 5. 查看运行状态和日志 tail -f runner.log ps aux | grep act_runner 3）令牌获取： 如果你想给整个实例用 → 站点管理员设置 → Actions → Runners。 如果只想给某个仓库用 → 进入该仓库 → Settings → Actions → Runners。 点击 New Runner，系统会生成一个 TOKEN。 例如：abcdef1234567890 还是设置整个实例好！！ 4）将act_runner注册为服务自启动 sudo vim /etc/systemd/system/act_runner.service 写入以下内容： [Unit] Description=Gitea Actions Runner After=network.target [Service] ExecStart=/usr/local/bin/act_runner daemon WorkingDirectory=/opt/gitea-runner User=zy123 Restart=always RestartSec=5 [Install] WantedBy=multi-user.target ExecStart 指向你安装的 act_runner 路径（你已经放在 /usr/local/bin/ 了）。 WorkingDirectory 可以写你打算存放 Runner 缓存的目录（比如 /home/zy123/act_runner，你已经在这里 register 过了）。 User=zy123 保证 Runner 以你当前用户运行，而不是 root。 重新加载 systemd 配置： sudo systemctl daemon-reexec 启动并开机自启: sudo systemctl enable --now act_runner 查看运行状态: systemctl status act_runner 5）在后端仓库根目录下，新建目录和文件： .gitea/workflows/deploy.yml 写入以下内容： name: Deploy Backend on: push: branches: [ "master" ] # master 分支推送时触发 jobs: build-and-deploy: runs-on: self-hosted steps: - name: Checkout code uses: actions/checkout@v3 - name: Create application-local.yml run: | mkdir -p src/main/resources/ cat << 'EOF' > src/main/resources/application-local.yml ${{ secrets.APPLICATION_LOCAL_YML }} EOF - name: Build and restart smile-picture run: | cd docs/tags/picture-v1.0 docker compose -f docker-compose-app-v1.0.yml build smile-picture-backend docker compose -f docker-compose-app-v1.0.yml up -d smile-picture-backend - name: Cleanup dangling images run: docker image prune -f 特别注意,application-local没有用git管理，把它存在了Actions的密钥中： 然后deploy.yml中可以把里面的内容复制过去。 6）工作原理 1.Runner 接收任务 当你 push 到 main 分支时： Gitea 会触发 workflow（.gitea/workflows/deploy.yml）。 服务器上的 act_runner 会接收到这个任务，并开始执行 jobs.build-and-deploy。 2.actions/checkout@v3 这一行的作用是：它会把你刚刚 push 的最新代码 完整克隆 到 Runner 的工作目录。 /home/<你的用户>/actions-runner/_work/<repo名>/<repo名>/ 所以，这时候你的项目在 Runner 的临时目录里已经是最新代码了，不需要 git pull。 3.后续 cd docs/tag/group-buy-v3.0 都是在 这个临时目录 里执行的。 相当于你在服务器上的临时副本中： 用 docker compose build 构建镜像 用 docker compose up -d 启动/更新容器 4.Runner 每次执行 workflow 时，工作目录都会 重新 checkout 最新代码。 默认不会自动清理旧目录，但可以在 workflow 里加 actions/checkout 的参数来控制，比如 clean: true。. 7）git push之后
mermaid画图 graph TD A[多智能体随机网络结构分析] --> B[多智能体协同学习与推理] A --> A1["谱参数实时估算"] A1 --> A11["卡尔曼滤波"] A1 --> A12["矩阵扰动理论"] A1 --> A13["输出：谱参数"] A --> A2["网络拓扑重构"] A2 --> A21["低秩分解重构"] A2 --> A22["聚类量化"] A2 --> A23["输出：邻接矩阵、特征矩阵"] graph TD B[多智能体协同学习与推理] B --> B1["联邦学习、强化学习"] B1 --> B11["谱驱动学习率调整"] B1 --> B12["自适应节点选择策略"] B --> B2["动态图神经网络"] B2 --> B21["动态图卷积设计"] B2 --> B22["一致性推理"] graph TD %% 颜色和样式定义 classDef startEnd fill:#e6ffe6,stroke:#333,stroke-width:2px classDef operation fill:#fff,stroke:#000,stroke-width:1px classDef decision fill:#ffcccc,stroke:#000,stroke-width:1px classDef update fill:#ccffcc,stroke:#000,stroke-width:1px %% 节点定义（严格按图片顺序） A([开始]):::startEnd B[交易信息\n外部订单号]:::operation C{判断是否为锁单订单}:::decision D[查询拼团组队信息]:::operation E[更新订单详情\n状态为交易完成]:::update F[更新拼团组队进度]:::update G{拼团组队完结\n目标量判断}:::decision H[写入回调任务表]:::operation I([结束]):::startEnd %% 流程连接（完全还原图片走向） A --> B B --> C C -->|是| D D --> E E --> F F --> G G -->|是| H H --> I C -->|否| I G -->|否| I %% 保持原图连接线样式 linkStyle 0,1,2,3,4,5,6,7,8 stroke-width:1px graph TD A[用户发起退单请求] --> B{检查拼团状态} B -->|拼团未完成| C1[场景1:拼团中退单] C1 --> D1{是否已支付?} D1 -->|未支付| E1[取消订单] E1 --> F1[更新订单状态为2] F1 --> G1[通知拼团失败] G1 --> H1[退单完成] D1 -->|已支付| I1[发起退款] I1 --> F1 B -->|拼团已完成| C2[场景2:完成后退单] C2 --> D2{是否超时限?} D2 -->|未超时| E2[发起退款] E2 --> F2[更新订单状态] F2 --> H1 D2 -->|超时| G2[退单失败] style A fill:#f9f,stroke:#333 style B fill:#66f,stroke:#333 style C1 fill:#fbb,stroke:#f66 style C2 fill:#9f9,stroke:#090 flowchart LR %% ===================== 左侧：模板模式块 ===================== subgraph Template["设计模式 - 模板"] direction TB SM["StrategyMapper 策略映射器"] SH["StrategyHandler 策略处理器"] ASR["AbstractStrategyRouter<T, D, R> 策略路由抽象类"] SM -->|实现| ASR SH -->|实现| ASR end %% ===================== 右侧：策略工厂与支持类 ===================== DASFactory["DefaultActivityStrategyFactory 默认的拼团活动策略工厂"] AGMS["AbstractGroupBuyMarketSupport 功能服务支撑类"] DASFactory --> AGMS AGMS -->|继承| ASR %% ===================== 业务节点链路 ===================== Root["RootNode 根节点"] Switch["SwitchRoot 开关节点"] Market["MarketNode 营销节点"] End["EndNode 结尾节点"] Other["其他节点"] AGMS --> Root Root --> Switch Switch --> Market Market --> End Switch -.-> Other Other --> End %% ===================== 样式（可选） ===================== classDef green fill:#DFF4E3,stroke:#3B7A57,stroke-width:1px; classDef red fill:#E74C3C,color:#fff,stroke:#B03A2E; classDef purple fill:#7E60A2,color:#fff,stroke:#4B3B6B; classDef blue fill:#3DA9F5,color:#fff,stroke:#1B6AA5; class SM,SH,Root,Switch,Market,End,Other green; class DASFactory red; class AGMS purple; class ASR blue; style Template stroke-dasharray: 5 5; sequenceDiagram participant A as 启动时 participant B as BeanPostProcessor participant C as 管理后台 participant D as Redis Pub/Sub participant E as RTopic listener participant F as Bean 字段热更新 A->>B: 扫描 @DCCValue 标注的字段 B->>B: 写入默认值 / 读取 Redis B->>B: 注入字段值 B->>B: 缓存 key→Bean 映射 A->>A: Bean 初始化完成 C->>D: publish("myKey,newVal") D->>E: 订阅频道 "dcc_update" E->>E: 收到消息，更新 Redis E->>E: 从 Map 找到 Bean E->>E: 反射注入新值到字段 E->>F: Bean 字段热更新完成 sequenceDiagram participant A as 后台/系统 participant B as Redis Pub/Sub participant C as DCC监听器 participant D as Redis数据库 participant E as 反射更新字段 participant F as Bean实例 A->>B: 发布消息 ("cutRange:50") B->>D: 将消息 "cutRange:50" 写入 Redis B->>C: 触发订阅者接收消息 C->>D: 更新 Redis 中的 "cutRange" 配置值 C->>F: 根据映射找到对应的 Bean C->>E: 通过反射更新 Bean 中的字段 E->>C: 更新成功，字段值被同步 C->>A: 配置变更更新完成 flowchart LR A[请求进入链头 Head] --> B[节点1: 日志LogLink] B -->|继续| C[节点2: 权限AuthLink] B -->|直接返回/终止| R1[返回结果] C -->|通过→继续| D[节点3: 审批ApproveLink] C -->|不通过→终止| R2[返回失败结果] D --> R3[返回成功结果] classDef node fill:#eef,stroke:#669; classDef ret fill:#efe,stroke:#393; class A,B,C,D node; class R1,R2,R3 ret; flowchart LR subgraph mall["小型支付商城"] style mall fill:#ffffff,stroke:#333,stroke-width:2 A[AliPayController 发起退单申请]:::blue C[订单状态扭转 退单中]:::grey E[RefundSuccessTopicListener 接收MQ消息 执行退款和订单状态变更]:::green end subgraph pdd["拼团系统"] style pdd fill:#ffffff,stroke:#333,stroke-width:2 B[MarketTradeController 接收退单申请]:::yellow D[TradeRefundOrderService 退单策略处理]:::red F[TradeRepository 发送MQ消息]:::purple G([MQ消息队列 退单成功消息]):::orange H[RefundSuccessTopicListener 接收MQ消息 恢复库存]:::green end A -- "1. 发起退单请求" --> B B -- "2. 处理退单" --> D D -- "3. 发送MQ消息" --> F F -- "4. 发布消息 (异步+本地消息表补偿)" --> G F -- "5. 返回结果" --> C G -- "6. 消费消息 (恢复库存)" --> H G -. "7. 消费消息 (执行退款)" .-> E classDef blue fill:#dbe9ff,stroke:#6fa1ff,stroke-width:1; classDef grey fill:#e5e5e5,stroke:#9e9e9e,stroke-width:1; classDef green fill:#d6f2d6,stroke:#76b076,stroke-width:1; classDef yellow fill:#fef3cd,stroke:#f5c700,stroke-width:1; classDef red fill:#f8d7da,stroke:#e55353,stroke-width:1; classDef purple fill:#e4dbf9,stroke:#9370db,stroke-width:1; classDef orange fill:#ffecca,stroke:#ffa500,stroke-width:1; sequenceDiagram participant Client as 前端 participant WS as WebSocket 服务器 participant Auth as 权限校验 participant Dispatcher as 消息分发器 participant Handler as 消息处理器 Client->>WS: 请求建立 WebSocket 连接 WS->>Auth: 校验用户权限 Auth-->>WS: 校验通过，保存用户和图片信息 WS-->>Client: 连接成功 Client->>WS: 发送消息（包含消息类型） WS->>Dispatcher: 根据消息类型分发 Dispatcher->>Handler: 执行对应的消息处理逻辑 Handler-->>Dispatcher: 返回处理结果 Dispatcher-->>WS: 返回处理结果 WS-->>Client: 返回处理结果给客户端 Client->>WS: 断开连接 WS-->>Client: 删除 WebSocket 会话，释放资源 sequenceDiagram participant Client as Client(浏览器) participant WS as WebSocket Endpoint participant Producer as PictureEditEventProducer participant RB as RingBuffer participant Worker as PictureEditEventWorkHandler participant Handler as PictureEditHandler Client->>WS: 发送 PictureEditRequestMessage WS->>Producer: publishEvent(msg, session, user, pictureId) Producer->>RB: next() 获取序号，写入事件字段 Producer->>RB: publish(sequence) 发布 RB-->>Worker: 回调 onEvent(event) Worker->>Worker: 解析 type -> PictureEditMessageTypeEnum alt ENTER_EDIT Worker->>Handler: handleEnterEditMessage(...) else EXIT_EDIT Worker->>Handler: handleExitEditMessage(...) else EDIT_ACTION Worker->>Handler: handleEditActionMessage(...) else 其他/异常 Worker->>WS: sendMessage(ERROR 响应) end Worker-->>Client: 业务处理后的响应（通过 WS） sequenceDiagram participant Client as WebSocket Client participant IO as WebSocket I/O线程 participant Biz as 业务逻辑(耗时) Client->>IO: 收到消息事件(onMessage) IO->>Biz: 执行业务逻辑(耗时3s) Biz-->>IO: 返回结果 IO->>Client: 发送响应 Note over IO: I/O线程被业务阻塞3s 不能处理其他连接的消息 sequenceDiagram participant Client as WebSocket Client participant IO as WebSocket I/O线程 participant Disruptor as RingBuffer队列 participant Worker as Disruptor消费者线程 participant Biz as 业务逻辑(耗时) Client->>IO: 收到消息事件(onMessage) IO->>Disruptor: 发布事件(快速) Disruptor-->>IO: 立即返回 IO->>Client: (继续处理其他连接消息) Worker->>Biz: 异步执行业务逻辑(耗时3s) Biz-->>Worker: 返回结果 Worker->>Client: 通过WebSocket发送响应 flowchart TD A[客户端发起WebSocket连接] --> B[HTTP握手阶段] B --> C[WsHandshakeInterceptor.beforeHandshake] C -->|校验失败| D[拒绝握手 连接关闭] C -->|校验成功| E[建立WebSocket连接] E --> F[PictureEditHandler] F --> G[处理WebSocket消息 收发数据] flowchart TD A([接收请求]) --> B{查询本地缓存 Caffeine} B -- 命中 --> C[返回本地缓存数据] C --> End1(((结束))) B -- 未命中 --> D{查询分布式缓存 Redis} D -- 命中 --> E[更新本地缓存] E --> F[返回 Redis 缓存数据] F --> End2(((结束))) D -- 未命中 --> G[查询数据库] G --> H[更新本地缓存和 Redis 缓存] H --> I[返回数据库数据] I --> End3(((结束))) classDiagram class ImageSearchApiFacade { +searchImage(localImagePath) } class GetImagePageUrlApi { +getImagePageUrl(localImagePath) } class GetImageFirstUrlApi { +getImageFirstUrl(imagePageUrl) } class GetImageListApi { +getImageList(imageFirstUrl) } ImageSearchApiFacade --> GetImagePageUrlApi : Calls ImageSearchApiFacade --> GetImageFirstUrlApi : Calls ImageSearchApiFacade --> GetImageListApi : Calls erDiagram 用户 { BIGINT 用户ID VARCHAR 用户名 } 角色 { BIGINT 角色ID VARCHAR 角色名称 VARCHAR 描述 } 权限 { BIGINT 权限ID VARCHAR 权限名称 VARCHAR 描述 } 用户 }o--o{ 角色 : 拥有 角色 }o--o{ 权限 : 赋予 classDiagram class Collection { <<interface>> +add() +remove() +clear() +size() } class Set { <<interface>> } class List { <<interface>> } class Queue { <<interface>> } class Map { <<interface>> } class HashSet { <<class>> } class TreeSet { <<class>> } class ArrayList { <<class>> } class LinkedList { <<class>> } class PriorityQueue { <<class>> } class HashMap { <<class>> } class TreeMap { <<class>> } Collection <|-- Set Collection <|-- List Collection <|-- Queue Set <|-- HashSet Set <|-- TreeSet List <|-- ArrayList List <|-- LinkedList Queue <|-- LinkedList Queue <|-- PriorityQueue Map <|-- HashMap Map <|-- TreeMap sequenceDiagram participant U as 用户 participant O as 下单服务 participant P as 拼团/优惠服务 participant R as 风控/库存校验 U ->> O: 请求锁单(userId, goodsId, activityId, teamId) activate O %% Step 1 幂等查询 O ->> P: 幂等查询(out_trade_no 是否已有锁单) P -->> O: 存在则直接返回该条记录 %% Step 2 拼团人数校验 O ->> P: 校验拼团人数(再次拉取，避免前端滞后) P -->> O: 校验结果 %% Step 3 优惠试算 O ->> P: 优惠试算(activityId, goodsId) P -->> O: 返回拼团优惠价格 %% Step 4 人群限定 O ->> R: 校验是否在目标人群范围 R -->> O: 校验结果(非目标人群直接拒绝) %% Step 5 锁单责任链 O ->> P: 活动有效性校验 O ->> P: 用户参与次数校验 O ->> R: 剩余库存校验 O -->> U: 返回锁单结果(成功/失败) deactivate O flowchart TD A[initialize @PostConstruct] --> B[fetchAllPictureTableNames] B -->|查询 SpaceService| C[组装所有表名 picture + picture_xxx] C --> D[updateShardingTableNodes] D --> E[getContextManager] E --> F[获取 ShardingSphereRuleMetaData] F --> G[更新 ShardingRuleConfiguration.actual-data-nodes] G --> H[alterRuleConfiguration + reloadDatabase] subgraph 动态建表 I[createSpacePictureTable] --> J{space 是否旗舰团队?} J -- 否 --> K[不建表] J -- 是 --> L[SqlRunner 创建新表 picture_xxx] L --> D end flowchart TD %% 定义节点 Publisher[Publisher 消息发布者] Exchange[fanout Exchange 扇形交换机] Queue1[Queue1] Queue2[Queue2] Queue3[Queue3] Consumer1[Consumer1] Consumer2[Consumer2] Consumer3[Consumer3] Msg[msg] %% 消息流向 Publisher -->|发布消息| Exchange Exchange -->|广播消息| Queue1 Exchange -->|广播消息| Queue2 Exchange -->|广播消息| Queue3 Queue1 -->|投递消息| Consumer1 Queue2 -->|投递消息| Consumer2 Queue3 -->|投递消息| Consumer3 %% 确认回执 Consumer1 -->|ack 成功处理，删除消息| Queue1 Consumer2 -->|nack 处理失败，重新投递| Queue2 Consumer3 -->|reject 处理失败并拒绝，删除消息| Queue3 %% 样式定义 classDef publisher fill:#e1f5fe,stroke:#01579b; classDef exchange fill:#d1c4e9,stroke:#4527a0; classDef queue fill:#f8bbd0,stroke:#880e4f; classDef consumer fill:#c8e6c9,stroke:#1b5e20; class Publisher publisher; class Exchange exchange; class Queue1,Queue2,Queue3 queue; class Consumer1,Consumer2,Consumer3 consumer; flowchart TD subgraph 运营 A1[配置拼团] end subgraph 用户 B1[查看商品] end subgraph 用户A/B C1[参与拼团] end %% 运营流程 A1 --> A2[拼团折扣] A2 --> A3[团长优惠] A3 --> A4[人群标签] %% 用户查看拼团 B1 --> B2[查看拼团] B2 --> B3[优惠试算] B3 --> B4[展示拼团] %% 用户参与拼团 C1 --> D1[商品支付 / 折扣支付] D1 --> D2[展示拼团 + 分享] D1 --> D3[拼团系统] D3 --> D4[记录拼团/多人拼团] D4 --> D5[团购回调/回调地址] D3 --> D6[拼团超时/拼团失败] D6 --> D7[发起退单] D7 --> D8[团购回调/回调地址] %% 拼团后逻辑 D1 --> E1[拼团订单 暂不发货] E1 --> E2[免拼下单 直接成单] E2 --> E3[拼团完成 商品发货] D6 --> F1[拼团失败 商品退单] E1 --> E4[直接购买 放弃拼团] E4 --> F1 E3 -->|成功| End1([结束]) F1 -->|失败| End2([结束]) flowchart TD A[Throwable] --> B[Error] A --> C[Exception] B --> D[虚拟机错误 VirtualMachineError] B --> E[内存溢出错误 OutOfMemoryError] B --> F[栈溢出错误 StackOverflowError] C --> G[IOException] C --> H[RuntimeException] C --> I[检查异常 Checked Exception （除RuntimeException外的Exception）] G --> J[FileNotFoundException] G --> K[EOFException] H --> L[空指针异常 NullPointerException] H --> M[数组越界异常 ArrayIndexOutOfBoundsException] H --> N[类型转换异常 ClassCastException] H --> O[算术异常 ArithmeticException] flowchart TD A[请求进入方法] --> B{@DCCValue("rateLimiterSwitch:open") == "close"?} B -- 是 --> Z[直接放行 不执行限流逻辑] --> END[方法正常返回] B -- 否 --> C[@RateLimiterAccessInterceptor 拦截方法] C --> D[解析注解参数 获取限流维度 key] D --> E[反射提取方法参数中的字段值 如 userId] E --> F[生成 Redis Key rl:limiter:userId] F --> G{是否在黑名单中?} G -- 是 --> H[调用 fallbackMethod 执行降级逻辑] --> END G -- 否 --> I[通过 RRateLimiter 尝试获取令牌] I -- 成功获取令牌 --> J[执行目标方法] --> END I -- 未获取令牌 --> K[记录拒绝次数 RAtomicLong 自增] K --> L{拒绝次数 > blacklistCount?} L -- 是 --> M[加入黑名单 设置 Key: rl:bl:userId 过期24小时] --> N[调用 fallbackMethod] L -- 否 --> N[调用 fallbackMethod] N --> END[降级逻辑返回结果]
matlab笔记 命令行窗口 clc：清屏（命令行窗口） clear all:把命名的变量删掉，不是命令行窗口 命名规则： 变量命名以字母开头，不可以下划线，变量是区分字母大小写的 脚本 %% xxx 注释（百分号+一个空格） % xxx 也是注释 s='a' '"aaaa",字符串 abs(s) 字符s的ascii码,为97 char(97), 输出'a' numtostr(65) ans='65'，数字转字符串 length(str),字符串的长度 矩阵 A=[1 2 3 ;4 5 6 ;7 8 9] 分号换行 B=A‘ ，矩阵转置 C=A(:) ,将矩阵拉成一列，按列存储，第一列拼接第二列拼接第三列 D=inv(A) 求逆矩阵 E=zeros(10,5,3) 生成10行5列3维0矩阵 元胞数组 ​ A=cell(1,6)，生成1行6列的小格子，每个小格子可以存放各种数据 eye(3),生成3x3的单位阵 ​ A{2}=eye(3),matlab数组从1开始，不是0
llinux服务器（以debian为例） 预先准备 域名购买与解析 购买：Low-Cost Domain Names & Hosting from $0.99 | NameSilo 教程：【服务器、域名购买】Namesilo优惠码和域名解析教程（附带服务器购买推荐和注意事项） | 爱玩实验室 DNS解析：可能需等待几分钟生效 买的域名的r2studying.top 这里的HOSTNAME相当于二级域名，如npm.r2studying.top 现改为CloudFlare来做DNS解析，不用namesilo，它有两种模式： Proxied（橙色云朵）：当你将某个 DNS 记录设置为 Proxied 时，Cloudflare 会作为反向代理服务器处理该域名的 HTTP/HTTPS 流量。这样做有几个效果： 隐藏真实 IP：用户访问时看到的是 Cloudflare 的 Anycast IP，而不是你服务器的真实 IP，从而提高安全性。 提供 CDN 加速：Cloudflare 会缓存静态资源，并通过全球节点加速内容传输，提升网站响应速度。 附加安全防护：包括 DDoS 防护和 Web 应用防火墙等功能。 DNS Only（灰色云朵）：如果你设置为 DNS Only，Cloudflare 只负责 DNS 解析，不会对流量进行代理或处理。也就是说，用户访问时会直接获取并连接到你服务器的真实 IP。 安全组设置 登录云服务器的控制台设置 入站规则 入站规则（Inbound Rules）是指防火墙中用来控制外部流量进入服务器的规则。通过这些规则，你可以指定允许或拒绝哪些类型的网络流量（例如特定协议、端口号、IP地址等）进入你的服务器。 类型 协议端口 源地址 描述 IPv4 TCP : 22 0.0.0.0/0 允许外部访问安全组内实例的SSH(22)端口，用于远程登录Linux实例。 IPv4 TCP : 3389 0.0.0.0/0 允许外部访问安全组内实例的RDP(3389)端口，用于远程登录Windows实例。 IPv4 TCP : 80 0.0.0.0/0 允许外部访问安全组内实例的HTTP(80)端口，用于通过HTTP协议访问网站。 IPv4 TCP : 443 0.0.0.0/0 允许外部访问安全组内实例的HTTPS(443)端口，用于通过HTTPS协议访问网站。 IPv4 TCP : 20-21 0.0.0.0/0 允许通过FTP上传和下载文件。 IPv4 ICMP: 全部 0.0.0.0/0 允许外部使用ping命令验证安全组内实例的网络连通性。 出站规则 出站规则（Outbound Rules）则是指控制服务器向外部发送流量的规则。你可以通过出站规则来限制服务器发出的数据包，比如限制服务器访问某些外部服务或 IP 地址。 凡是服务正常启动但是浏览器上无法访问的，都首先想想防火墙端口是否打开！！！ 常用的命令 cat 用于查看文本文件的内容 head 查看前n行 head -n 100 文件名 tail 查看后n行 tail -n 3 file wc (word count )统计行数、单词数 Hello world Linux is great wc -l file #统计行数: 2 file wc -w file #统计单词数：5 file touch 新建文本文件，如touch /home/hello.py 将在home 文件夹下新建hello.py ls 列出所有文件，但默认只是显示出最基础的文件和文件夹，如果需要更详细的信息，则使用ls -la，这将列出包括隐藏文件在内的所有文件和文件夹，并且给出对应的权限、大小和日期等信息。 zy123@hcss-ecs-588d:~$ ls -la total 44 drwxr-xr-x 6 zy123 zy123 4096 Feb 26 08:53 . drwxr-xr-x 3 root root 4096 Feb 24 16:33 .. -rw------- 1 zy123 zy123 6317 Feb 25 19:41 .bash_history -rw-r--r-- 1 zy123 zy123 220 Feb 24 16:33 .bash_logout -rw-r--r-- 1 zy123 zy123 3526 Feb 24 16:33 .bashrc drwx------ 3 zy123 zy123 4096 Feb 24 16:35 .config drwxr-xr-x 3 zy123 zy123 4096 Feb 24 16:36 .local -rw-r--r-- 1 zy123 zy123 807 Feb 24 16:33 .profile drwxr-xr-x 5 zy123 zy123 4096 Feb 26 08:53 zbparse drwxr-xr-x 3 root root 4096 Feb 26 08:54 zbparse_output 权限与文件类型（第一列）： 第一个字符表示文件类型： “d”表示目录（directory） “-”表示普通文件（regular file） “l”表示符号链接（symbolic link） 后续的9个字符分为3组，每组三个字符，分别代表所有者、所属组和其他用户的权限（读、写、执行）。 硬链接数（第二列）： 表示指向该文件的硬链接数量。对于目录来说，这个数字通常会大于1，因为“.”和“..”也算在内。 所有者（第三列）： 显示该文件或目录的拥有者用户名。 所属组（第四列）： 显示该文件或目录所属的用户组。 文件大小（第五列）： 以字节为单位显示文件的大小。对于目录，通常显示的是目录文件占用的磁盘空间（一般为4096字节）。 最后修改日期和时间（第六列）： 显示文件最后一次修改的日期和时间（可能包含月、日和具体时间或年份）。 文件名或目录名（第七列）： 显示文件或目录的名称。 cd 进入指定文件夹，如cd /home 将进入home目录。返回上层目录的命令是 cd .. ，返回刚才操作的目录的命令是 cd - mkdir 新建文件夹，如 mkdir /home/Python 将在home 文件夹下新建一个Python 文件夹。 mv 移动文件和文件夹，也可以用来重命名，如： mv /home/hello.py /home/helloworld.py 将上文的hello.py重命名为helloworld.py， mv /home/helloworld.py /home/Python/helloworld.py 将helloworld.py 由home文件夹移动到了次级的Python文件夹。 mv /home/hello.py . 将/home/hello.py 移动到当前目录下 cp 复制文件 cp /home/Python/hellowrold.py /home/Python/HelloWorld.py 将helloworld.py复制为HelloWolrd.py。注意：Linux系统严格区分大小写，helloworld.py和HelloWolrd.py是两个文件。 rm 删除，即江湖传说中 rm -rf ，r为递归，可以删除文件夹中的文件，f为强制删除。rm /home/Python/helloworld.py 可以删除刚才的helloworld.py 文件，而想删除包括Python 在内的所有文件，则是 rm -rf /home/Python 。 grep 是用于在文件或标准输入中搜索符合条件的行的命令。 #test.txt Hello World hello linux Grep is useful HELLO GREP # 精确匹配大小写 grep "Hello" test.txt 输出：Hello World -i忽略大小写 -n显示行号 # 忽略大小写匹配 grep -i "hello" test.txt 输出： Hello World hello linux HELLO GREP awk 是一个功能强大的文本处理工具，它可以对文本文件进行分列处理、模式匹配和报告生成。它的语法类似一种简单的脚本语言。 awk 'pattern { action }' filename pattern：用于匹配文本的条件（可以省略，默认对所有行生效）。 action：在匹配的行上执行的操作。 $0：代表整行内容$1+ $2+ $3+ ...。 $1, $2, ...：代表各个列（默认分隔符是空白字符，可以通过 -F 参数指定其他分隔符）。 对于： A B C 1 Alice 25 Engineer 2 Bob 30 Designer awk '{print $1, $3}' filename #印指定列 输出： Alice Engineer Bob Designer sed sed -n '1000,$p' file 对于 filename这个文件，请只打印从第1000行开始一直到文件末尾的所有内容。$代表结尾，p是print打印。 管道 | 是将一个命令的输出直接传递给另一个命令作为输入的一种机制。 示例：将 grep 与 awk 联合使用：假设有一个日志文件 access.log，需要先用 grep 过滤出包含 "ERROR" 的行，再用 awk 提取时间字段： 127.0.0.1 27/Feb/2025:10:30:25 "GET /index.html HTTP/1.1" 200 1024 192.168.1.1 27/Feb/2025:10:31:45 "POST /login HTTP/1.1" 302 512 10.0.0.5 27/Feb/2025:10:32:10 "GET /error_page HTTP/1.1" 500 2048 ERROR grep 'ERROR' access.log | awk '{print $2}' 输出：27/Feb/2025:10:32:10 usermode 修改用户账户信息的命令 sudo usermod -aG docker zy123 #-aG一起用，添加zy123到group组 chmod 命令用于修改文件或目录的权限 数字方式:数字方式使用三个（或四个）数字来表示所有者、组用户和其他用户的权限。每个数字代表读 (4)、写 (2)、执行 (1) 权限的和。 chmod 644 filename #所有者：读 + 写 = 6 组用户：读 = 4 其他用户：读 = 4 符号方式 chmod [用户类别][操作符][权限] filename 用户类别： u：所有者（user） g：组用户（group） o：其他用户（others） a：所有用户（all），等同于 u+g+o 操作符： +：增加权限 -：去掉权限 =：直接设置权限 权限： r：读权限 w：写权限 x：执行权限 chmod u+x filename #为所有者增加执行权限 系统分析 df -h 查看磁盘空间使用情况 lsof"List Open Files"显示系统中当前打开的文件。 -i会显示所有正在使用网络连接的进程 lsof -i :80 #查看 80 端口上的进程,或者判断80端口是否被占用！ netstat -ano | findstr :8080这是windows cmd下检查端口占用的命令 top 用于实时查看系统进程和资源占用情况。（CPU、内存、PID、用户等）。 top -p <pid> 只监控某个进程。 交互操作（进入 top 后按键）：P → 按 CPU 占用率排序；M → 按 内存占用率排序 q → 退出 ps 用于查看当前系统中的进程快照。 ps -ef 查看所有进程的详细信息（常用）。 ps -aux 以 BSD 风格显示进程（带 CPU、内存占用率）。 ps -u <username> 查看某个用户的进程。 ps -p <pid> 查看某个进程的详细信息。 文本编辑器 nano：Debian 11自带了简便易用的nano文本编辑器 nano /etc/apt/sources.list #打开sources.list文件 Ctrl+O:保存修改 ->弹出询问-> Y则保存，N则不保存,ctrl+c 取消操作。 Ctrl+X:退出 vim 普通模式（Normal Mode）： 打开 Vim 后默认进入普通模式。在该模式下，可以执行移动光标、删除、复制、粘贴等命令。 光标移动： 0：跳到当前行行首 $：跳到当前行行尾 gg: 将光标移到文件开头 文本操作： dd：删除（剪切）整行 yy：复制（拷贝）整行 p：在光标后粘贴（把剪切或复制的内容贴上） u：撤销上一步操作 Ctrl + r：重做上一步撤销的操作 插入模式（Insert Mode）： 在普通模式下按 i、I、a、A 等键可进入插入模式，此时可以像普通编辑器那样输入文本。 ​ 按 ESC 键退出插入模式，返回普通模式。 可视模式（Visual Mode）： 用于选中一段文本，自动进入可视模式。选中文本后可以进行复制、剪切等操作。 ​ 在可视模式下选中后按 d 删除 ​ 按 y 复制选中区域 命令行模式（Command-Line Mode）： 在普通模式下，输入 : 进入命令行模式，可以执行保存、退出、查找等命令。 ​ :w：保存当前文件 ​ :q：退出 Vim（如果有未保存的修改会警告） ​ :wq 或 :x：保存文件并退出 ​ :q!：不保存强制退出 ​ :set number：显示行号 ​ :set paste：适用于代码或格式敏感的文本，确保粘贴操作不会破坏原有的布局和缩进。 ​ :%d: 删除全文 抓包 sudo tcpdump -nn -i any port 1000 //查看请求端口1000的源 IP 地址 SSH 1. 生成密钥对 使用以下命令生成安全的 SSH 密钥对： ssh-keygen -t rsa -b 4096 -C "your_email@example.com" 生成的文件默认保存在用户主目录的 ~/.ssh/文件夹中： 私钥 (id_rsa)：必须妥善保存在本地，严禁泄露。这是证明身份的核心凭证。 公钥 (id_rsa.pub)：需要提供给服务端用于身份验证。 2. 核心概念：理解客户端与服务端 SSH 认证是双向的，关键在于分清每次连接中谁是客户端（主动发起连接的一方），谁是服务端（被动接受连接的一方）。 场景一：从服务器拉取 GitHub 代码 角色分配 客户端：你的 Linux 服务器（执行 git clone/push命令的机器） 服务端：GitHub 代码托管平台 认证流程 在客户端（你的服务器）生成 SSH 密钥对 将客户端的公钥内容添加到 GitHub 账户的 SSH Keys 设置中 当服务器执行 git clone git@github.com:...时： GitHub 会用存储的公钥发起挑战 你的服务器用本地私钥完成验证 本质：让你的服务器向 GitHub 证明其合法身份 场景二：通过 FinalShell 连接 Linux 服务器 角色分配 客户端：你的本地 Windows 电脑（运行 FinalShell 的机器） 服务端：目标 Linux 服务器 认证流程 在客户端（你的电脑）生成 SSH 密钥对 将客户端的公钥内容添加到服务端的 ~/.ssh/authorized_keys文件中 当 FinalShell 连接时： Linux 服务器用 authorized_keys中的公钥发起挑战 FinalShell 用本地私钥完成验证 本质：让你的电脑向 Linux 服务器证明你的用户身份 文件系统 在 Linux 系统中，整个文件系统从根目录 / 开始，下面简单介绍一些主要目录及其存放的文件类型： /bin 存放系统启动和运行时必需的用户二进制可执行文件，如常用的 shell 命令（例如 ls、cp、mv 等）。 /boot 包含启动加载器（如 GRUB）的配置文件和内核映像（kernel image），这些文件用于系统启动过程。 /dev 包含设备文件，这些文件代表系统中的各种硬件设备（例如硬盘、终端、USB 设备等），以及一些伪设备。 /etc 存放系统范围内的配置文件，例如网络配置、用户账户信息、服务配置等。这些文件通常由管理员维护。 /home 为普通用户提供的家目录，每个用户在这里有一个独立的子目录，存放个人文件和配置。 /lib 和 /lib64 存放系统和应用程序所需的共享库文件，这些库支持 /bin、/sbin 及其他程序的运行。 /media 通常用于挂载移动介质，如光盘、U 盘或其他可移动存储设备。 /mnt 提供一个临时挂载点，一般供系统管理员在需要手动挂载文件系统时使用。 /opt 用于安装附加的应用程序软件包，通常是第三方提供的独立软件，不与系统核心软件混合。 /proc 这是一个虚拟文件系统，提供内核和进程信息，例如系统资源使用情况、硬件信息、内核参数等。这里的文件不占用实际磁盘空间。 /root 系统管理员（root 用户）的家目录，与普通用户的 /home 分开存放。 /run 存储系统启动后运行时产生的临时数据，比如 PID 文件、锁文件等，系统重启后会清空该目录。 /sbin 存放系统管理和维护所需的二进制文件（系统级命令），例如网络配置、磁盘管理工具等，这些通常只由 root 用户使用。 /srv 用于存放由系统提供的服务数据，如 FTP、HTTP 服务的数据目录等。 /tmp 用于存放临时文件，许多应用程序在运行时会将临时数据写入这里，系统重启后通常会清空该目录。 /usr 存放大量用户应用程序和共享资源，其子目录包括： /usr/bin：大部分用户命令和应用程序。 /usr/sbin：非基本系统维护工具，主要供系统管理员使用。 /usr/lib：程序库文件。 /usr/share：共享数据，如文档、图标、配置样本等。 /var 存放经常变化的数据，如日志文件、缓存、邮件、打印队列和临时应用数据等。 Bash #!/bin/bash # 定义变量，注意等号两边不能有空格 name="World" # 如果脚本传入了参数，则使用第一个参数覆盖默认值 if [ $# -ge 1 ]; then # $# 表示传入脚本的参数个数 name=$1 # $1 表示第一个参数。 fi # 输出问候语 echo "Hello, $name!" #变量引用时要用 $ 符号，如 $name。 # 循环示例：遍历1到5的数字 for i in {1..5}; do echo "当前数字：$i" done # 定义一个函数，函数名为greet greet() { echo "函数内问候: Hello, $1!" } # 调用函数，并传入变量name作为参数 greet $name 如何运行？ 赋予可执行权限 chmod +x hello_world.sh 执行 ./hello_world.sh 或者 ./hello_world.sh Alice #传参 在 Linux 系统中，默认情况下当前目录（.）并不包含在 PATH 环境变量中。这意味着，如果你在终端中直接输入脚本名（例如 hello_world.sh），系统不会在当前目录下查找这个脚本，而是只在 PATH 中指定的目录中查找可执行程序。使用 ./hello_world.sh 表示“在当前目录下执行 hello_world.sh”，从而告诉系统正确的路径。 如何设置定时任务？ sudo crontab -e #在里面添加： 10 0 * * * /path/toyour/xx.sh #让gpt写 反向代理神器——Nginx Proxy Manager 【Docker系列】一个反向代理神器——Nginx Proxy Manager-我不是咕咕鸽 概念 正向代理是代理客户端的行为，即代理服务器代表客户端向目标服务器发出请求。客户端将自己的请求先发送给代理服务器，由代理服务器转发给真正的目标服务器，然后再将返回结果传递给客户端。 特点： 保护访问者（客户端）的信息：目标服务器只会看到代理服务器的请求，无法直接获知真正发起请求的客户端是谁。 应用场景：当客户端出于隐私、访问控制或跨越网络限制的目的，需要隐藏自己的真实IP或身份时，会使用正向代理。 反向代理是代理服务器代表目标服务器接收客户端请求，并将请求转发给内部的真实服务器，然后将结果返回给客户端。客户端只与代理服务器通信，而不知道背后实际处理请求的服务器。 特点： 保护服务器端的信息：客户端看不到真正的服务器细节，只知道代理服务器。这样可以隐藏真实服务器的 IP 和其他内部结构信息，从而增强安全性和负载均衡等功能。 应用场景：在大型网站或应用中，为了防止恶意攻击或实现负载均衡，通常会在真实服务器前部署一个反向代理服务器。 docker 部署 version: '3' services: app: image: 'jc21/nginx-proxy-manager:latest' restart: unless-stopped ports: - '80:80' # 保持默认即可，不建议修改左侧的80 - '81:81' # 冒号左边可以改成自己服务器未被占用的端口 - '443:443' # 保持默认即可，不建议修改左侧的443 volumes: - ./data:/data # 冒号左边可以改路径，现在是表示把数据存放在在当前文件夹下的 data 文件夹中 - ./letsencrypt:/etc/letsencrypt # 冒号左边可以改路径，现在是表示把数据存放在在当前文件夹下的 letsencrypt 文件夹中 NPM后台管理网站运行在81号端口，NPM服务本身监听80(http)和443(https)端口 工作原理 用户访问网站（80/443端口） 当用户访问 https://blog.test.com 时，请求到达服务器的443端口。 Nginx根据域名匹配代理规则（由NPM配置），将请求转发到后端服务（如 192.168.1.100:8080）。 管理员访问后台（81端口） 管理员通过 http://服务器IP:81 访问NPM管理界面，配置代理规则。 配置完成后，NPM会自动生成Nginx配置文件并重启Nginx服务，使新规则生效。 两种方法实现SSL安全连接 1. 开启橙云+Cloudflare Origin CA：网站SSL证书自动续期又又又失败了？试试CloudFlare的免费证书，15年有效期！-我不是咕咕鸽 cloudflare解析DNS，开启橙云 Cloudflare Full (strict)模式(灵活模式下无需以下步骤) 在 Nginx Proxy Manager（NPM）添加 Cloudflare Origin CA 配置 Proxy Host 使其使用 选择刚刚添加的 Cloudflare Origin CA 证书 选择 Force SSL（强制 HTTPS） 启用 HTTP/2 支持 Cloudflare Origin CA作用:实现cloudflare与源服务器之间的流量加密 2.通配符SSL证书：【Docker系列】反向代理神器NginxProxyManager——通配符SSL证书申请-我不是咕咕鸽 更推荐第二种！！！目前正在使用，但是3个月续签一次证书！ 浏览器 → (HTTPS) → NPM → (HTTP 或 HTTPS) → Gitea 这就是反向代理常见的工作流程。 默认经常是 NPM 做 SSL 终止（内网用 HTTP 转发给 Gitea）。如果你想内外全程加密，就要让 NPM -> Gitea 这段也走 HTTPS，并在 Gitea 上正确配置证书。 正向代理（用于拉取镜像） 下载Clash客户端：Release Clash-Premium · DustinWin/proxy-tools 或者Index of /Linux/centOS/ 我是windows上下载clashpremium-release-linux-amd64.tar.gz 然后FTP上传到linux服务器上。 下载配置文件config.yaml：每个人独一无二的 wget -O /home/zy123/VPN/config.yaml "https://illo1.no-mad-world.club/link/2zXAEzExPjAi6xij?clash=3" 类似这样： port: 7890 socks-port: 7891 allow-lan: false mode: Rule //Global log-level: info external-controller: 0.0.0.0:9090 unified-delay: true hosts: time.facebook.com: 17.253.84.125 time.android.com: 17.253.84.125 dns: enable: true use-hosts: true nameserver: - 119.29.29.29 - 223.5.5.5 - 223.6.6.6 - tcp://223.5.5.5 - tcp://223.6.6.6 - tls://dns.google:853 - tls://8.8.8.8:853 - tls://8.8.4.4:853 - tls://dns.alidns.com - tls://223.5.5.5 - tls://223.6.6.6 - tls://dot.pub - tls://1.12.12.12 - tls://120.53.53.53 - https://dns.google/dns-query - https://8.8.8.8/dns-query - https://8.8.4.4/dns-query - https://dns.alidns.com/dns-query - https://223.5.5.5/dns-query - https://223.6.6.6/dns-query - https://doh.pub/dns-query - https://1.12.12.12/dns-query - https://120.53.53.53/dns-query default-nameserver: - 119.29.29.29 - 223.5.5.5 - 223.6.6.6 - tcp://119.29.29.29 - tcp://223.5.5.5 - tcp://223.6.6.6 proxies: - {name: 🇭🇰 香港Y01, server: qvhh1-g03.hk01-ae5.entry.v50307shvkaa.art, port: 19273, type: ss, cipher: aes-256-gcm, password: 6e4124c4-456e-36a3-b144-c0e1a618d04c, udp: true} 注意，魔戒vpn给的是一个订阅地址！！！还需要解码 简便方法：windows上将订阅链接导入，自动解析成yaml配置文件，然后直接把该文件传到服务器上！ 启动Clash ./CrashCore -d . & //后台启动 为Clash创建服务 1.创建 systemd 服务文件 sudo vim /etc/systemd/system/clash.service 2.在文件中添加以下内容： [Unit] Description=Clash Proxy Service After=network.target [Service] ExecStart=/home/zy123/VPN/CrashCore -d /home/zy123/VPN WorkingDirectory=/home/zy123/VPN Restart=always User=zy123 Group=zy123 [Install] WantedBy=multi-user.target 这段配置将 Clash 配置为： 在网络服务启动后运行。 在启动时自动进入后台，执行 CrashCore 服务。 如果服务意外停止，它将自动重启。 以 zy123 用户身份运行 Clash。 启动服务： sudo systemctl start clash 停止服务： sudo systemctl stop clash 查看服务状态： sudo systemctl status clash 配置YACD YACD 是一个基于 Clash 的 Web 管理面板，用于管理您的 Clash 配置、查看流量和节点信息等。 直接用现成的：https://yacd.haishan.me/ 服务器上部署：目前是npm手动构建安装启动的。 下载yacd git clone https://github.com/haishanh/yacd.git 安装npm 构建yacd cd ~/VPN/yacd pnpm install pnpm build 启动yacd nohup pnpm serve --host 0.0.0.0 & //如果不是0.0.0.0 不能在windows上打开 停止进程 ps aux | grep pnpm kill xxx 通过http://124.71.159.195:4173/ 访问yacd控制面板。手动添加crash服务所在的ip:端口。 如果连不上：yacd面板和crash都是http协议就行了。 连接测试 直连： curl -v https://www.google.com 使用代理：curl -x http://127.0.0.1:7890 https://www.google.com File Browser 文件分享 https://github.com/filebrowser/filebrowser Docker 部署 File Browser 文件管理系统_filebrowser docker-CSDN博客 1.创建数据目录 mkdir -p /data/filebrowser/{srv,config,db} 2.目录授权 chmod -R 777 /data/filebrowser/ 3.编辑 docker-compose.yaml 文件 version: '3' services: filebrowser: image: filebrowser/filebrowser:s6 container_name: filebrowser restart: always ports: - "2000:80" # 将容器的80端口映射到宿主机2000端口 volumes: - /data/filebrowser/srv:/srv #保存用户上传的文件 - /data/filebrowser/config:/config # 配置文件存储路径 - /data/filebrowser/db:/database #数据库存储路径 调用API实现文件上传与下载 登录： # 登录 → 获取 JWT token（原始字符串） curl -X POST "yourdomain/api/login" \ -H "Content-Type: application/json" \ -d '{ "username": "admin", "password": "123456" }' 响应: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" //jwt令牌 上传： # 先把 token 保存到环境变量（假设你已经执行过 /api/login 并拿到了 JWT） export TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…" # 定义要上传的本地文件和目标名称 FILE_PATH="/path/to/local/photo.jpg" OBJECT_NAME="photo.jpg" # 对远程路径做 URL 编码（保留斜杠） REMOTE_PATH="store/${OBJECT_NAME}" ENCODED_PATH=$(printf "%s" "${REMOTE_PATH}" \ | jq -sRr @uri \ | sed 's/%2F/\//g') # 发起上传请求（raw body 模式） curl -v -X POST "https://yourdomain/api/resources/${ENCODED_PATH}?override=true" \ -H "X-Auth: ${TOKEN}" \ -H "Content-Type: image/jpeg" \ # 根据文件后缀改成 image/png 等 --data-binary "@${FILE_PATH}" 获取分享链接url： # 假设已经执行过 /api/login 并把 JWT 保存在环境变量 TOKEN # 同样复用之前算好的 ENCODED_PATH 和 REMOTE_PATH # 调用分享接口（注意：POST，body 为空 JSON "{}"） curl -s -X POST "https://yourdomain/api/share/${ENCODED_PATH}" \ -H "X-Auth: ${TOKEN}" \ -H "Cookie: auth=${TOKEN}" \ -H "Content-Type: text/plain;charset=UTF-8" \ -d '{}' \ | jq -r '.hash' \ | xargs -I{} printf "https://yourdomain/api/public/dl/%s/%s\n" {} "${REMOTE_PATH}" Gitea Gitea Docker 安装与使用详解：轻量级自托管 Git 服务教程-CSDN博客 version: "3" services: gitea: image: gitea/gitea:latest container_name: gitea environment: - USER_UID=1000 - USER_GID=1000 restart: always ports: - "3000:3000" # 将宿主机的3000端口映射到容器的3000端口 volumes: - /data/gitea:/data # 持久化存储Gitea数据（包括仓库、配置、日志等） EasyImage 【好玩儿的Docker项目】10分钟搭建一个简单图床——Easyimage-我不是咕咕鸽 github地址：icret/EasyImages2.0: 简单图床 - 一款功能强大无数据库的图床 2.0版 sudo -i # 切换到root用户 apt update -y # 升级packages apt install wget curl sudo vim git # Debian系统比较干净，安装常用的软件 version: '3.3' services: easyimage: image: ddsderek/easyimage:latest container_name: easyimage ports: - '1000:80' environment: - TZ=Asia/Shanghai - PUID=1000 - PGID=1000 volumes: - '/root/data/docker_data/easyimage/config:/app/web/config' - '/root/data/docker_data/easyimage/i:/app/web/i' restart: unless-stopped 网页打开显示bug： cd /data/easyimage/config/config.php 这里添加上https 网站域名 图片域名设置可以改变图片的url：IP或域名 picgo安装： Releases · Molunerfinn/PicGo 1.右下角小窗打开 2.插件设置，搜索web-uploader 1.1.1 （自定义web图床） 旧版有搜索不出来的情况！建议直接安装最新版！ 3.配置如下，API地址从easyimage-设置-API设置中获取 typora设置 左上角文件-偏好设置-图像-插入图片时{ 上传图片-picgo服务器-填写picgo安装路径 } ps:还可以选择上传到./assets，每个md文件独立 或者上传到指定路径如/image，多个md文件共享 py脚本1：将所有md文件中的图片路径改为本地，统一保存到本地output文件夹中 py脚本2：将每个md文件及其所需图片单独保存，保存到本地，但每个md文件有自己独立的assets文件夹 py脚本3：将本地图片上传到easyimage图床并将链接返回替换md文件中的本地路径 Typecho 【好玩儿的Docker项目】10分钟搭建一个Typecho博客｜太破口！念念不忘，必有回响！-我不是咕咕鸽 typecho:https://github.com/typecho/typecho/ 注意：nginx一定要对typecho目录有操作权限！ sudo chmod 755 -R ./typecho services: nginx: image: nginx ports: - "4000:80" # 左边可以改成任意没使用的端口 restart: always environment: - TZ=Asia/Shanghai volumes: - ./typecho:/var/www/html - ./nginx:/etc/nginx/conf.d - ./logs:/var/log/nginx depends_on: - php networks: - web php: build: php restart: always expose: - "9000" # 不暴露公网，故没有写9000:9000 volumes: - ./typecho:/var/www/html environment: - TZ=Asia/Shanghai depends_on: - mysql networks: - web pyapp: build: ./markdown_operation # Dockerfile所在的目录 restart: "no" networks: - web env_file: - .env depends_on: - mysql mysql: image: mysql:5.7 restart: always environment: - TZ=Asia/Shanghai expose: - "3306" # 不暴露公网，故没有写3306:3306 volumes: - ./mysql/data:/var/lib/mysql - ./mysql/logs:/var/log/mysql - ./mysql/conf:/etc/mysql/conf.d env_file: - mysql.env networks: - web networks: web: 卸载： sudo -i # 切换到root cd /root/data/docker_data/typecho # 进入docker-compose所在的文件夹 docker-compose down # 停止容器，此时不会删除映射到本地的数据 cd ~ rm -rf /root/data/docker_data/typecho # 完全删除映射到本地的数据 主题 Joe主题：https://github.com/HaoOuBa/Joe Joe再续前缘主题 - 搭建本站同款网站 - 易航博客 自定义文章详情页的上方信息（如更新日期/文章字数第）： /typecho/usr/themes/Joe/functions.php中定义art_count，统计字数(粗略)。 原始 Markdown → [1] 删除代码块/行内代码/图片/链接标记/标题列表标记/强调符号 → [2] strip_tags() + html_entity_decode() → [3] 正则保留 “文字+数字+标点”，去除其它 → 结果用 mb_strlen() 得到最终字数 typecho/usr/themes/Joe/module/single/batten.php <?php if (!defined('__TYPECHO_ROOT_DIR__')) { http_response_code(404); exit; } ?> <?php $this->title() ?> <a href="<?php $this->author->permalink(); ?>"> <img width="38" height="38" class="avatar lazyload" src="<?php joe\getAvatarLazyload(); ?>" data-src="<?php joe\getAvatarByMail($this->author->mail) ?>" alt="<?php $this->author(); ?>" /> <a class="link" href="<?php $this->author->permalink(); ?>" title="<?php $this->author(); ?>"><?php $this->author(); ?> <?php echo $this->date('Y-m-d'); ?> / <?php $this->commentsNum('%d'); ?> 评论 / <?php echo joe\getAgree($this); ?> 点赞 / <?php echo joe\getViews($this); ?> 阅读 / <?php echo art_count($this->cid); ?> 字 最后更新于 <?php echo date('m-d', $this->modified); ?> 修改代码块背景色： typecho/usr/themes/Joe/assets/css/joe.global.css .joe_detail__article code:not([class]) { border-radius: var(--radius-inner, 4px); /* 可以设置一个默认值 */ background: #f5f5f5; /* 稍微偏灰的背景色 */ color: #000000; /* 黑色字体 */ padding: 2px 6px; /* 内边距可以适当增大 */ font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; word-break: break-word; font-weight: normal; -webkit-text-size-adjust: 100%; -webkit-font-smoothing: antialiased; white-space: pre-wrap; /* 保持代码换行 */ font-size: 0.875em; margin-inline-start: 0.25em; margin-inline-end: 0.25em; } 大坑：{x}会显示为勾选框，无法正常进行latex公式解析，因为typecho/usr/themes/Joe/public/short.php中设置了短代码替换，在文章输出前对 $content 中的特定标记或短代码进行搜索和替换，从而实现一系列自定义功能。现已全部注释。 typecho/usr/themes/Joe/assets/js/joe.single.js原版： 显示弹窗，点叉后消失 { document.querySelector('.joe_detail__article').addEventListener('copy', () => { autolog.log(`本文版权属于 ${Joe.options.title} 转载请标明出处！`, 'warn', false); }); } 显示5秒后消失： document.querySelector('.joe_detail__article').addEventListener('copy', () => { // 显示 autolog 消息 autolog.log(`本文版权属于 ${Joe.options.title} 转载请标明出处！`, 'warn', false); // 5 秒后删除该消息 setTimeout(() => { const warnElem = document.querySelector('.autolog-warn'); if (warnElem) { warnElem.remove(); // 或者使用 warnElem.style.display = 'none'; } }, 5000); }); markdown编辑与解析 确保代码块```后面紧跟着语言，如```java，否则无法正确显示。 markdown编辑器插件：https://xiamp.net/archives/aaeditor-is-another-typecho-editor-plugin.html '开启公式解析！' markdown解析器插件：mrgeneralgoo/typecho-markdown: A markdown parse plugin for typecho. 关闭公式解析，仅开启代码解析！ slug为页面缩略名，在新增文章时可以传入，默认是index数字。 qBittorrent 【好玩的Docker项目】10分钟搭建你专属的下载神器——qbittorrent-我不是咕咕鸽 docker pull linuxserver/qbittorrent cd ~ mkdir /root/data/docker_data/qBittorrent #创建qbitorrent数据文件夹 cd /root/data/docker_data/qBittorrent mkdir config downloads #创建配置文件目录与下载目录 nano docker-compose.yml #创建并编辑文件 services: qbittorrent: image: linuxserver/qbittorrent container_name: qbittorrent environment: - PUID=1000 - PGID=1000 - TZ=Asia/Shanghai # 你的时区 - UMASK_SET=022 - WEBUI_PORT=8081 # 将此处修改成你欲使用的 WEB 管理平台端口 volumes: - ./config:/config # 绝对路径请修改为自己的config文件夹 - ./downloads:/downloads # 绝对路径请修改为自己的downloads文件夹 ports: # 要使用的映射下载端口与内部下载端口，可保持默认，安装完成后在管理页面仍然可以改成其他端口。 - 6881:6881 - 6881:6881/udp # 此处WEB UI 目标端口与内部端口务必保证相同，见问题1 - 8081:8081 restart: unless-stopped 有个bug！qBittorrent 登录遇到 unauthorized的解决方法： 1、先停止容器docker compose down 2、进入配置文件夹config，编辑qBittorrent.conf在文末加上： WebUI\HostHeaderValidation=false WebUI\CSRFProtection=false 3.如果还是进不去，在地址后端添加'/' 内网穿透 使用服务提供商 网址：https://natapp.cn 1.隧道查看 2.隧道配置 配置映射关系： 3.客户端下载与配置 https://natapp.cn/#download ，参考官方文档，配置本地token，启动本地客户端。 自己搭建FRP 数据流转流程 外部请求到达 frp-server 你在 frps.ini（服务端配置）里为某个 proxy 分配了一个 remote_port（或 custom_domains）。 当外部用户（浏览器、移动端、其他服务）访问 http://your.frps.ip:remote_port/... 时，流量首先打到你部署在公网的 frp-server 上。 frp-server 转发到 frp-client frp-server 维护着一个与每个 frp-client 的长连接（control connection）。 收到外部连接后，frp-server 会基于这个 control 通道告诉对应的 frp-client： “有一个新连接，请你去拿 proxy(name) 对应的后端服务数据。” frp-server 不自己去连 Java 后端，它只是做信令和数据的“管道”管理。 frp-client 建立到本地 Java 服务的连接 frp-client 收到信令后，内部根据 proxies 配置： proxies name = "my-java-app" type = "tcp" local_ip = "127.0.0.1" local_port = 8080 remote_port= 18080 它会在容器或宿主机内部打开一个新的 TCP 连接，指向 127.0.0.1:8080（即你的 Java 服务） frp-server frps.toml: # https://github.com/fatedier/frp/blob/dev/conf/frps_full_example.toml [common] # 监听端口 bind_port = 7000 # 面板端口 dashboard_port = 7500 # 登录面板的账号密码（修改成自己的） dashboard_user = admin dashboard_pwd = admin # token = docker-compose: version: '3.9' services: frps: image: fatedier/frps:v0.60.0 hostname: frps container_name: frps volumes: - "./config/frps.toml:/frps.toml" command: - "-c" - "/frps.toml" network_mode: "host" frp-client frpc.toml: # 服务端地址 https://github.com/fatedier/frp/blob/dev/conf/frpc_full_example.toml serverAddr = "124.71.159.195" # 服务端配置的bindPort serverPort = 7000 # token = proxies # 代理应用名称，根据自己需要进行配置 name = "smile-dev-tech-01" # 代理类型 有tcp\udp\stcp\p2p type = "tcp" # 客户端代理应用IP localIP = "host.docker.internal" # 客户端代理应用端口 localPort = 8234 # 服务端反向代理端口；提供给外部访问 remotePort = 8234 proxies # 代理应用名称，根据自己需要进行配置 name = "smile-dev-tech-02" # 代理类型 有tcp\udp\stcp\p2p type = "tcp" # 客户端代理应用IP localIP = "host.docker.internal" # 客户端代理应用端口 localPort = 9001 # 服务端反向代理端口；提供给外部访问 remotePort = 9001 docker-compose: # 命令执行 docker-compose -f docker-compose.yml up -d version: '3.9' services: frpc: image: fatedier/frpc:v0.60.0 hostname: frpc container_name: frpc volumes: - "./config/frpc.toml:/frpc.toml" command: - "-c" - "/frpc.toml" network_mode: "host" frp-server必须部署在有公网ip的服务器，frp-client客户端有两种部署方式： 1.docker部署，如上 2.下载windows客户端https://github.com/fatedier/frp/releases/tag/v0.60.0 **注意：**如果java后端和client都部署在docker同一网络中，frpc.toml 中 localIP = "localhost" 如果client在docker容器，java在idea中启动，那么 localIP = "host.docker.internal" 如果client在windows下启动，java在idea中启动， localIP = "localhost" 总之，关键是让client和java互通；client和server互通比较容易！！！ 公网ip:7500 可以查看面板。