[{"content":"模型选择 本地大模型-oMLX 先部署oMLX\nANTHROPIC_BASE_URL=\u0026#39;http://127.0.0.1:8000\u0026#39; ANTHROPIC_AUTH_TOKEN=\u0026#39;$密钥\u0026#39; ANTHROPIC_DEFAULT_OPUS_MODEL=\u0026#39;Qwen3.5-35B-A3B-4bit\u0026#39; ANTHROPIC_DEFAULT_SONNET_MODEL=\u0026#39;Qwen3.5-35B-A3B-4bit\u0026#39; ANTHROPIC_DEFAULT_HAIKU_MODEL=\u0026#39;Qwen3.5-4B-MLX-4bit\u0026#39; API_TIMEOUT_MS=3000000 CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 claude /init 命令 学习此文件夹里的项目文件, 帮助ai更快的理解这个项目 类似cursor-rule\n/compact 压缩上下文\n/clear 清除上下文, 用于开启一个新任务, 保持一个干净的上下文\n/think, think hard, think harder, ultrathink 控制模型思考长度\n! 感叹号 输入!感叹号, 将对话窗口切换为命令行模型\n例如需要执行 npm install 执行后, ai会将结果加上下文, 后面ai就不会重复安装\n“#” 井号,进入记忆模型 输入的文字将会成为claude的记忆\n~/.claude/claude.md 全局记忆\n/ide 使用这个命令之前, 需要先安装插件 以vscode为例子: 先安装claude插件, 选中后, claude能感知到\nclaude -p 临时对话 后台思考, 命令行ai助手\nmcp server MCP（Model Context Protocol） 是 Anthropic 推出的开放标准协议，让 Claude 能够以统一方式连接各种外部工具和数据源。 一个让 Claude 与外部世界通信的开放标准。类比 USB——不同厂商的设备都能插进同一个接口。\n在 claude_desktop_config.json 中注册 Server { \u0026#34;mcpServers\u0026#34;: { \u0026#34;filesystem\u0026#34;: { \u0026#34;command\u0026#34;: \u0026#34;npx\u0026#34;, \u0026#34;args\u0026#34;: [\u0026#34;-y\u0026#34;, \u0026#34;@modelcontextprotocol/server-filesystem\u0026#34;, \u0026#34;/Users/me/projects\u0026#34;] }, \u0026#34;my-db-server\u0026#34;: { \u0026#34;command\u0026#34;: \u0026#34;python3\u0026#34;, \u0026#34;args\u0026#34;: [\u0026#34;/path/to/my_mcp_server.py\u0026#34;], \u0026#34;env\u0026#34;: { \u0026#34;DB_URL\u0026#34;: \u0026#34;postgresql://localhost/mydb\u0026#34; } } } } 自定义mcp-server from mcp.server.fastmcp import FastMCP import psycopg2, os mcp = FastMCP(\u0026#34;my-db-server\u0026#34;) # 声明一个 Tool：Claude 可主动调用 @mcp.tool() def query_sales(start_date: str, end_date: str) -\u0026gt; str: \u0026#34;\u0026#34;\u0026#34;查询指定日期范围内的销售数据\u0026#34;\u0026#34;\u0026#34; conn = psycopg2.connect(os.environ[\u0026#34;DB_URL\u0026#34;]) cur = conn.cursor() cur.execute( \u0026#34;SELECT product, SUM(amount) FROM sales WHERE date BETWEEN %s AND %s GROUP BY product\u0026#34;, (start_date, end_date) ) rows = cur.fetchall() return \u0026#34;\\n\u0026#34;.join(f\u0026#34;{r[0]}: {r[1]}\u0026#34; for r in rows) # 声明一个 Resource：Claude 可读取的静态数据 @mcp.resource(\u0026#34;db://schema\u0026#34;) def get_schema() -\u0026gt; str: \u0026#34;\u0026#34;\u0026#34;返回数据库表结构\u0026#34;\u0026#34;\u0026#34; return \u0026#34;sales(date, product, amount, region)\u0026#34; if __name__ == \u0026#34;__main__\u0026#34;: mcp.run() # 默认走 stdio 传输 最新代码文档的 mcp claude mcp add context7 \u0026ndash; npx\n/permission 授权 控制\u0026quot;Claude 被允许做什么\u0026quot;的核心机制。\n允许所有工具，但 Bash 命令须人工确认（默认行为）\n{ \u0026#34;allowedTools\u0026#34;: [\u0026#34;*\u0026#34;], \u0026#34;hooks\u0026#34;: { \u0026#34;PreToolUse\u0026#34;: [ { \u0026#34;matcher\u0026#34;: \u0026#34;Bash\u0026#34;, \u0026#34;hooks\u0026#34;: [{ \u0026#34;type\u0026#34;: \u0026#34;command\u0026#34;, \u0026#34;command\u0026#34;: \u0026#34;bash ~/.claude/hooks/confirm.sh\u0026#34; }] } ] } } 无人值守\nclaude --dangerously-skip-permissions 自定义命令 示例: code_review.md git diff 命令, 给出意见\n添加描述: 对比这个分支, 查看差异\nHooks 允许你在 Agent 生命周期的特定时间点注入自定义脚本——拦截、审计、修改或阻止 Claude 的行为。先看整体流程图，再看具体示例。 4 个 Hook 时机： PreToolUse — 工具调用前，可以 阻止或批准。最常用于安全拦截（禁止危险命令、需要人工二次确认等） PostToolUse — 工具完成后，拿到输入+输出。适合审计日志、格式校验、自动测试 Notification — Claude 要发送通知时触发，可以转发到任意渠道 Stop — Agent 全部结束时触发，适合发完成通知、清理临时文件\nHooks 写在 ~/.claude/settings.json（全局）或项目的 .claude/settings.json 中：\n{ \u0026#34;hooks\u0026#34;: { \u0026#34;PreToolUse\u0026#34;: [ { \u0026#34;matcher\u0026#34;: \u0026#34;Bash\u0026#34;, \u0026#34;hooks\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;command\u0026#34;, \u0026#34;command\u0026#34;: \u0026#34;python3 ~/.claude/hooks/check_bash.py\u0026#34; } ] } ] } } /agents 普通对话是\u0026quot;一问一答\u0026quot;，而 Agent 是\u0026quot;给我一个目标，我来自己想办法完成它\u0026quot;。\n创建一个审核代码的agent 示例: 你是一位资深的代码审核专家, 拥有丰富的代码开发和代码质量管理经验, 你的专长是分析git分支之间的代码差异, 并提供专业, 详细的代码审核意见\n","permalink":"http://fxio.site/posts/ai/claude-code/","summary":"\u003ch2 id=\"模型选择\"\u003e模型选择\u003c/h2\u003e\n\u003ch3 id=\"本地大模型-omlx\"\u003e本地大模型-oMLX\u003c/h3\u003e\n\u003cp\u003e先部署oMLX\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nv\"\u003eANTHROPIC_BASE_URL\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;http://127.0.0.1:8000\u0026#39;\u003c/span\u003e \u003cspan class=\"nv\"\u003eANTHROPIC_AUTH_TOKEN\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;$密钥\u0026#39;\u003c/span\u003e \u003cspan class=\"nv\"\u003eANTHROPIC_DEFAULT_OPUS_MODEL\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;Qwen3.5-35B-A3B-4bit\u0026#39;\u003c/span\u003e \u003cspan class=\"nv\"\u003eANTHROPIC_DEFAULT_SONNET_MODEL\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;Qwen3.5-35B-A3B-4bit\u0026#39;\u003c/span\u003e \u003cspan class=\"nv\"\u003eANTHROPIC_DEFAULT_HAIKU_MODEL\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;Qwen3.5-4B-MLX-4bit\u0026#39;\u003c/span\u003e \u003cspan class=\"nv\"\u003eAPI_TIMEOUT_MS\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"m\"\u003e3000000\u003c/span\u003e \u003cspan class=\"nv\"\u003eCLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"m\"\u003e1\u003c/span\u003e claude\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"init-命令\"\u003e/init 命令\u003c/h2\u003e\n\u003cp\u003e学习此文件夹里的项目文件, 帮助ai更快的理解这个项目\n类似cursor-rule\u003c/p\u003e\n\u003ch2 id=\"compact\"\u003e/compact\u003c/h2\u003e\n\u003cp\u003e压缩上下文\u003c/p\u003e\n\u003ch2 id=\"clear\"\u003e/clear\u003c/h2\u003e\n\u003cp\u003e清除上下文, 用于开启一个新任务, 保持一个干净的上下文\u003c/p\u003e\n\u003ch2 id=\"think-think-hard-think-harder-ultrathink\"\u003e/think, think hard, think harder, ultrathink\u003c/h2\u003e\n\u003cp\u003e控制模型思考长度\u003c/p\u003e\n\u003ch2 id=\"-感叹号\"\u003e! 感叹号\u003c/h2\u003e\n\u003cp\u003e输入!感叹号, 将对话窗口切换为命令行模型\u003c/p\u003e\n\u003cp\u003e例如需要执行 npm install\n执行后, ai会将结果加上下文, 后面ai就不会重复安装\u003c/p\u003e\n\u003ch2 id=\"-井号进入记忆模型\"\u003e“#” 井号,进入记忆模型\u003c/h2\u003e\n\u003cp\u003e输入的文字将会成为claude的记忆\u003c/p\u003e\n\u003cp\u003e~/.claude/claude.md 全局记忆\u003c/p\u003e\n\u003ch2 id=\"ide\"\u003e/ide\u003c/h2\u003e\n\u003cp\u003e使用这个命令之前, 需要先安装插件\n以vscode为例子: 先安装claude插件, 选中后, claude能感知到\u003c/p\u003e\n\u003ch2 id=\"claude--p-临时对话\"\u003eclaude -p 临时对话\u003c/h2\u003e\n\u003cp\u003e后台思考, 命令行ai助手\u003c/p\u003e\n\u003ch2 id=\"mcp-server\"\u003emcp server\u003c/h2\u003e\n\u003cp\u003eMCP（Model Context Protocol） 是 Anthropic 推出的开放标准协议，让 Claude 能够以统一方式连接各种外部工具和数据源。\n一个让 Claude 与外部世界通信的开放标准。类比 USB——不同厂商的设备都能插进同一个接口。\u003c/p\u003e\n\u003cp\u003e\u003cimg alt=\"img_2.png\" loading=\"lazy\" src=\"/posts/ai/claude-code/img_2.png\"\u003e\u003c/p\u003e\n\u003ch3 id=\"在-claude_desktop_configjson-中注册-server\"\u003e在 claude_desktop_config.json 中注册 Server\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026#34;mcpServers\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026#34;filesystem\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nt\"\u003e\u0026#34;command\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;npx\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nt\"\u003e\u0026#34;args\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;-y\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;@modelcontextprotocol/server-filesystem\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;/Users/me/projects\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e},\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026#34;my-db-server\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nt\"\u003e\u0026#34;command\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;python3\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nt\"\u003e\u0026#34;args\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;/path/to/my_mcp_server.py\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e],\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"nt\"\u003e\u0026#34;env\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e \u003cspan class=\"nt\"\u003e\u0026#34;DB_URL\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;postgresql://localhost/mydb\u0026#34;\u003c/span\u003e \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"自定义mcp-server\"\u003e自定义mcp-server\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003efrom\u003c/span\u003e \u003cspan class=\"nn\"\u003emcp.server.fastmcp\u003c/span\u003e \u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"n\"\u003eFastMCP\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003eimport\u003c/span\u003e \u003cspan class=\"nn\"\u003epsycopg2\u003c/span\u003e\u003cspan class=\"o\"\u003e,\u003c/span\u003e \u003cspan class=\"nn\"\u003eos\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003emcp\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eFastMCP\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;my-db-server\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 声明一个 Tool：Claude 可主动调用\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nd\"\u003e@mcp.tool\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003equery_sales\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estart_date\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nb\"\u003estr\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eend_date\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"nb\"\u003estr\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"nb\"\u003estr\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s2\"\u003e\u0026#34;\u0026#34;\u0026#34;查询指定日期范围内的销售数据\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003econn\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003epsycopg2\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003econnect\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eos\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eenviron\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;DB_URL\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e])\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ecur\u003c/span\u003e  \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003econn\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ecursor\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003ecur\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eexecute\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"s2\"\u003e\u0026#34;SELECT product, SUM(amount) FROM sales WHERE date BETWEEN \u003c/span\u003e\u003cspan class=\"si\"\u003e%s\u003c/span\u003e\u003cspan class=\"s2\"\u003e AND \u003c/span\u003e\u003cspan class=\"si\"\u003e%s\u003c/span\u003e\u003cspan class=\"s2\"\u003e GROUP BY product\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003estart_date\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003eend_date\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003erows\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003ecur\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003efetchall\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"se\"\u003e\\n\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003ejoin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"sa\"\u003ef\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003er\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e0\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e: \u003c/span\u003e\u003cspan class=\"si\"\u003e{\u003c/span\u003e\u003cspan class=\"n\"\u003er\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"mi\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\u003cspan class=\"si\"\u003e}\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u003c/span\u003e \u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003er\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003erows\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 声明一个 Resource：Claude 可读取的静态数据\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nd\"\u003e@mcp.resource\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;db://schema\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003edef\u003c/span\u003e \u003cspan class=\"nf\"\u003eget_schema\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e-\u0026gt;\u003c/span\u003e \u003cspan class=\"nb\"\u003estr\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s2\"\u003e\u0026#34;\u0026#34;\u0026#34;返回数据库表结构\u0026#34;\u0026#34;\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;sales(date, product, amount, region)\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"vm\"\u003e__name__\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;__main__\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003emcp\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003erun\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e  \u003cspan class=\"c1\"\u003e# 默认走 stdio 传输\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"最新代码文档的-mcp\"\u003e最新代码文档的 mcp\u003c/h3\u003e\n\u003cp\u003eclaude mcp add context7 \u0026ndash; npx\u003c/p\u003e","title":"Claude Code"},{"content":"oMLX是什么? omlx.ai（通常指 oMLX 项目）是一个专为 Apple Silicon（M1/M2/M3/M4 系列芯片）设计的本地大语言模型（LLM）推理服务器。它的核心目标是让 Mac 用户能够以极高的效率、极低的延迟在本地运行各种 AI 模型（如 Llama 3、Mistral、DeepSeek 等）。\n简单来说，它是对 Apple 官方 MLX 框架的深度封装和功能扩展，提供了一个类似 OpenAI/Anthropic 接口的本地后端，并附带了美观的 macOS 菜单栏管理工具。\noMLX 速度提升的核心原理 oMLX 之所以能在 Mac 上跑出惊人的速度，主要归功于以下几个技术层面的深度优化：\n1. 统一内存架构 (Unified Memory Architecture) 这是 Apple Silicon 的硬件优势，也是 MLX 框架的灵魂。\n原理：在传统 PC 中，数据需要在 CPU 内存和 GPU 显存之间来回拷贝。而 oMLX 利用了 Mac 的统一内存，CPU 和 GPU 共享同一块物理内存。 提升：消除了昂贵的显存带宽瓶颈，模型数据加载到内存后，GPU 可以直接读取并处理，极大减少了延迟。 2. 双层 KV 缓存系统 (Two-Tier KV Cache) 这是 oMLX 最具创新性的优化点，解决了大上下文下的重复计算问题。\n热缓存 (RAM)：正在进行的对话上下文保存在内存中，实现即时响应。 冷缓存 (SSD)：当内存满了或服务器重启时，oMLX 会将过往的 KV 缓存以 safetensors 格式持久化到 SSD。 提升：当你再次输入相似的 Prompt 或继续之前的长对话时，系统直接从磁盘恢复缓存，无需重新计算（Prefill）。这使得处理数万字上下文的“首字延迟”大幅缩短。 3. 连续批处理 (Continuous Batching) 通过集成 mlx-lm 的 BatchGenerator 技术，oMLX 能够同时处理多个并发请求。\n原理：它不像传统的排队机制，而是将不同请求的 Prefill（预填充）和 Decoding（生成）阶段交织在一起。 提升：极大地提高了 GPU 的利用率，在多任务处理或多用户连接时，整体吞吐量（Throughput）显著提升。 4. 延迟计算 (Lazy Computation) 继承自 MLX 框架的特性。\n原理：只有在真正需要计算结果时，才会触发底层的 Metal 图构建和执行。 提升：这种机制允许框架在执行前对计算图进行整体优化，减少了不必要的中间计算步骤。 5. 针对 Metal 4 的深度优化 oMLX 利用了 Apple 最新的 Metal 加速接口。\n原理：针对 Apple GPU 的 Tensor 内核进行了指令级优化，特别是针对矩阵乘法（GEMM）等 LLM 核心运算。 提升：在相同的硬件下，比通用的推理后端（如早期的 llama.cpp 某些版本）拥有更高的 FP16 或量化模型推理速度。 总结：为什么要用它？ 如果你在 Mac 上进行 AI 开发或使用（例如配合 Claude Code 或 Cursor），oMLX 的优势在于：\n快：冷/热缓存机制让长对话几乎秒开。 省：比运行 Python 脚本更省内存，支持自动卸载不使用的模型。 全：支持 VLM（多模态视觉）、Embedding（嵌入）、Rerank（重排序）等全套模型。 它将 Mac 从一台普通的办公电脑，变成了一个拥有高性能、低延迟 AI 能力的“个人 AI 服务器”。\noMLX应用 本地api服务 OpenAI API http://127.0.0.1:8000/v1\nclaude ANTHROPIC_BASE_URL=\u0026lsquo;http://127.0.0.1:8000\u0026rsquo; ANTHROPIC_AUTH_TOKEN=\u0026lsquo;key-xxx\u0026rsquo; ANTHROPIC_DEFAULT_OPUS_MODEL=\u0026lsquo;Qwen3.5-35B-A3B-4bit\u0026rsquo; ANTHROPIC_DEFAULT_SONNET_MODEL=\u0026lsquo;Qwen3.5-35B-A3B-4bit\u0026rsquo; ANTHROPIC_DEFAULT_HAIKU_MODEL=\u0026lsquo;Qwen3.5-4B-MLX-4bit\u0026rsquo; API_TIMEOUT_MS=3000000 CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 claude\nopenclaw \u0026lsquo;/Applications/oMLX.app/Contents/MacOS/omlx-cli\u0026rsquo; launch openclaw \u0026ndash;model \u0026lsquo;Qwen3.5-35B-A3B-4bit\u0026rsquo; \u0026ndash;api-key \u0026lsquo;key-xxx\u0026rsquo; \u0026ndash;tools-profile \u0026lsquo;coding\u0026rsquo;\n","permalink":"http://fxio.site/posts/ai/omlx/","summary":"\u003ch2 id=\"omlx是什么\"\u003eoMLX是什么?\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eomlx.ai\u003c/strong\u003e（通常指 \u003cstrong\u003eoMLX\u003c/strong\u003e 项目）是一个专为 Apple Silicon（M1/M2/M3/M4 系列芯片）设计的本地大语言模型（LLM）推理服务器。它的核心目标是让 Mac 用户能够以极高的效率、极低的延迟在本地运行各种 AI 模型（如 Llama 3、Mistral、DeepSeek 等）。\u003c/p\u003e\n\u003cp\u003e简单来说，它是对 Apple 官方 \u003cstrong\u003eMLX\u003c/strong\u003e 框架的深度封装和功能扩展，提供了一个类似 OpenAI/Anthropic 接口的本地后端，并附带了美观的 macOS 菜单栏管理工具。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"omlx-速度提升的核心原理\"\u003eoMLX 速度提升的核心原理\u003c/h3\u003e\n\u003cp\u003eoMLX 之所以能在 Mac 上跑出惊人的速度，主要归功于以下几个技术层面的深度优化：\u003c/p\u003e\n\u003ch4 id=\"1-统一内存架构-unified-memory-architecture\"\u003e1. 统一内存架构 (Unified Memory Architecture)\u003c/h4\u003e\n\u003cp\u003e这是 Apple Silicon 的硬件优势，也是 MLX 框架的灵魂。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e原理\u003c/strong\u003e：在传统 PC 中，数据需要在 CPU 内存和 GPU 显存之间来回拷贝。而 oMLX 利用了 Mac 的统一内存，CPU 和 GPU 共享同一块物理内存。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e提升\u003c/strong\u003e：消除了昂贵的显存带宽瓶颈，模型数据加载到内存后，GPU 可以直接读取并处理，极大减少了延迟。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"2-双层-kv-缓存系统-two-tier-kv-cache\"\u003e2. 双层 KV 缓存系统 (Two-Tier KV Cache)\u003c/h4\u003e\n\u003cp\u003e这是 oMLX 最具创新性的优化点，解决了大上下文下的重复计算问题。\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e热缓存 (RAM)\u003c/strong\u003e：正在进行的对话上下文保存在内存中，实现即时响应。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e冷缓存 (SSD)\u003c/strong\u003e：当内存满了或服务器重启时，oMLX 会将过往的 KV 缓存以 \u003ccode\u003esafetensors\u003c/code\u003e 格式持久化到 SSD。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e提升\u003c/strong\u003e：当你再次输入相似的 Prompt 或继续之前的长对话时，系统直接从磁盘恢复缓存，\u003cstrong\u003e无需重新计算（Prefill）\u003c/strong\u003e。这使得处理数万字上下文的“首字延迟”大幅缩短。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch4 id=\"3-连续批处理-continuous-batching\"\u003e3. 连续批处理 (Continuous Batching)\u003c/h4\u003e\n\u003cp\u003e通过集成 \u003ccode\u003emlx-lm\u003c/code\u003e 的 BatchGenerator 技术，oMLX 能够同时处理多个并发请求。\u003c/p\u003e","title":"OMLX"},{"content":"Function Calling（函数调用）是人工智能领域，特别是大语言模型（LLM）应用中的一项关键技术。它允许 AI 模型不仅生成文本，还能主动选择并执行外部定义的函数或工具，以解决超出其内部知识库的问题，或完成需要精确计算、实时数据查询等任务。\n简单来说，就是让 AI 学会“调用代码”来干活，而不仅仅是“说话”。\n1. 核心概念：AI 如何调用函数？ 在传统的 LLM 交互中，用户输入提示词（Prompt），模型直接生成文本回答。而在 Function Calling 模式下，流程发生了变化：\n定义工具：开发者预先定义一组函数（Function Schema），描述这些函数的名称、参数类型、参数含义以及返回值。 模型决策：当用户提问时，模型会根据意图判断：是否需要调用某个函数？如果需要，它会自动生成一个包含函数名称和参数值的结构化请求（通常是 JSON 格式）。 执行与反馈：用户的后端服务器接收到这个请求，执行真实的函数逻辑，获取结果。 模型生成回答：系统将执行结果（如天气数据、搜索结果、数据库记录）传回给模型，模型结合原始问题和执行结果，生成最终的自然语言回答。 2. 为什么需要 Function Calling？ 大模型本身存在一些局限性，通过函数调用可以弥补：\n时效性问题：LLM 的训练数据有截止时间，无法知道“现在的天气”或“今天的股价”。通过调用 API，模型可以获取实时数据。 精确计算与逻辑：LLM 在处理复杂数学运算或精确代码执行时容易出错（幻觉）。调用 Python 解释器或计算器函数可以得到 100% 准确的结果。 访问私有数据：企业的数据在内部数据库中，模型无法直接读取。通过调用内部 API，模型可以查询订单状态或用户信息。 控制输出格式：让模型生成结构化的 JSON 数据，而不是长篇大论的文本，便于程序后续处理。 3. 工作流程示例 假设你正在开发一个智能天气助手：\n开发者定义函数：\n函数名：get_current_weather 参数：location (string), unit (string: \u0026ldquo;celsius\u0026rdquo; or \u0026ldquo;fahrenheit\u0026rdquo;) 用户提问：\n“上海现在的气温是多少？用摄氏度表示。”\n模型推理与调用： 模型识别到需要查询天气，于是输出如下结构（JSON）：\n{ \u0026#34;name\u0026#34;: \u0026#34;get_current_weather\u0026#34;, \u0026#34;arguments\u0026#34;: { \u0026#34;location\u0026#34;: \u0026#34;上海\u0026#34;, \u0026#34;unit\u0026#34;: \u0026#34;celsius\u0026#34; } } 后端执行： 你的代码解析出 JSON，调用真实的天气 API，得到结果：{\u0026quot;temp\u0026quot;: 24, \u0026quot;status\u0026quot;: \u0026quot;sunny\u0026quot;}。\n模型生成回答： 系统将执行结果传回模型，模型生成最终回复：\n“上海目前的天气是晴朗，气温为 24 摄氏度。”\n4. 主要实现方式 目前主流的大模型厂商（如 OpenAI、Google Gemini、Anthropic Claude、国内的文心一言/通义千问等）都原生支持或提供了类似的 Function Calling 接口。\nOpenAI (gpt-3.5-turbo / gpt-4)：引入了 tools 参数，支持定义函数列表，模型会自动选择调用。 Google Vertex AI / Gemini：原生支持 Tools，允许模型生成 function_call 对象。 LangChain / LlamaIndex：作为编排框架，它们提供了封装好的 FunctionExecutor 机制，简化了开发者将函数与 LLM 对接的过程。 Ollama / Local Models：通过特定协议（如 OpenAPI 格式）支持本地模型的函数调用。 5. 优势与挑战 优势 从“聊天机器人”进化为“智能代理”（Agent）：这是构建自主 Agent 的基石，模型可以自主规划任务、调用工具、循环执行直到解决问题。 准确性提升：减少了模型在数值和事实性上的幻觉。 灵活性：可以无限扩展外部能力，只要你能写出对应的 API 函数。 挑战 错误处理：如果函数执行失败（如网络超时），如何优雅地反馈给模型并让其重试，需要良好的工程逻辑。 参数校验：模型生成的参数可能不符合类型要求，后端代码需要做严格的校验。 延迟：调用外部 API 会增加响应时间，需要异步处理或流式输出优化用户体验。 安全风险：如果函数权限控制不当，模型可能会调用删除数据库、发送垃圾邮件等危险函数（需严格限制模型可调用的函数列表）。 总结 Function Calling 是大模型从“知识库”迈向“行动库”的关键转折点。它打破了 AI 只能“说话”的限制，使其能够真正介入现实世界的操作、查询和执行。对于开发者而言，构建 Function Calling 能力是实现生产级 AI 应用（如自动化客服、数据分析助手、代码生成器）的必经之路。\n","permalink":"http://fxio.site/posts/ai/function-calling/","summary":"\u003cp\u003e\u003cstrong\u003eFunction Calling\u003c/strong\u003e（函数调用）是人工智能领域，特别是大语言模型（LLM）应用中的一项关键技术。它允许 AI 模型不仅生成文本，还能\u003cstrong\u003e主动选择并执行外部定义的函数或工具\u003c/strong\u003e，以解决超出其内部知识库的问题，或完成需要精确计算、实时数据查询等任务。\u003c/p\u003e\n\u003cp\u003e简单来说，就是让 AI 学会“调用代码”来干活，而不仅仅是“说话”。\u003c/p\u003e\n\u003chr\u003e\n\u003ch3 id=\"1-核心概念ai-如何调用函数\"\u003e1. 核心概念：AI 如何调用函数？\u003c/h3\u003e\n\u003cp\u003e在传统的 LLM 交互中，用户输入提示词（Prompt），模型直接生成文本回答。而在 \u003cstrong\u003eFunction Calling\u003c/strong\u003e 模式下，流程发生了变化：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003e定义工具\u003c/strong\u003e：开发者预先定义一组函数（Function Schema），描述这些函数的名称、参数类型、参数含义以及返回值。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e模型决策\u003c/strong\u003e：当用户提问时，模型会根据意图判断：是否需要调用某个函数？如果需要，它会自动生成一个包含函数名称和参数值的结构化请求（通常是 JSON 格式）。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e执行与反馈\u003c/strong\u003e：用户的后端服务器接收到这个请求，执行真实的函数逻辑，获取结果。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e模型生成回答\u003c/strong\u003e：系统将执行结果（如天气数据、搜索结果、数据库记录）传回给模型，模型结合原始问题和执行结果，生成最终的自然语言回答。\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch3 id=\"2-为什么需要-function-calling\"\u003e2. 为什么需要 Function Calling？\u003c/h3\u003e\n\u003cp\u003e大模型本身存在一些局限性，通过函数调用可以弥补：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e时效性问题\u003c/strong\u003e：LLM 的训练数据有截止时间，无法知道“现在的天气”或“今天的股价”。通过调用 API，模型可以获取实时数据。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e精确计算与逻辑\u003c/strong\u003e：LLM 在处理复杂数学运算或精确代码执行时容易出错（幻觉）。调用 Python 解释器或计算器函数可以得到 100% 准确的结果。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e访问私有数据\u003c/strong\u003e：企业的数据在内部数据库中，模型无法直接读取。通过调用内部 API，模型可以查询订单状态或用户信息。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e控制输出格式\u003c/strong\u003e：让模型生成结构化的 JSON 数据，而不是长篇大论的文本，便于程序后续处理。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"3-工作流程示例\"\u003e3. 工作流程示例\u003c/h3\u003e\n\u003cp\u003e假设你正在开发一个\u003cstrong\u003e智能天气助手\u003c/strong\u003e：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e开发者定义函数\u003c/strong\u003e：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e函数名：\u003ccode\u003eget_current_weather\u003c/code\u003e\u003c/li\u003e\n\u003cli\u003e参数：\u003ccode\u003elocation\u003c/code\u003e (string), \u003ccode\u003eunit\u003c/code\u003e (string: \u0026ldquo;celsius\u0026rdquo; or \u0026ldquo;fahrenheit\u0026rdquo;)\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e用户提问\u003c/strong\u003e：\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e“上海现在的气温是多少？用摄氏度表示。”\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e模型推理与调用\u003c/strong\u003e：\n模型识别到需要查询天气，于是输出如下结构（JSON）：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-json\" data-lang=\"json\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026#34;name\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;get_current_weather\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"nt\"\u003e\u0026#34;arguments\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026#34;location\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;上海\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026#34;unit\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;celsius\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e  \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e\u003cstrong\u003e后端执行\u003c/strong\u003e：\n你的代码解析出 JSON，调用真实的天气 API，得到结果：\u003ccode\u003e{\u0026quot;temp\u0026quot;: 24, \u0026quot;status\u0026quot;: \u0026quot;sunny\u0026quot;}\u003c/code\u003e。\u003c/p\u003e","title":"Function Calling"},{"content":"一、什么是 RAG？ RAG 全称是 Retrieval-Augmented Generation（检索增强生成）。\n为了理解它，我们需要先了解大语言模型（LLM）的两大痛点：\n知识滞后性：大模型的训练数据截止于某个时间点，对于训练后发生的新闻、事件或企业内部数据，它一无所知。 “幻觉”问题：当面对未知领域的问题时，模型可能会自信地编造事实（Hallucination），导致输出内容看似通顺但内容错误。 RAG 的核心理念非常简单：不要让大模型去“背”所有知识，而是给它配一个“图书馆”。\n当用户提问时，RAG 系统不会直接让大模型生成答案，而是先执行两步操作：\n检索（Retrieval）：在外部知识库中搜索与问题最相关的信息。 生成（Generation）：将检索到的信息连同用户的问题一起交给大模型，让模型基于这些事实生成最终回答。 一句话总结：RAG = 大模型（生成能力） + 外部知识库（事实来源）。\n二、RAG 是如何工作的？（工作流 + 代码示例） RAG 的工作流程通常包含以下四个关键步骤。下面我们通过一个具体的场景，用伪代码和逻辑图解来展示它是如何运行的。\n🎯 场景设定 背景：一家科技公司的 AI 客服。 知识库（Vector DB）：包含《员工手册 2024 版》和《最新产品 Q3 发布说明书》。 用户提问：“我报销差旅费需要几个人审批？另外，Q3 发布的 AI 助手叫什么名字？” 问题难点： 审批人数在《员工手册》里，不在训练数据中。 产品名字是刚发布的，模型不知道。 🔧 步骤详解与代码逻辑 1. 数据准备与索引（Building the Library） 在系统上线前，我们需要将文档切片并转化为向量存入数据库。\n# 伪代码：建立知识库 documents = [ \u0026#34;《员工手册》：差旅费报销流程需经过直接主管和部门经理两级审批。\u0026#34;, \u0026#34;《Q3 发布说明书》：我们于 2023 年 10 月发布了名为 \u0026#39;Nebula AI\u0026#39; 的智能助手。\u0026#34;, \u0026#34;《Q3 发布说明书》：\u0026#39;Nebula AI\u0026#39; 支持自然语言处理和多模态交互。\u0026#34; ] # 将文本分块 (Chunking) chunks = split_text(documents) # 将文本转化为向量 (Embedding) 并存入向量数据库 (如 Pinecone, Milvus) for chunk in chunks: vector = embedding_model.encode(chunk) vector_db.upsert(id=chunk.id, vector=vector, metadata=chunk) 2. 用户提问（Query） 用户输入：\u0026quot;我报销差旅费需要几个人审批？另外，Q3 发布的 AI 助手叫什么名字？\u0026quot;\n3. 检索相关片段（Retrieval） 系统将用户的提问转化为向量，在向量数据库中进行相似度匹配。\nuser_query = \u0026#34;我报销差旅费需要几个人审批？另外，Q3 发布的 AI 助手叫什么名字？\u0026#34; user_vector = embedding_model.encode(user_query) # 从向量库中检索最相似的 Top-2 片段 # 1. 匹配到\u0026#34;员工手册\u0026#34;相关片段 # 2. 匹配到\u0026#34;Q3 发布说明书\u0026#34;相关片段 retrieved_chunks = vector_db.search(user_vector, top_k=2) # 结果示例： # chunk_1: \u0026#34;《员工手册》：差旅费报销流程需经过直接主管和部门经理两级审批。\u0026#34; # chunk_2: \u0026#34;《Q3 发布说明书》：我们于 2023 年 10 月发布了名为 \u0026#39;Nebula AI\u0026#39; 的智能助手。\u0026#34; 4. 增强与生成（Augmentation \u0026amp; Generation） 系统将检索到的片段和用户问题拼接，发送给大模型。\n# 构建 Prompt (提示词工程) prompt_template = \u0026#34;\u0026#34;\u0026#34; 请基于以下【检索到的信息】回答用户的问题。 如果信息中不包含答案，请明确说明无法回答。 【检索到的信息】： {retrieved_chunks} 【用户问题】： {user_query} 【回答】： \u0026#34;\u0026#34;\u0026#34; final_prompt = prompt_template.format( retrieved_chunks=\u0026#34;\\n\u0026#34;.join(retrieved_chunks), user_query=user_query ) # 调用大模型 (LLM) llm_response = llm.generate(final_prompt) ✅ 预期输出结果 系统最终生成的回答将是：\n“根据《员工手册》，您的差旅费报销需要经过两级审批（直接主管和部门经理）。关于 Q3 发布的产品，名称为 \u0026lsquo;Nebula AI\u0026rsquo;，它于 2023 年 10 月发布，支持自然语言处理和多模态交互。”\n对比： 如果没有 RAG，普通大模型可能会编造“需要三人审批”或者给出一个从未发布过的产品名。\n三、为什么 RAG 如此重要？ 在 RAG 出现之前，如果想让大模型知道私有数据，通常只能选择微调（Fine-tuning）。但微调存在成本高、周期长、难以更新知识的缺点。\nRAG 的优势在于：\n特性 传统微调 (Fine-tuning) RAG (检索增强生成) 知识时效性 训练后数据固化，更新需重新训练 实时更新，只要更新知识库即可 成本 高（需要算力资源训练模型） 低（无需训练模型，只需维护数据库） 可解释性 黑盒，难以追溯答案来源 高，可以追溯到具体的文档段落 数据隐私 敏感数据可能泄露到训练集中 数据保留在本地库，安全性更高 灵活性 修改错误答案难 灵活修改，只需删除或更新数据库中的文档 对于企业而言，RAG 是构建“企业级知识库”的首选方案。 它可以快速将公司内部数万个文档变成可对话的 AI 助手，且无需大模型重新学习这些内容。\n四、RAG 的局限与未来 当然，RAG 并非万能。它也有其挑战：\n检索质量决定上限：如果检索系统没能找到最相关的片段（即“检索失败”），大模型依然无法给出好答案（Garbage In, Garbage Out）。 上下文窗口限制：如果知识库过于庞大或检索到的内容太多，超过了模型的上下文窗口（Context Window），系统需要设计更复杂的压缩或摘要机制。 跨文档推理：如果答案需要综合多个分散的文档片段才能得出，RAG 的检索机制可能会遗漏关键信息。 未来的发展方向包括：\n多路检索：结合关键词搜索（BM25）、向量搜索和图数据库搜索。 Query 重写：在检索前，让模型先优化用户的提问，使其更适合搜索。 RAG 与 Agent 结合：让 AI 不仅能查资料，还能根据查到的资料自动执行复杂的任务（如查天气、查股价、调用 API）。 ","permalink":"http://fxio.site/posts/ai/rag/","summary":"\u003ch2 id=\"一什么是-rag\"\u003e一、什么是 RAG？\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003eRAG\u003c/strong\u003e 全称是 \u003cstrong\u003eRetrieval-Augmented Generation\u003c/strong\u003e（检索增强生成）。\u003c/p\u003e\n\u003cp\u003e为了理解它，我们需要先了解大语言模型（LLM）的两大痛点：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003e知识滞后性\u003c/strong\u003e：大模型的训练数据截止于某个时间点，对于训练后发生的新闻、事件或企业内部数据，它一无所知。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e“幻觉”问题\u003c/strong\u003e：当面对未知领域的问题时，模型可能会自信地编造事实（Hallucination），导致输出内容看似通顺但内容错误。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e\u003cstrong\u003eRAG 的核心理念非常简单：不要让大模型去“背”所有知识，而是给它配一个“图书馆”。\u003c/strong\u003e\u003c/p\u003e\n\u003cp\u003e当用户提问时，RAG 系统不会直接让大模型生成答案，而是先执行两步操作：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\u003cstrong\u003e检索（Retrieval）\u003c/strong\u003e：在外部知识库中搜索与问题最相关的信息。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e生成（Generation）\u003c/strong\u003e：将检索到的信息连同用户的问题一起交给大模型，让模型基于这些\u003cstrong\u003e事实\u003c/strong\u003e生成最终回答。\u003c/li\u003e\n\u003c/ol\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003e一句话总结\u003c/strong\u003e：RAG = 大模型（生成能力） + 外部知识库（事实来源）。\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003chr\u003e\n\u003ch2 id=\"二rag-是如何工作的工作流--代码示例\"\u003e二、RAG 是如何工作的？（工作流 + 代码示例）\u003c/h2\u003e\n\u003cp\u003eRAG 的工作流程通常包含以下四个关键步骤。下面我们通过一个\u003cstrong\u003e具体的场景\u003c/strong\u003e，用伪代码和逻辑图解来展示它是如何运行的。\u003c/p\u003e\n\u003ch3 id=\"-场景设定\"\u003e🎯 场景设定\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e背景\u003c/strong\u003e：一家科技公司的 AI 客服。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e知识库（Vector DB）\u003c/strong\u003e：包含《员工手册 2024 版》和《最新产品 Q3 发布说明书》。\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e用户提问\u003c/strong\u003e：“我报销差旅费需要几个人审批？另外，Q3 发布的 AI 助手叫什么名字？”\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e问题难点\u003c/strong\u003e：\n\u003cul\u003e\n\u003cli\u003e审批人数在《员工手册》里，不在训练数据中。\u003c/li\u003e\n\u003cli\u003e产品名字是刚发布的，模型不知道。\u003c/li\u003e\n\u003c/ul\u003e\n\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"-步骤详解与代码逻辑\"\u003e🔧 步骤详解与代码逻辑\u003c/h3\u003e\n\u003ch4 id=\"1-数据准备与索引building-the-library\"\u003e1. 数据准备与索引（Building the Library）\u003c/h4\u003e\n\u003cp\u003e在系统上线前，我们需要将文档切片并转化为向量存入数据库。\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 伪代码：建立知识库\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003edocuments\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s2\"\u003e\u0026#34;《员工手册》：差旅费报销流程需经过直接主管和部门经理两级审批。\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s2\"\u003e\u0026#34;《Q3 发布说明书》：我们于 2023 年 10 月发布了名为 \u0026#39;Nebula AI\u0026#39; 的智能助手。\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"s2\"\u003e\u0026#34;《Q3 发布说明书》：\u0026#39;Nebula AI\u0026#39; 支持自然语言处理和多模态交互。\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 将文本分块 (Chunking)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003echunks\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003esplit_text\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003edocuments\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 将文本转化为向量 (Embedding) 并存入向量数据库 (如 Pinecone, Milvus)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003efor\u003c/span\u003e \u003cspan class=\"n\"\u003echunk\u003c/span\u003e \u003cspan class=\"ow\"\u003ein\u003c/span\u003e \u003cspan class=\"n\"\u003echunks\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003evector\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"n\"\u003eembedding_model\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eencode\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003echunk\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"n\"\u003evector_db\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eupsert\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nb\"\u003eid\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003echunk\u003c/span\u003e\u003cspan class=\"o\"\u003e.\u003c/span\u003e\u003cspan class=\"n\"\u003eid\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003evector\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003evector\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"n\"\u003emetadata\u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"n\"\u003echunk\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch4 id=\"2-用户提问query\"\u003e2. 用户提问（Query）\u003c/h4\u003e\n\u003cp\u003e用户输入：\u0026quot;\u003cem\u003e我报销差旅费需要几个人审批？另外，Q3 发布的 AI 助手叫什么名字？\u003c/em\u003e\u0026quot;\u003c/p\u003e","title":"Rag"},{"content":"数据库选择 sqlite 小巧 无需安装 支持标准sql 语法 数据库客户端 DBeaver DBeaver (Community Edition) 支持 MySQL, PostgreSQL, SQLite等数据库 免费,开源 跨平台 DBeaver 下载安装 下载地址: https://dbeaver.io/download/ 创建示例数据库 下载jdbc驱动 打开sql脚本编辑器 DBeaver示例数据库-表介绍 DBeaver 默认自带的示例数据库 使用的是业界非常著名的 Chinook 数据库。 它模拟了一个 “数字音乐商店”（类似早期的 iTunes Store）的业务场景。 这个数据库结构非常经典，特别适合用来练习 SQL 的 JOIN（连接查询）、GROUP BY（分组统计） 以及理解主外键关系。 数据表 Album 音乐专辑表 Artist 艺术家/歌手 Customer 客户 Employee 员工 Genre 流派 Invoice 发票/订单头 InvoiceLine 发票明细/订单行 MediaType 媒体格式 Playlist 歌单 PlaylistTrack 歌单 sqlite_schema sqlite元数据 Track 歌曲/单曲 查看表关系 select 练习 1.select单表查询 select * from Track; 笔记:\n*是通配符, 意思是: 所有列 sql语句以;结尾 2.select查询指定字段 select Name, Composer from Track; 3.where(带条件的查询) -- TrackId=1的歌曲 select * from Track where TrackId = 1; --- Composer=AC/DC select * from Track where Composer = \u0026#39;AC/DC\u0026#39;; -- 找出时长 (Milliseconds) 超过 5 分钟（300,000 毫秒）的歌 select * from Track WHERE Milliseconds \u0026gt; 300000; 4.where-and-or带条件的查询2 -- 时长超过5分钟并且作曲家是 \u0026#39;AC/DC\u0026#39; 的所有歌 select * from Track WHERE Milliseconds \u0026gt; 300000 and Composer = \u0026#39;AC/DC\u0026#39;; -- 曲家是 U2 或者 AC/DC select * from Track WHERE Composer=\u0026#39;U2\u0026#39; or Composer = \u0026#39;AC/DC\u0026#39;; 5.order by 排序 -- 按文件大小 (Bytes) 从大到小排序(desc: 降序, asc: 长序) select * from Track order by Bytes desc; 6.聚合函数 -- 歌曲总数 select count(*) as 总数 from Track; -- 单价格最贵的歌曲 select max(UnitPrice) as 最贵单价 from Track; -- 平均时长 select AVG(Milliseconds) as 平均时长 from Track; select count(*) as 总数, max(UnitPrice) as 最贵单价, avg(Milliseconds) as 平均时长 from Track; as 是给字段取个别名, 避免显示为表达式\n7.join连接查询 问题: 我想看每首歌的歌名，以及它属于哪张专辑的标题。 问题来了：\n歌名在 Track 表里。 专辑标题在 Album 表里。 它们是分开的 SELECT Track.Name AS 歌名, Album.Title AS 专辑名 FROM Track INNER JOIN Album ON Track.AlbumId = Album.AlbumId; sql解释：\n从 Track 表开始。 内连接 (INNER JOIN) 上 Album 表。 连接条件 (ON) 是：Track 的身份证号 = Album 的身份证号。 8.group by分组统计 -- 每个作曲家 (Composer) 各有多少首歌 SELECT Composer, COUNT(*) AS 歌曲数量 FROM Track GROUP BY Composer; -- 排序与筛选 (谁是创作狂人？) SELECT Composer, COUNT(*) AS 歌曲数量 FROM Track WHERE Composer IS NOT NULL GROUP BY Composer ORDER BY 歌曲数量 DESC; 9.having子句 注意: WHERE 和 HAVING 的区别\nWHERE：是在分组之前干活。它过滤的是原始数据 HAVING：是在分组之后干活。它过滤的是统计结果 -- 作品数量超过 10 首的专辑 (AlbumId) SELECT AlbumId, COUNT(*) AS 歌曲数 FROM Track GROUP BY AlbumId HAVING COUNT(*) \u0026gt; 10 ORDER BY 歌曲数 DESC; ","permalink":"http://fxio.site/posts/sql/dbeaver-sql/","summary":"\u003ch2 id=\"数据库选择\"\u003e数据库选择\u003c/h2\u003e\n\u003ch3 id=\"sqlite\"\u003esqlite\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e小巧\u003c/li\u003e\n\u003cli\u003e无需安装\u003c/li\u003e\n\u003cli\u003e支持标准sql 语法\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"数据库客户端\"\u003e数据库客户端\u003c/h2\u003e\n\u003ch3 id=\"dbeaver\"\u003eDBeaver\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eDBeaver (Community Edition)\u003c/li\u003e\n\u003cli\u003e支持 MySQL, PostgreSQL, SQLite等数据库\u003c/li\u003e\n\u003cli\u003e免费,开源\u003c/li\u003e\n\u003cli\u003e跨平台\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"dbeaver-下载安装\"\u003eDBeaver 下载安装\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e下载地址: \u003ca href=\"https://dbeaver.io/download/\"\u003ehttps://dbeaver.io/download/\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e创建示例数据库\u003c/li\u003e\n\u003cli\u003e\u003cimg alt=\"img.png\" loading=\"lazy\" src=\"/posts/sql/dbeaver-sql/img.png\"\u003e\u003c/li\u003e\n\u003cli\u003e下载jdbc驱动\u003c/li\u003e\n\u003cli\u003e\u003cimg alt=\"img_1.png\" loading=\"lazy\" src=\"/posts/sql/dbeaver-sql/img_1.png\"\u003e\u003c/li\u003e\n\u003cli\u003e打开sql脚本编辑器\u003c/li\u003e\n\u003cli\u003e\u003cimg alt=\"img_2.png\" loading=\"lazy\" src=\"/posts/sql/dbeaver-sql/img_2.png\"\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"dbeaver示例数据库-表介绍\"\u003eDBeaver示例数据库-表介绍\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eDBeaver 默认自带的示例数据库\u003c/li\u003e\n\u003cli\u003e使用的是业界非常著名的 Chinook 数据库。\u003c/li\u003e\n\u003cli\u003e它模拟了一个 “数字音乐商店”（类似早期的 iTunes Store）的业务场景。\u003c/li\u003e\n\u003cli\u003e这个数据库结构非常经典，特别适合用来练习 SQL 的 JOIN（连接查询）、GROUP BY（分组统计）\u003c/li\u003e\n\u003cli\u003e以及理解主外键关系。\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"数据表\"\u003e数据表\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003eAlbum 音乐专辑表\u003c/li\u003e\n\u003cli\u003eArtist 艺术家/歌手\u003c/li\u003e\n\u003cli\u003eCustomer 客户\u003c/li\u003e\n\u003cli\u003eEmployee 员工\u003c/li\u003e\n\u003cli\u003eGenre 流派\u003c/li\u003e\n\u003cli\u003eInvoice 发票/订单头\u003c/li\u003e\n\u003cli\u003eInvoiceLine 发票明细/订单行\u003c/li\u003e\n\u003cli\u003eMediaType 媒体格式\u003c/li\u003e\n\u003cli\u003ePlaylist  歌单\u003c/li\u003e\n\u003cli\u003ePlaylistTrack 歌单\u003c/li\u003e\n\u003cli\u003esqlite_schema sqlite元数据\u003c/li\u003e\n\u003cli\u003eTrack 歌曲/单曲\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"查看表关系\"\u003e查看表关系\u003c/h3\u003e\n\u003cp\u003e\u003cimg alt=\"img_3.png\" loading=\"lazy\" src=\"/posts/sql/dbeaver-sql/img_3.png\"\u003e\u003c/p\u003e\n\u003ch2 id=\"select-练习\"\u003eselect 练习\u003c/h2\u003e\n\u003ch3 id=\"1select单表查询\"\u003e1.select单表查询\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-sql\" data-lang=\"sql\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"k\"\u003eselect\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e*\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003efrom\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTrack\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e笔记:\u003c/p\u003e","title":"数据库客户端-DBeaver安装与使用"},{"content":"引言 在开发者的潜意识里，LIMIT 关键字就是 SQL 查询的安全带。 我们通常认为，只要加了 LIMIT，无论表多大，数据库都只会吐出少量数据，内存就是安全的。\n然而，最近的一次线上 OOM（内存溢出）事故狠狠地打破了这个认知。 一个看似人畜无害的 UNION ALL + LIMIT 组合，竟然避开了doris 的优化器的下推机制，引发了生产环境的连锁崩溃。\n本文记录了这次在受限环境下，如何抽丝剥茧定位 Bug 的过程。\n一、高峰期的“幽灵”崩溃 环境背景：\n部署方式 Kubernetes 网关： Springboot + zuul 服务： Spring Boot + MyBatis db： Apache Doris 报错服务： 网关 java版本： jdk8, g1 权限： 无root权限,只能查看基本日志 网关pod报错关键日志\nnetflix.zuul.exception.ZuulException: Filter threw Exception postModifyResponseBodyFilter.run ... Caused by: java.lang.OutOfMemoryError: Java heap space 报错日志关键字: oom\n二、 真相误判：GC 的烟雾弹 面对 OOM，作为 Java 开发者的第一直觉往往是：“是不是流量太大，垃圾回收（GC）跟不上了？” 查看存活期间的 JVM 监控，发现 Old Gen（老年代）增长迅速。当时的判断是：CMS 回收器产生内存碎片，导致大对象分配失败。\n行动： 将 JVM 参数从 CMS 升级为 G1。 结果： 情况确实“有所改善”，Pod 存活时间变长了，报警频率降低了。 反思（陷阱）： 这其实是 G1 带来的假象。G1 对堆内存的管理确实更优秀，它延缓了崩溃，但并没有解决根本问题。 真相： 这不是“垃圾回收”的问题，而是“垃圾产生”的问题。Doris 返回了海量数据（Live Objects），Java 正在处理这些数据，它们* 在 JVM 眼里是**“必须存活的对象”**。无论 GC 多么努力，它都无权回收正在被使用的业务数据。 比喻： 浴缸的水龙头（数据源）全开，排水口（GC）再大，只要进水速度 \u0026gt; 排水速度，水漫金山是迟早的事。 三、 陷入僵局：gc优化后oom再次出现 GC 调优失败后，问题回到了原点。此时不仅面临技术难题，更面临流程壁垒：\n无法 Debug： 线上不能挂断点。 无法使用arthas： 有限的权限 关键线索（已脱敏） oom出现时, 总是伴随着如下类似的SQL语句：\nSELECT col1, col2 FROM table_A WHERE ... UNION ALL SELECT col1, col2 FROM table_B WHERE ... LIMIT 100; 推理验证 如下sql, 应该返回7条数据才对\nSELECT col1, col2 FROM table_A WHERE col1=‘单独执行,返回5条数据的条件’ UNION ALL SELECT col1, col2 FROM table_B WHERE col1=‘单独执行,返回6条数据的条件’ LIMIT 7; 但是在当时的doris版本返回了11条数据，而不是7条数据。 limit竟然没有对整个SQL进行limit\n四、 原因分析：Doris 的解析 Bug 这是一个典型的 “水坝效应”。\nDoris (源头)： 由于 LIMIT 解析 Bug，返回了 11 条（甚至更多, t1 的全量扫描数据）非预期的全量扫描数据，数据量极大。 App Service (管道)： 业务服务采用流式输出，数据穿肠而过，内存占用尚在可控范围。 Zuul Gateway (大坝)： 网关开启了 postModifyResponseBodyFilter（响应体修改过滤器）。为了修改响应内容，Zuul 被迫将 App 传来的所有数据流截断并完整加载到内存中。 当 Doris 误传回的海量数据（也许几百 MB）遇到网关的高并发（几十个请求并发），28GB 的堆内存瞬间被数十个巨型 Response Body 填满。网关本想做个中间人，却因为试图缓存“洪水”而被冲垮。 强制让doris-sql最终的limit生效 select * from( SELECT col1, col2 FROM table_A WHERE col1=‘单独执行,返回5条数据的条件’ UNION ALL SELECT col1, col2 FROM table_B WHERE col1=‘单独执行,返回6条数据的条件’ )t1 LIMIT 7; 原因分析-网关 为什么挂的是网关？\n这是一个典型的**“水坝效应”**。\nDoris (源头)： 由于 LIMIT 解析 Bug，返回了 11 条（甚至更多）非预期的全量扫描数据，数据量极大。 App Service (管道)： 业务服务采用流式输出，数据穿肠而过，内存占用尚在可控范围。 Zuul Gateway (大坝)： 网关开启了 postModifyResponseBodyFilter（响应体修改过滤器）。为了修改响应内容，Zuul 被迫将 App 传来的所有数据流截断并完整加载到内存中。 当 Doris 误传回的海量数据（也许几百 MB）遇到网关的高并发（几十个请求并发），28GB 的堆内存瞬间被数十个巨型 Response Body 填满。网关本想做个中间人，却因为试图缓存“洪水”而被冲垮。 完整的故障链路：\nDoris 误判，对 Table A 进行全表扫描，吐出数百万行数据。 App 服务无罪透传。 Zuul 网关 为了做 JSON 包装，被迫将这几百 MB 数据加载到 RAM。 五、 总结与启示 架构层面的启示：\n网关的脆弱性： 网关作为所有流量的入口，最忌讳处理“大报文”。在网关层做 ResponseBody 的修改（如统一包装、日志记录）是非常危险的操作，它会把“流”变成“块”，引入巨大的内存风险。\n全链路防御： 仅仅在 App 层做防护是不够的。如果数据库失控，必须确保这种压力不会沿着链路传导并击穿最脆弱的环节（网关）。\n这次排查最宝贵的经验不是修复了 SQL，而是在极端受限环境下的排查思路：\n深度思考 警惕“代码没变”的幻觉： 代码没变，但数据环境变了（数据量增长），依赖组件变了（Doris 版本差异），这就是最大的变量。 网关是脆弱的水坝： 在微服务架构中，网关是所有流量的汇聚点。在网关层做“修改 Body”这种重内存操作（Buffer）是极高风险的架构反模式。 防御性编程： 不要信任数据库优化器。在分布式系统中，显式地把 LIMIT 写在每一个子查询里，是保护系统的最后一道防线。 ","permalink":"http://fxio.site/posts/java/doris-zuul-oom/","summary":"\u003ch2 id=\"引言\"\u003e引言\u003c/h2\u003e\n\u003cp\u003e在开发者的潜意识里，\u003ccode\u003eLIMIT\u003c/code\u003e 关键字就是 SQL 查询的安全带。\n我们通常认为，只要加了 \u003ccode\u003eLIMIT\u003c/code\u003e，无论表多大，数据库都只会吐出少量数据，内存就是安全的。\u003c/p\u003e\n\u003cp\u003e然而，最近的一次线上 OOM（内存溢出）事故狠狠地打破了这个认知。\n一个看似人畜无害的 \u003ccode\u003eUNION ALL\u003c/code\u003e + \u003ccode\u003eLIMIT\u003c/code\u003e 组合，竟然避开了doris 的优化器的下推机制，引发了生产环境的连锁崩溃。\u003c/p\u003e\n\u003cp\u003e本文记录了这次在受限环境下，如何抽丝剥茧定位 Bug 的过程。\u003c/p\u003e\n\u003ch2 id=\"一高峰期的幽灵崩溃\"\u003e一、高峰期的“幽灵”崩溃\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e环境背景：\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e部署方式\u003c/strong\u003e Kubernetes\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e网关：\u003c/strong\u003e Springboot + zuul\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e服务：\u003c/strong\u003e Spring Boot + MyBatis\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003edb：\u003c/strong\u003e Apache Doris\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e报错服务：\u003c/strong\u003e 网关\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ejava版本：\u003c/strong\u003e jdk8, g1\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e权限：\u003c/strong\u003e 无root权限,只能查看基本日志\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003cstrong\u003e网关pod报错关键日志\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003enetflix\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003ezuul\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eexception\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eZuulException\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eFilter\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ethrew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eException\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003epostModifyResponseBodyFilter\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003erun\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e...\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"n\"\u003eCaused\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eby\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ejava\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003elang\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eOutOfMemoryError\u003c/span\u003e\u003cspan class=\"p\"\u003e:\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eJava\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eheap\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003espace\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e报错日志关键字: oom\u003c/p\u003e\n\u003ch2 id=\"二-真相误判gc-的烟雾弹\"\u003e二、 真相误判：GC 的烟雾弹\u003c/h2\u003e\n\u003cp\u003e面对 OOM，作为 Java 开发者的第一直觉往往是：“是不是流量太大，垃圾回收（GC）跟不上了？”\n查看存活期间的 JVM 监控，发现 Old Gen（老年代）增长迅速。当时的判断是：CMS 回收器产生内存碎片，导致大对象分配失败。\u003c/p\u003e","title":"Doris-\u003eZuul Oom"},{"content":"准备 客户端，服务端都安装 hugo 服务端, 创建一个空的git仓库 # 更新系统 sudo apt update \u0026amp;\u0026amp; sudo apt upgrade -y # 安装 Git 和 Nginx (Web 服务器) sudo apt install git nginx -y # 安装 Hugo # 建议直接安装 extended 版本以支持更多主题，Ubuntu 24 的仓库版本通常较新 sudo apt install hugo -y mkdir blog.git cd blog.git git init --bare 客户端创建一个博客项目 hugo new site blog 添加主题 https://themes.gohugo.io/ 选择一个主题， 放在theme目录 更新: hugo.toml 例如： theme = \u0026ldquo;PaperMod\u0026rdquo;\n删除theme里面的.git避免子目录问题\n配置远程push权限 编辑 ~/.ssh/config Host myblog.com HostName 192.168.1.100 User root IdentityFile ~/.ssh/user.pem IdentitiesOnly yes 添加remote url git remote add deploy myblog.com:/srv/myblog/blog.git hooks自动部署 vim hooks/post-receive\n#!/bin/bash # 路径定义 TMP_DIR=/srv/www/blog-fxio/tmp GIT_DIR=/srv/www/blog-fxio/blog.git PUBLIC_DIR=/srv/www/blog-fxio/blog-html # 1. 强制同步源码目录 echo \u0026#34;--- 正在更新源码 ---\u0026#34; cd $TMP_DIR git --git-dir=$GIT_DIR --work-tree=. checkout -f fxio.site # 2. 运行 Hugo 构建 echo \u0026#34;--- 正在构建 HTML ---\u0026#34; cd $TMP_DIR # 升级后的 Hugo 路径确认 hugo --destination $PUBLIC_DIR --gc --minify # 3. 权限修正 chown -R www-data:www-data $PUBLIC_DIR echo \u0026#34;--- 部署成功! ---\u0026#34; https sudo apt install python3-certbot-nginx -y sudo certbot --nginx -d fxio.site ","permalink":"http://fxio.site/posts/note/hugo-init/","summary":"\u003ch2 id=\"准备\"\u003e准备\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e客户端，服务端都安装 hugo\u003c/li\u003e\n\u003cli\u003e服务端, 创建一个空的git仓库\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 更新系统\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt update \u003cspan class=\"o\"\u003e\u0026amp;\u0026amp;\u003c/span\u003e sudo apt upgrade -y\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 安装 Git 和 Nginx (Web 服务器)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt install git nginx -y\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 安装 Hugo\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 建议直接安装 extended 版本以支持更多主题，Ubuntu 24 的仓库版本通常较新\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt install hugo -y\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003emkdir blog.git\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003ecd\u003c/span\u003e blog.git\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egit init --bare\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"3\"\u003e\n\u003cli\u003e客户端创建一个博客项目\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ehugo new site blog\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"4\"\u003e\n\u003cli\u003e\n\u003cp\u003e添加主题\n\u003ca href=\"https://themes.gohugo.io/\"\u003ehttps://themes.gohugo.io/\u003c/a\u003e\n选择一个主题， 放在theme目录\n更新: hugo.toml\n例如： theme = \u0026ldquo;PaperMod\u0026rdquo;\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003e删除theme里面的.git避免子目录问题\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"配置远程push权限\"\u003e配置远程push权限\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e编辑 ~/.ssh/config\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eHost myblog.com\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    HostName 192.168.1.100\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    User root\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    IdentityFile  ~/.ssh/user.pem\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    IdentitiesOnly yes\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"2\"\u003e\n\u003cli\u003e添加remote url\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003egit remote add deploy myblog.com:/srv/myblog/blog.git\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"hooks自动部署\"\u003ehooks自动部署\u003c/h2\u003e\n\u003cp\u003evim hooks/post-receive\u003c/p\u003e","title":"Hugo Blog Deploy"},{"content":"m2硬盘安装ubuntu出现I/O错误: DMAR fault的排查记录（含解决方案） 在旧台式机安装Ubuntu24.04 的过程中，我遇到一个非常棘手的问题：\n第一次安装失败; 安装过程中, 提示io错误 关机后, 再次安装, 安装成功 进入系统后, 硬盘灯持续规律闪烁, 频繁出现 I/O 错误、系统卡顿、硬盘灯间隔性闪烁、并伴随 DMAR/IOMMU 报错 最开始遇到这个问题, 我以为是硬盘问题, 更换为 sata硬盘后, 问题消失。似乎从某种程序上证明是此硬盘问题; 随后此”坏硬盘“, 就安静的放在角落; 今天整理物品, 发现这块硬盘, 突然想到, 让ai帮忙分析分析硬盘是什么原因导致的故障, 以后如何避免买到类似的硬盘;\n这篇文章记录整个排查过程，希望给未来遇到类似问题的人提供一个可参考的解决思路。\n1. 硬件与环境背景 主板：Gigabyte Z97X-UD3H（2014年） CPU：Intel i7-4790K（Haswell） NVMe：YMTC PC300 512GB（支持 HMB，NVMe1.4） 系统：Ubuntu 24.04 NVMe 安装在主析的m2硬盘槽位 这是典型的“老主板 + 新 NVMe 控制器”的组合，在 Linux 下非常容易触发兼容性问题。\n2. 问题现象 （1）安装 Ubuntu 时随机 I/O 错误 系统安装过程中文件复制中断 安装流程偶尔直接失败 重试偶尔能安装成功 （2）安装成功后,进入系统, 硬盘灯持续规律闪烁 开机后系统明显不顺畅。 复制文件时，会出现卡顿, 此时硬盘灯一直有规律的闪烁; （3）复制大文件（如 ubuntu.iso 6GB）出现卡顿 传输速度会突然降到零，直到系统无响应。 （4）dmesg 出现 DMAR/IOMMU 报错 DMAR: DRHD: handling fault status reg 2 DMAR: [DMA Write] Request device [01:00.0] fault addr ... DMAR: write no_pasid (5) 硬盘smart 检测无异常 使用 smartctl 读取 NVMe 健康状态： smartctl -x /dev/nvme0\nSMART overall-health self-assessment: PASSED Media and Data Integrity Errors: 0 Temperature: 27~31C 这一步至关重要：\n硬盘smart信息说明: NVMe 并没有坏。 但是硬盘灯闪烁，似乎是硬盘无法写入, 有故障;\n4. 排查思路与定位过程 (1) 没加散热器, 高温导致硬盘进入防御模式 购买并中装置散热器，问题依然存在.\n(2) 进入命令行模式, 复制文件, 发现报错 (3) dmsg 中查看 DMAR 错误 从 DMAR 错误入手 → 怀疑 IOMMU（VT-d）\nGoogle 搜索关键字：\nDMAR write no_pasid\nDevice fault VT-d NVMe\nZ97 NVMe IOMMU issue\n大量报告显示： Z97/H97/B85/X99 等老主板的 IOMMU 对新 NVMe 控制器支持极差。\n特别是支持 HMB 的 NVMe，会频繁触发 DMA remapping 错误。\n尝试关闭 IOMMU（最终突破） sudo nano /etc/default/grub GRUB_CMDLINE_LINUX=\u0026#34;intel_iommu=off\u0026#34; sudo update-grub 重启后\ndmesg | grep -i dmar DMAR: IOMMU disabled 随后系统立刻恢复流畅，所有异常消失。\n总结: 软件/兼容性问题，而不是硬盘故障 YMTC PC300 属于新 NVMe 控制器（支持 NVMe1.4 + HMB）， 而 Gigabyte Z97 主板发布于 2014 年，BIOS 对新型 DMA 功能支持不完整。\n当 Linux 使用 Intel IOMMU 进行 DMA 页表（I/O Page Table）映射时，会触发：\nPASID 错误\nIOMMU Translation Fault\nNVMe DMA 超时\n关闭 IOMMU 后，NVMe 直接使用传统 DMA → 完全恢复正常。\n结语 这次排查耗费了近五天时间，从怀疑硬盘损坏、到怀疑 BIOS、文件系统、驱动，再到最终定位到 IOMMU 与 NVMe 控制器的不兼容。\n最终的解决方法却只是一行：\nintel_iommu=off 参考链接 ","permalink":"http://fxio.site/posts/linux/ubuntu-nvme-post/","summary":"\u003ch1 id=\"m2硬盘安装ubuntu出现io错误-dmar-fault的排查记录含解决方案\"\u003em2硬盘安装ubuntu出现I/O错误: DMAR fault的排查记录（含解决方案）\u003c/h1\u003e\n\u003cp\u003e在旧台式机安装Ubuntu24.04 的过程中，我遇到一个非常棘手的问题：\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e第一次安装失败; 安装过程中, 提示io错误\u003c/li\u003e\n\u003cli\u003e关机后, 再次安装, 安装成功\u003c/li\u003e\n\u003cli\u003e进入系统后, 硬盘灯持续规律闪烁, 频繁出现 I/O 错误、系统卡顿、硬盘灯间隔性闪烁、并伴随 DMAR/IOMMU 报错\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003e最开始遇到这个问题, 我以为是硬盘问题, 更换为 sata硬盘后, 问题消失。似乎从某种程序上证明是此硬盘问题;\n随后此”坏硬盘“, 就安静的放在角落;\n今天整理物品, 发现这块硬盘, 突然想到, 让ai帮忙分析分析硬盘是什么原因导致的故障, 以后如何避免买到类似的硬盘;\u003c/p\u003e\n\u003cp\u003e这篇文章记录整个排查过程，希望给未来遇到类似问题的人提供一个可参考的解决思路。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"1-硬件与环境背景\"\u003e1. 硬件与环境背景\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e主板：Gigabyte Z97X-UD3H（2014年）\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eCPU：Intel i7-4790K（Haswell）\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eNVMe：YMTC PC300 512GB（支持 HMB，NVMe1.4）\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e系统：Ubuntu 24.04\u003c/strong\u003e\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eNVMe 安装在主析的m2硬盘槽位\u003c/strong\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e这是典型的“老主板 + 新 NVMe 控制器”的组合，在 Linux 下非常容易触发兼容性问题。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"2-问题现象\"\u003e2. 问题现象\u003c/h2\u003e\n\u003ch3 id=\"1安装-ubuntu-时随机-io-错误\"\u003e（1）安装 Ubuntu 时随机 I/O 错误\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e系统安装过程中文件复制中断\u003c/li\u003e\n\u003cli\u003e安装流程偶尔直接失败\u003c/li\u003e\n\u003cli\u003e重试偶尔能安装成功\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"2安装成功后进入系统-硬盘灯持续规律闪烁\"\u003e（2）安装成功后,进入系统, 硬盘灯持续规律闪烁\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e开机后系统明显不顺畅。\u003c/li\u003e\n\u003cli\u003e复制文件时，会出现卡顿, 此时硬盘灯一直有规律的闪烁;\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"3复制大文件如-ubuntuiso-6gb出现卡顿\"\u003e（3）复制大文件（如 ubuntu.iso 6GB）出现卡顿\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e传输速度会突然降到零，直到系统无响应。\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch3 id=\"4dmesg-出现-dmariommu-报错\"\u003e（4）dmesg 出现 DMAR/IOMMU 报错\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eDMAR: DRHD: handling fault status reg \u003cspan class=\"m\"\u003e2\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eDMAR: \u003cspan class=\"o\"\u003e[\u003c/span\u003eDMA Write\u003cspan class=\"o\"\u003e]\u003c/span\u003e Request device \u003cspan class=\"o\"\u003e[\u003c/span\u003e01:00.0\u003cspan class=\"o\"\u003e]\u003c/span\u003e fault addr ...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eDMAR: write no_pasid\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"5-硬盘smart-检测无异常\"\u003e(5) 硬盘smart 检测无异常\u003c/h3\u003e\n\u003cp\u003e使用 smartctl 读取 NVMe 健康状态：\nsmartctl -x /dev/nvme0\u003c/p\u003e","title":"旧主板-新Nvme-IO问题"},{"content":"debug调试问题是经常用到的， 在调试状态有时候需要复制list对象的某个属性值，一个个复制是不现实的 这个时候Idea调试状态的 Evaluate Expression 工具就派上大用场了\n在Expression输入框，根据自己的需求，转换后，转换为json格式，然后右键复制即可\n","permalink":"http://fxio.site/posts/tools/2023-02-04-idea-evaluate/","summary":"\u003cp\u003edebug调试问题是经常用到的， 在调试状态有时候需要复制list对象的某个属性值，一个个复制是不现实的\n这个时候Idea调试状态的 Evaluate Expression 工具就派上大用场了\u003c/p\u003e\n\u003cp\u003e在Expression输入框，根据自己的需求，转换后，转换为json格式，然后右键复制即可\u003c/p\u003e\n\u003cp\u003e\u003cimg loading=\"lazy\" src=\"/images/note/idea_evaluate.png\"\u003e\u003c/p\u003e","title":"Idea调试状态复制对象列表数据"},{"content":"简介 2021.1出版 作者： 日本-成毛真， 原Microsoft-日本社长， 从微软离职后，创立了一家投资顾问公司， 专为上市企业做投资顾问工作；兼任微软的社外顾问；日本Suruga银行的社外董事；日本早稻田大学商学院客员教授\n提问 为什么是2040？ 短时间预测比长时间预测难， 长期的趋势比较明显 回顾历史 新事物出现的时候， 人们普通抵抗 视频平台， 抖音， 直播带货 新事物出现的时候， 人们普通抵抗 100多年前， 照相机刚刚出来的时候， 人们很抵触 iphone刚刚出现的时候， 人们害怕自己的指纹补记录 电脑刚刚出现的时候，人们也没想到人手一台 100年前的汽车与现在的汽车（新技术的改良与组合） 科技发展， 社会发展\n通讯技术 3G: 传输照片 目前处于4-5G时代， 在线看直播， 视频电话， 视频会议 6G：远程手术，汽车自动驾驶， 同声传译 无人机定点送货 飞行汽车 物联网iot， 衣服， 冰箱， 镜子， 牙刷，餐具联网 媒体 电视和报纸将会覆灭， 拿手表看时间的变少， 网络媒体崛起 VR眼镜将会越来越轻， 越来越方便\n医疗 AI医疗， 整合全国全世界的病例， 误诊率下降 根据dna，定制mRNA疫苗 人体组织的培养 老年痴呆药物\n风险 自然灾害增加：地震 战争增加：粮食和水 人口减少： 人口出生率持续降低 -\u0026gt; 劳动力减少 人口老龄化严重: 从三四线城市开始体现 消费税增加\n","permalink":"http://fxio.site/posts/note/2023-02-04-2040%E6%9C%AA%E6%9D%A5%E8%B6%8B%E5%8A%BF/","summary":"\u003ch2 id=\"简介\"\u003e简介\u003c/h2\u003e\n\u003cp\u003e2021.1出版\n作者： 日本-成毛真， 原Microsoft-日本社长， 从微软离职后，创立了一家投资顾问公司， 专为上市企业做投资顾问工作；兼任微软的社外顾问；日本Suruga银行的社外董事；日本早稻田大学商学院客员教授\u003c/p\u003e\n\u003ch2 id=\"提问\"\u003e提问\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e为什么是2040？\n短时间预测比长时间预测难， 长期的趋势比较明显\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"回顾历史\"\u003e回顾历史\u003c/h2\u003e\n\u003cp\u003e新事物出现的时候， 人们普通抵抗\n视频平台， 抖音， 直播带货\n新事物出现的时候， 人们普通抵抗\n100多年前， 照相机刚刚出来的时候， 人们很抵触\niphone刚刚出现的时候， 人们害怕自己的指纹补记录\n电脑刚刚出现的时候，人们也没想到人手一台\n100年前的汽车与现在的汽车（新技术的改良与组合）\n科技发展， 社会发展\u003c/p\u003e\n\u003ch2 id=\"通讯技术\"\u003e通讯技术\u003c/h2\u003e\n\u003cp\u003e3G: 传输照片\n目前处于4-5G时代， 在线看直播， 视频电话， 视频会议\n6G：远程手术，汽车自动驾驶， 同声传译\n无人机定点送货\n飞行汽车\n物联网iot， 衣服， 冰箱， 镜子， 牙刷，餐具联网\n媒体\n电视和报纸将会覆灭， 拿手表看时间的变少， 网络媒体崛起\nVR眼镜将会越来越轻， 越来越方便\u003c/p\u003e\n\u003ch2 id=\"医疗\"\u003e医疗\u003c/h2\u003e\n\u003cp\u003eAI医疗， 整合全国全世界的病例， 误诊率下降\n根据dna，定制mRNA疫苗\n人体组织的培养\n老年痴呆药物\u003c/p\u003e\n\u003ch2 id=\"风险\"\u003e风险\u003c/h2\u003e\n\u003cp\u003e自然灾害增加：地震\n战争增加：粮食和水\n人口减少： 人口出生率持续降低  -\u0026gt;  劳动力减少\n人口老龄化严重: 从三四线城市开始体现\n消费税增加\u003c/p\u003e","title":"2040未来趋势"},{"content":"昵称: JoshKryo\n坐标: 深圳\n此博客作为个人技术学习的输出平台，记录学习总结，优秀项目和工具推荐，或许还有一些人生感悟。\n不是每个人都应该像我这样去建造一座水晶大教堂，但是每个人都应该拥有自己的梦想，设计自己的梦想，追求自己的梦想，实现自己的梦想。梦想是生命的灵魂，是心灵的灯塔，是引导人走向成功的信仰。有了崇高的梦想，只要矢志不渝地追求，梦想就会成为现实，奋斗就会变成壮举，生命就会创造奇迹。 ——罗伯·舒乐\n涉猎 后端：Java，Golang 数据库：Mysql，Presto 交流 Email: joshkryo@gmail.com\n","permalink":"http://fxio.site/about/","summary":"\u003cp\u003e昵称: JoshKryo\u003c/p\u003e\n\u003cp\u003e坐标: 深圳\u003c/p\u003e\n\u003cp\u003e此博客作为个人技术学习的输出平台，记录学习总结，优秀项目和工具推荐，或许还有一些人生感悟。\u003c/p\u003e\n\u003cp\u003e不是每个人都应该像我这样去建造一座水晶大教堂，但是每个人都应该拥有自己的梦想，设计自己的梦想，追求自己的梦想，实现自己的梦想。梦想是生命的灵魂，是心灵的灯塔，是引导人走向成功的信仰。有了崇高的梦想，只要矢志不渝地追求，梦想就会成为现实，奋斗就会变成壮举，生命就会创造奇迹。 ——罗伯·舒乐\u003c/p\u003e\n\u003ch2 id=\"涉猎\"\u003e涉猎\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e后端：Java，Golang\u003c/li\u003e\n\u003cli\u003e数据库：Mysql，Presto\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"交流\"\u003e交流\u003c/h2\u003e\n\u003cp\u003eEmail: \u003ca href=\"mailto:joshkryo@gmail.com\"\u003ejoshkryo@gmail.com\u003c/a\u003e\u003c/p\u003e","title":"关于我"},{"content":"Spring-动态替换Bean\n问题 假如spring-boot项目引用了第三方库， 里面有个类通过autowire引用了：testService， 如何修改testService里面的实现逻辑呢？ 通过动态替换testService为自定义的bean可以实现这个功能\n实现原理 添加一个新的TestService2与原testService实现同样的接口 添加一个组件实现： BeanDefinitionRegistryPostProcessor 使用BeanDefinitionRegistry动态替换bean 代码示例 @Component public class MyBeanProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { final String beanName = \u0026#34;testService\u0026#34;; if (registry.containsBeanDefinition(beanName)) { registry.removeBeanDefinition(beanName); GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(TestService2.class); registry.registerBeanDefinition(beanName, beanDefinition); } } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException { } } ","permalink":"http://fxio.site/posts/java/spring-%E5%8A%A8%E6%80%81%E6%9B%BF%E6%8D%A2bean/","summary":"\u003cp\u003eSpring-动态替换Bean\u003c/p\u003e\n\u003ch2 id=\"问题\"\u003e问题\u003c/h2\u003e\n\u003cp\u003e假如spring-boot项目引用了第三方库， 里面有个类通过autowire引用了：testService， 如何修改testService里面的实现逻辑呢？\n通过动态替换testService为自定义的bean可以实现这个功能\u003c/p\u003e\n\u003ch2 id=\"实现原理\"\u003e实现原理\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003e添加一个新的TestService2与原testService实现同样的接口\u003c/li\u003e\n\u003cli\u003e添加一个组件实现： BeanDefinitionRegistryPostProcessor\u003c/li\u003e\n\u003cli\u003e使用BeanDefinitionRegistry动态替换bean\u003c/li\u003e\n\u003c/ol\u003e\n\u003ch2 id=\"代码示例\"\u003e代码示例\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nd\"\u003e@Component\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eMyBeanProcessor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eimplements\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBeanDefinitionRegistryPostProcessor\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nd\"\u003e@Override\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003epostProcessBeanDefinitionRegistry\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eBeanDefinitionRegistry\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eregistry\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003ethrows\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBeansException\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"kd\"\u003efinal\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebeanName\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;testService\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eregistry\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003econtainsBeanDefinition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebeanName\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"n\"\u003eregistry\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eremoveBeanDefinition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebeanName\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"n\"\u003eGenericBeanDefinition\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebeanDefinition\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eGenericBeanDefinition\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"n\"\u003ebeanDefinition\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003esetBeanClass\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTestService2\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eclass\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"n\"\u003eregistry\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eregisterBeanDefinition\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebeanName\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebeanDefinition\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nd\"\u003e@Override\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003epostProcessBeanFactory\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eConfigurableListableBeanFactory\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003efactory\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003ethrows\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBeansException\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"Spring-动态替换Bean"},{"content":"后端接口为了安全考虑， 通常会增加接口参数签名认证；增加接口参数签名认证， postman直接调用，会认证失败， 需要实现一套和前端项目一样的签名动作；\napi参数签名认证api参数签名认证原理 api-time: 本次API调用的有效时间，超过该时间调用失效，避免重放攻击 api-key: 与api-secret是一个pair对，一一对应，知道了api-key即可查询到api-secret api-signature: api-secret和message一起生成的签名，这里的message一般包括api-key， 请求方法， get， post参数 api-signature的生成规则一般为： crypto-js的hmac_sha256，输出值需转化为base64字符串\npostman pre-request签名计算 var apiKey = pm.globals.get(\u0026#34;apiKey\u0026#34;); var apiSecret = pm.globals.get(\u0026#34;apiSecret\u0026#34;); const query = pm.request.url.query; var keys = []; var map = {}; query?.each(e =\u0026gt; { let disabled = e[\u0026#34;disabled\u0026#34;]; if (!disabled) { let k = e[\u0026#34;key\u0026#34;]; keys.push(k); map[k] = e[\u0026#34;value\u0026#34;]; } }); const queryArr = []; keys.sort(); keys.forEach(k =\u0026gt; { queryArr.push(k + \u0026#34;=\u0026#34; + map[k]); }); const queryStr = queryArr.join(\u0026#34;\u0026amp;\u0026#34;); const body = JSON.stringify(JSON.parse(pm.request.body.raw.toString())); var method = request.method; var signArr = [apiKey, method.toLowerCase(), queryStr, body]; const signSrcStr = signArr.join(\u0026#39;\u0026amp;\u0026#39;); console.log(signSrcStr); var signatureBase64 = CryptoJS.HmacSHA256(signSrcStr, apiSecret).toString(CryptoJS.enc.Base64); console.log(\u0026#34;signatureBase64\u0026#34;, signatureBase64); pm.environment.set(\u0026#34;api-signature\u0026#34;, signatureBase64); const timeStr = Math.round(new Date().getTime()); pm.environment.set(\u0026#34;api-time\u0026#34;, timeStr); pm.request.body = body; java后端签名计算 class ApiPreHandler { public static String generateHmac256(String msg, String key) { if (Objects.isNull(msg)) { return \u0026#34;\u0026#34;; } if (Objects.isNull(key)) { return msg; } final String algorithm = \u0026#34;HmacSHA256\u0026#34;; try { SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm); Mac mac = Mac.getInstance(algorithm); mac.init(secretKeySpec); byte[] bytes = mac.doFinal(msg.getBytes()); return Base64.getEncoder().encodeToString(bytes); } catch (Exception e) { LogUtils.error(e.getMessage(), e); return \u0026#34;\u0026#34;; } } public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String requestURI = request.getRequestURI(); String method = request.getMethod().toLowerCase(Locale.ROOT); String querySorted = getSortedQuery(request.getQueryString()); String body = request.getReader().lines().collect(Collectors.joining()); String apiSignature = request.getHeader(\u0026#34;api-signature\u0026#34;); String signStrSrc = String.join(\u0026#34;\u0026amp;\u0026#34;, Lists.newArrayList(apiKey, method, querySorted, body)); log.info(\u0026#34;requestURI: {}, singStrSrc={}\u0026#34;, requestURI, signStrSrc); String calcSign = SecurityUtils.generateHmac256(signStrSrc, apiSecret); if (!Objects.equals(apiSignature, calcSign)) { log.error(\u0026#34;api-signature denied, signStrSrc={}\u0026#34;, signStrSrc); return false; } return true; } } ","permalink":"http://fxio.site/posts/postman/postman%E6%8E%A5%E5%8F%A3%E7%AD%BE%E5%90%8D/","summary":"\u003cp\u003e后端接口为了安全考虑， 通常会增加接口参数签名认证；增加接口参数签名认证， postman直接调用，会认证失败， 需要实现一套和前端项目一样的签名动作；\u003c/p\u003e\n\u003ch2 id=\"api参数签名认证api参数签名认证原理\"\u003eapi参数签名认证api参数签名认证原理\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eapi-time: 本次API调用的有效时间，超过该时间调用失效，避免重放攻击\u003c/li\u003e\n\u003cli\u003eapi-key: 与api-secret是一个pair对，一一对应，知道了api-key即可查询到api-secret\u003c/li\u003e\n\u003cli\u003eapi-signature: api-secret和message一起生成的签名，这里的message一般包括api-key， 请求方法， get， post参数\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eapi-signature的生成规则一般为： crypto-js的hmac_sha256，输出值需转化为base64字符串\u003c/p\u003e\n\u003ch2 id=\"postman-pre-request签名计算\"\u003epostman pre-request签名计算\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-javascript\" data-lang=\"javascript\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003eapiKey\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003epm\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eglobals\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;apiKey\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003eapiSecret\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003epm\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eglobals\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eget\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;apiSecret\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003equery\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003epm\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eurl\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003equery\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003ekeys\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003emap\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e{};\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003equery\u003c/span\u003e\u003cspan class=\"o\"\u003e?\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eeach\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ee\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nx\"\u003edisabled\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;disabled\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"nx\"\u003edisabled\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"kd\"\u003elet\u003c/span\u003e \u003cspan class=\"nx\"\u003ek\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;key\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003ekeys\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003epush\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ek\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nx\"\u003emap\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003ek\u003c/span\u003e\u003cspan class=\"p\"\u003e]\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;value\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"p\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003equeryArr\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003ekeys\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003esort\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003ekeys\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eforEach\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ek\u003c/span\u003e \u003cspan class=\"p\"\u003e=\u0026gt;\u003c/span\u003e \u003cspan class=\"p\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nx\"\u003equeryArr\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003epush\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003ek\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"s2\"\u003e\u0026#34;=\u0026#34;\u003c/span\u003e \u003cspan class=\"o\"\u003e+\u003c/span\u003e \u003cspan class=\"nx\"\u003emap\u003c/span\u003e\u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003ek\u003c/span\u003e\u003cspan class=\"p\"\u003e]);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e});\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003equeryStr\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003equeryArr\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ejoin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;\u0026amp;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003ebody\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eJSON\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003estringify\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eJSON\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eparse\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003epm\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ebody\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eraw\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003etoString\u003c/span\u003e\u003cspan class=\"p\"\u003e()));\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003emethod\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003emethod\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003esignArr\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"p\"\u003e[\u003c/span\u003e\u003cspan class=\"nx\"\u003eapiKey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003emethod\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003etoLowerCase\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e \u003cspan class=\"nx\"\u003equeryStr\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003ebody\u003c/span\u003e\u003cspan class=\"p\"\u003e];\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003esignSrcStr\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003esignArr\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ejoin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;\u0026amp;\u0026#39;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003econsole\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003esignSrcStr\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003evar\u003c/span\u003e \u003cspan class=\"nx\"\u003esignatureBase64\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003eCryptoJS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eHmacSHA256\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003esignSrcStr\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003eapiSecret\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"nx\"\u003etoString\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"nx\"\u003eCryptoJS\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eenc\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eBase64\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003econsole\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;signatureBase64\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003esignatureBase64\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003epm\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eenvironment\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;api-signature\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003esignatureBase64\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kr\"\u003econst\u003c/span\u003e \u003cspan class=\"nx\"\u003etimeStr\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nb\"\u003eMath\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eround\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e \u003cspan class=\"nb\"\u003eDate\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"nx\"\u003egetTime\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003epm\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eenvironment\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003eset\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s2\"\u003e\u0026#34;api-time\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e \u003cspan class=\"nx\"\u003etimeStr\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nx\"\u003epm\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"nx\"\u003ebody\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e \u003cspan class=\"nx\"\u003ebody\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"java后端签名计算\"\u003ejava后端签名计算\u003c/h2\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eApiPreHandler\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003egenerateHmac256\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emsg\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eObjects\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eisNull\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emsg\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eObjects\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eisNull\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emsg\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"kd\"\u003efinal\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ealgorithm\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;HmacSHA256\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"k\"\u003etry\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"n\"\u003eSecretKeySpec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esecretKeySpec\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSecretKeySpec\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ekey\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003egetBytes\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eStandardCharsets\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eUTF_8\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ealgorithm\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"n\"\u003eMac\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emac\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eMac\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003egetInstance\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ealgorithm\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"n\"\u003emac\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003einit\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esecretKeySpec\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"kt\"\u003ebyte\u003c/span\u003e\u003cspan class=\"o\"\u003e[]\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebytes\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emac\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003edoFinal\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003emsg\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003egetBytes\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eBase64\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003egetEncoder\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"na\"\u003eencodeToString\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ebytes\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecatch\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eException\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"n\"\u003eLogUtils\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003egetMessage\u003c/span\u003e\u003cspan class=\"p\"\u003e(),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003eboolean\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003epreHandle\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eHttpServletRequest\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eHttpServletResponse\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eresponse\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eObject\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ehandler\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003ethrows\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eException\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003erequestURI\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003egetRequestURI\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emethod\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003egetMethod\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"na\"\u003etoLowerCase\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eLocale\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eROOT\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003equerySorted\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003egetSortedQuery\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003egetQueryString\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebody\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003egetReader\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"na\"\u003elines\u003c/span\u003e\u003cspan class=\"p\"\u003e().\u003c/span\u003e\u003cspan class=\"na\"\u003ecollect\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eCollectors\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003ejoining\u003c/span\u003e\u003cspan class=\"p\"\u003e());\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eapiSignature\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003erequest\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003egetHeader\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;api-signature\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esignStrSrc\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003ejoin\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;\u0026amp;\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eLists\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003enewArrayList\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eapiKey\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emethod\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003equerySorted\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ebody\u003c/span\u003e\u003cspan class=\"p\"\u003e));\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"n\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003einfo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;requestURI: {}, singStrSrc={}\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003erequestURI\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esignStrSrc\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecalcSign\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eSecurityUtils\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003egenerateHmac256\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003esignStrSrc\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eapiSecret\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"o\"\u003e!\u003c/span\u003e\u003cspan class=\"n\"\u003eObjects\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eequals\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eapiSignature\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ecalcSign\u003c/span\u003e\u003cspan class=\"p\"\u003e))\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"n\"\u003elog\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eerror\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;api-signature denied, signStrSrc={}\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003esignStrSrc\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003efalse\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003etrue\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e","title":"postman接口签名"},{"content":"","permalink":"http://fxio.site/categories/","summary":"","title":"categories"},{"content":"有时候我们需要录制Android手机的屏幕，比如写了一个Demo应用，需要发布到博客和微博上。 对于Android4.4以上的手机，系统自带了一个命令screenrecord，我们可以很方便的使用。\n录制命令 adb shell screenrecord /sdcard/test.mp4 视频保存目录可以自己指定，如上面的/sdcard/test.mp4， 命令执行后会一直录制180s，按下ctrl+c可以提前结束录制\n设定视频分辨率 对于高分辨率的手机，录制的视频很大，我们分享又不需要这么大的 我们可以设置录制的视频分辨率\nadb shell screenrecord --size 848x480 /sdcard/test.mp4 设定视频比特率 默认比特率是4M/s，为了分享方便，我们可以调低比特率为2M\nadb shell screenrecord --bit-rate 2000000 /sdcard/test.mp4 获取视频文件 使用adb pull 即可把手机SD卡中视频获取到本地\nadb pull /sdcard/test.mp4 . 转GIF文件 在Windows下有个不错的软件Free Video to GIF Converter可以把mp4转换成GIF。 转换时还可以删除不需要的帧，这点真得很不错。\nMac上可以使用gifrocket进行转换。\n原文链接\n","permalink":"http://fxio.site/posts/android/2018-05-01-android%E5%BD%95%E5%88%B6gif/","summary":"\u003cp\u003e有时候我们需要录制Android手机的屏幕，比如写了一个Demo应用，需要发布到博客和微博上。\n对于Android4.4以上的手机，系统自带了一个命令screenrecord，我们可以很方便的使用。\u003c/p\u003e\n\u003ch2 id=\"录制命令\"\u003e录制命令\u003c/h2\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eadb shell screenrecord /sdcard/test.mp4\n\u003c/code\u003e\u003c/pre\u003e\u003cp\u003e视频保存目录可以自己指定，如上面的/sdcard/test.mp4，\n命令执行后会一直录制180s，按下ctrl+c可以提前结束录制\u003c/p\u003e\n\u003ch2 id=\"设定视频分辨率\"\u003e设定视频分辨率\u003c/h2\u003e\n\u003cp\u003e对于高分辨率的手机，录制的视频很大，我们分享又不需要这么大的\n我们可以设置录制的视频分辨率\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eadb shell screenrecord --size 848x480 /sdcard/test.mp4\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"设定视频比特率\"\u003e设定视频比特率\u003c/h2\u003e\n\u003cp\u003e默认比特率是4M/s，为了分享方便，我们可以调低比特率为2M\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eadb shell screenrecord --bit-rate 2000000 /sdcard/test.mp4\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"获取视频文件\"\u003e获取视频文件\u003c/h2\u003e\n\u003cp\u003e使用adb pull 即可把手机SD卡中视频获取到本地\u003c/p\u003e\n\u003cpre tabindex=\"0\"\u003e\u003ccode\u003eadb pull /sdcard/test.mp4 .\n\u003c/code\u003e\u003c/pre\u003e\u003ch2 id=\"转gif文件\"\u003e转GIF文件\u003c/h2\u003e\n\u003cp\u003e在Windows下有个不错的软件Free Video to GIF Converter可以把mp4转换成GIF。\n转换时还可以删除不需要的帧，这点真得很不错。\u003c/p\u003e\n\u003cp\u003eMac上可以使用\u003ca href=\"http://www.gifrocket.com/\"\u003egifrocket\u003c/a\u003e进行转换。\u003c/p\u003e\n\u003cp\u003e\u003ca href=\"https://appkfz.com/2015/07/10/android-record-video-to-gif/\"\u003e原文链接\u003c/a\u003e\u003c/p\u003e","title":"Android录制Gif"},{"content":"常用 Linux 命令 cd 改变当前目录\n# 跳转到家目录 cd ~ # 跳转到上级目录 cd .. # 跳转根目录 cd / # 显示当前目录 pwd cp 复制文件\n# 复制目录 cp -r source_dir destination_dir mkdir mkdir -p /data/www/test tar tar -zcvf /data/backup/test.tar.gz /data/www/test 系统信息 uname -a cat /proc/cpuinfo cat /proc/meminfo cat /proc/meminfo | grep MemTotal lspci -tv lsusb -tv free -m df -h du -sh /data/www/test uptime fdisk -l 网络 ifconfig netstat -antp netstat -antp | grep 80 进程 ps -ef | grep java # 用户登录日志 last 软件 # 查看已安装的java版本 dpkg -l | grep java # 安装java sudo apt install -y openjdk-8-jdk # 卸载java sudo apt remove openjdk-8-jdk # dpkg -ivh 安装软件包 # rpm -qa | grep java 磁盘容量报警 服务器不停的运行，会产生很多日志文件（nginx，tomcat） 设查询条件为：\n日志文件 大于1G 方法：\n1.找到该文件 find / -type f -name \u0026#34;*log*\u0026#34; | xargs ls -lSh | more du -a / | sort -rn | grep log | more find / -name \u0026#39;*log*\u0026#39; -size +1000M -exec du -h {} \\; 2.将文件清空 假设找到的文件为a.log 正确的情况方式应该为：echo \u0026ldquo;\u0026quot;\u0026gt;a.log，文件空间会立刻释放。 很多同学：rm -rf a.log，这样文件虽然删除，但是因tomcat服务仍在运行，空间不会立刻释放，需要重启tomcat才能将空间释放。\n显示文件，过滤注释 问题：显示server.conf 文件，屏蔽掉#号开头的注释行\n方法：\nsed -n \u0026#39;/^[#]/!p\u0026#39; server.conf sed -e \u0026#39;/^#/d\u0026#39; server.conf grep -v \u0026#34;^#\u0026#34; server.conf 磁盘IO异常排查 问题：磁盘IO异常如何排查，类似写入慢或当前使用率较高，请查出导致磁盘IO异常高的进程ID。\n方法：\niotop -o 查看当前正在写磁盘操作的所有进程ID信息。\n如果此时各项写入指标都很低，基本没有大的写入操作，则需要排查磁盘自身。 可以查看系统dmesg或cat /var/log/message 看看是否有相关的磁盘异常报错，同时可以在写入慢的磁盘上touch 一个空文件看看，是否磁盘故障导致无法写入。\n从已经备份好的日志中查询数据 问题：从已备份的 a.log.bz2 日志中，找出包含关键字1.2.3.4的日志有多少条。\n方法：\nbzcat suyun.a.log.bz2 | grep \u0026#39;1.2.3.4\u0026#39; | wc -l bzgrep \u0026#39;1.2.3.4\u0026#39; a.log.bz2 | wc -l less a.log.bz2 | grep \u0026#39;10.37.9.11\u0026#39; | wc -l 说明：线上日志文件一般以bz2 压缩之后保留，如果解压查询，非常耗空间与时间，bzcat和bzgrep是研发同学必须掌握的工具。\n统计当前文件夹(目录)大小，并按文件大小排序 du -sh * | sort -n 统计文件数量 # 统计某个目录文件总数 find /home -type f |wc -l find . -name *.gz # 当前目录下所有普通文件(包含子目录) find . -type f -exec ls -l {} \\; 查找包含某个内容的文件 find . -type f -exec grep -H \u0026#39;redirect\u0026#39; {} \\; grep -rnw \u0026#39;/home/path\u0026#39; -e \u0026#39;redirect\u0026#39; 查看本机端口占用情况 netstat -anlp | grep :80 sudo lsof -i:80 查询线程数 问题：查询服务器运行服务的总线程数，当机器线程数超报警阀值时，能快速查出相关进程及线程信息。\n方法：\nps -eLf | wc -l pstree -p | wc -l 文件目录同步 # rsync rsync-a /data /backup 拷贝本地文件 rsync -av root@192.168.31.150::www /databack 远程拷贝 # scp # 复制远程文件到本机 scp root@192.168.31.150:./testfile testfile 备份文件 备份/home/www 目录，排除掉目录中的logs和目录，打包好的文件存放在/opt/backup目录下。\n方法：\ntar -zcvf /opt/backup/www.tar.gz \\ -exclude /home/www/logs \\ /home/www 这个命令应用较为频繁，在项目需要打包迁移时，常常需要排除掉日志目录，exclude是需要掌握的参数。\n","permalink":"http://fxio.site/posts/linux/2017-04-24-linux%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/","summary":"\u003ch2 id=\"常用-linux-命令\"\u003e常用 Linux 命令\u003c/h2\u003e\n\u003ch3 id=\"cd\"\u003ecd\u003c/h3\u003e\n\u003cp\u003e改变当前目录\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 跳转到家目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003ecd\u003c/span\u003e ~\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 跳转到上级目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003ecd\u003c/span\u003e ..\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 跳转根目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003ecd\u003c/span\u003e /\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 显示当前目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nb\"\u003epwd\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"cp\"\u003ecp\u003c/h3\u003e\n\u003cp\u003e复制文件\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 复制目录\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ecp -r source_dir destination_dir\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"mkdir\"\u003emkdir\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003emkdir -p /data/www/test\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"tar\"\u003etar\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003etar -zcvf /data/backup/test.tar.gz /data/www/test\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"系统信息\"\u003e系统信息\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003euname -a\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ecat /proc/cpuinfo\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ecat /proc/meminfo\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003ecat /proc/meminfo \u003cspan class=\"p\"\u003e|\u003c/span\u003e grep MemTotal\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003elspci -tv\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003elsusb -tv\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003efree -m\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003edf -h\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003edu -sh /data/www/test\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003euptime\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003efdisk -l\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"网络\"\u003e网络\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eifconfig\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003enetstat -antp\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003enetstat -antp \u003cspan class=\"p\"\u003e|\u003c/span\u003e grep \u003cspan class=\"m\"\u003e80\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"进程\"\u003e进程\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eps -ef \u003cspan class=\"p\"\u003e|\u003c/span\u003e grep java\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 用户登录日志\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003elast\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"软件\"\u003e软件\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 查看已安装的java版本\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003edpkg -l \u003cspan class=\"p\"\u003e|\u003c/span\u003e grep java\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 安装java\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt install -y openjdk-8-jdk\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# 卸载java\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esudo apt remove openjdk-8-jdk\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# dpkg -ivh 安装软件包\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"c1\"\u003e# rpm -qa | grep java\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3\u003e\u003c/h3\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"磁盘容量报警\"\u003e磁盘容量报警\u003c/h3\u003e\n\u003cp\u003e服务器不停的运行，会产生很多日志文件（nginx，tomcat）\n设查询条件为：\u003c/p\u003e","title":"常用的 Linux 命令"},{"content":"Android-opencv-cmake Android opencv image process samples ,build with cmake\n环境要求 Android studio 2.3.3 Cmake ndk14 opencv2.4.13 or opencv3.3 配置 在local.properties 文件中配置opencv sdk 路径 opencv.dir = ${opencv_sdk_dir} ndk.dir=/Users/king/Library/Android/ndk14 sdk.dir=/Users/king/Library/Android/sdk opencv.dir=/Users/king/Libs/OpenCV2413 在build.gradle中配置cmake参数 externalNativeBuild { cmake { cppFlags \u0026#34;-std=c++11 -frtti -fexceptions\u0026#34; arguments \u0026#34;-DOpenCV_DIR=\u0026#34; + getOpenCVDir().toString()+\u0026#34;/sdk/native/jni\u0026#34;, \u0026#34;-DANDROID_ARM_NEON=TRUE\u0026#34; } } ndk { abiFilters \u0026#34;armeabi-v7a\u0026#34; //, \u0026#34;arm64-v8a\u0026#34;,\u0026#34;armeabi\u0026#34;, } ... def getOpenCVDir() { Properties properties = new Properties() properties.load(new File(rootDir.absolutePath + \u0026#34;/local.properties\u0026#34;).newDataInputStream()) def externalModuleDir = properties.getProperty(\u0026#39;opencv.dir\u0026#39;, null) if (externalModuleDir == null) { throw new GradleException( \u0026#34;OpenCV location not found. Define location with opencv.dir in the local.properties file!\u0026#34;) } return externalModuleDir } 项目地址 源码\n","permalink":"http://fxio.site/posts/android/2017-3-15-android-opencv/","summary":"\u003ch2 id=\"android-opencv-cmake\"\u003eAndroid-opencv-cmake\u003c/h2\u003e\n\u003cblockquote\u003e\n\u003cp\u003eAndroid opencv image process samples ,build with cmake\u003c/p\u003e\n\u003c/blockquote\u003e\n\u003ch2 id=\"环境要求\"\u003e环境要求\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003eAndroid studio 2.3.3\u003c/li\u003e\n\u003cli\u003eCmake\u003c/li\u003e\n\u003cli\u003endk14\u003c/li\u003e\n\u003cli\u003eopencv2.4.13 or opencv3.3\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"配置\"\u003e配置\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e在local.properties 文件中配置opencv sdk 路径\nopencv.dir = ${opencv_sdk_dir}\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003endk.dir\u003cspan class=\"o\"\u003e=\u003c/span\u003e/Users/king/Library/Android/ndk14\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003esdk.dir\u003cspan class=\"o\"\u003e=\u003c/span\u003e/Users/king/Library/Android/sdk\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eopencv.dir\u003cspan class=\"o\"\u003e=\u003c/span\u003e/Users/king/Libs/OpenCV2413\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e在build.gradle中配置cmake参数\u003c/li\u003e\n\u003c/ul\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003eexternalNativeBuild \u003cspan class=\"o\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e     cmake \u003cspan class=\"o\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           cppFlags \u003cspan class=\"s2\"\u003e\u0026#34;-std=c++11 -frtti -fexceptions\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e           arguments \u003cspan class=\"s2\"\u003e\u0026#34;-DOpenCV_DIR=\u0026#34;\u003c/span\u003e + getOpenCVDir\u003cspan class=\"o\"\u003e()\u003c/span\u003e.toString\u003cspan class=\"o\"\u003e()\u003c/span\u003e+\u003cspan class=\"s2\"\u003e\u0026#34;/sdk/native/jni\u0026#34;\u003c/span\u003e, \u003cspan class=\"s2\"\u003e\u0026#34;-DANDROID_ARM_NEON=TRUE\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      \u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003endk \u003cspan class=\"o\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e      abiFilters  \u003cspan class=\"s2\"\u003e\u0026#34;armeabi-v7a\u0026#34;\u003c/span\u003e   //, \u003cspan class=\"s2\"\u003e\u0026#34;arm64-v8a\u0026#34;\u003c/span\u003e,\u003cspan class=\"s2\"\u003e\u0026#34;armeabi\u0026#34;\u003c/span\u003e,\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e...\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003edef getOpenCVDir\u003cspan class=\"o\"\u003e()\u003c/span\u003e \u003cspan class=\"o\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    Properties \u003cspan class=\"nv\"\u003eproperties\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e new Properties\u003cspan class=\"o\"\u003e()\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    properties.load\u003cspan class=\"o\"\u003e(\u003c/span\u003enew File\u003cspan class=\"o\"\u003e(\u003c/span\u003erootDir.absolutePath + \u003cspan class=\"s2\"\u003e\u0026#34;/local.properties\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e)\u003c/span\u003e.newDataInputStream\u003cspan class=\"o\"\u003e())\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    def \u003cspan class=\"nv\"\u003eexternalModuleDir\u003c/span\u003e \u003cspan class=\"o\"\u003e=\u003c/span\u003e properties.getProperty\u003cspan class=\"o\"\u003e(\u003c/span\u003e\u003cspan class=\"s1\"\u003e\u0026#39;opencv.dir\u0026#39;\u003c/span\u003e, null\u003cspan class=\"o\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003eif\u003c/span\u003e \u003cspan class=\"o\"\u003e(\u003c/span\u003e\u003cspan class=\"nv\"\u003eexternalModuleDir\u003c/span\u003e \u003cspan class=\"o\"\u003e==\u003c/span\u003e null\u003cspan class=\"o\"\u003e)\u003c/span\u003e \u003cspan class=\"o\"\u003e{\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        throw new GradleException\u003cspan class=\"o\"\u003e(\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e                \u003cspan class=\"s2\"\u003e\u0026#34;OpenCV location not found. Define location with opencv.dir in the local.properties file!\u0026#34;\u003c/span\u003e\u003cspan class=\"o\"\u003e)\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"k\"\u003ereturn\u003c/span\u003e externalModuleDir\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"o\"\u003e}\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cul\u003e\n\u003cli\u003e项目地址\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e\u003ca href=\"https://github.com/sunworthy/Android-opencv-cmake\"\u003e源码\u003c/a\u003e\u003c/p\u003e","title":"Android-opencv-cmake "},{"content":"AIDL是什么 ? AIDL是Android中IPC（Inter-Process Communication）方式中的一种，AIDL是Android Interface definition language的缩写，AIDL的作用是让你可以在自己的APP里绑定一个其他APP的service，这样你的APP可以和其他APP交互\n为什么要有aidl ? 用于两个App之间交换数据的场景 为什么不能直接通讯? 在 Android 上，一个进程通常无法访问另一个进程的内存, 而AIDL只是Android中众多进程间通讯方式中的一种方式\n使用方法 服务端AidlApp1 使用Android Studio在Service服务端创建aidl文件: IUserAidlInterface, 然后build一下 package com.joshkryo.aidl; interface IUserAidlInterface { String getUserInfo(int uid); } 创建Service实现类 public class UserAidlService extends Service { private static final String TAG = \u0026#34;UserAidlService\u0026#34;; @Nullable @Override public IBinder onBind(Intent intent) { Log.d(TAG, \u0026#34;onBind: \u0026#34; + intent); return mBinder; } private final IUserAidlInterface.Stub mBinder = new IUserAidlInterface.Stub() { @Override public String getUserInfo(int uid) throws RemoteException { return \u0026#34;{\\\u0026#34;id\\\u0026#34;:\u0026#34; + uid + \u0026#34; ,name\\\u0026#34;:\\\u0026#34;Tom\\\u0026#34;,\\\u0026#34;age\\\u0026#34;:18}\u0026#34;; } }; } 注册Service \u0026lt;service android:name=\u0026#34;com.joshkryo.aidlapp1.service.UserAidlService\u0026#34; android:enabled=\u0026#34;true\u0026#34;\u0026gt; \u0026lt;intent-filter\u0026gt; \u0026lt;action android:name=\u0026#34;com.joshkryo.aidlapp1.service.UserAidlService\u0026#34;/\u0026gt; \u0026lt;category android:name=\u0026#34;android.intent.category.DEFAULT\u0026#34;/\u0026gt; \u0026lt;/intent-filter\u0026gt; \u0026lt;/service\u0026gt; 客户端AidlApp2 复制AidlApp1的aidl文件到AidlApp2, build一下 bindService class BindService { private void bindAidlService() { Intent intent = new Intent(\u0026#34;com.joshkryo.aidlapp1.service.UserAidlService\u0026#34;);// service配置的action intent.setPackage(\u0026#34;com.joshkryo.aidlapp1\u0026#34;);//service服务端包名 bindService(intent, mAidlConn, Context.BIND_AUTO_CREATE); } private ServiceConnection mAidlConn = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d(TAG, \u0026#34;onServiceConnected\u0026#34;); userAidlInterface = IUserAidlInterface.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName name) { Log.e(TAG, \u0026#34;onServiceDisconnected: \u0026#34;); userAidlInterface = null; } }; } 使用aidl interface调用AidlApp1里的service class Test { public void getAidlUserInfo(View v) { try { if (userAidlInterface == null) { Log.e(TAG, \u0026#34;onClick: null userAidlInterface instance\u0026#34;); return; } Toast.makeText(MainActivity.this, userAidlInterface.getUserInfo(1), Toast.LENGTH_SHORT).show(); } catch (RemoteException e) { e.printStackTrace(); } } } 可能的错误 Service Intent must be explicit java.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com.joshkryo.aidlapp1 } at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2854) 原因: Android5.0之后service的intent一定要显性声明 onServiceConnected不调用 可能原因: service 没有在manifest里面注册 服务端, 客户端的 intent action 不一致 ","permalink":"http://fxio.site/posts/android/2015.05.18-android-aidl%E7%9A%84%E4%BD%BF%E7%94%A8/","summary":"\u003ch2 id=\"aidl是什么-\"\u003eAIDL是什么 ?\u003c/h2\u003e\n\u003cp\u003eAIDL是Android中IPC（Inter-Process Communication）方式中的一种，AIDL是Android Interface definition\nlanguage的缩写，AIDL的作用是让你可以在自己的APP里绑定一个其他APP的service，这样你的APP可以和其他APP交互\u003c/p\u003e\n\u003ch2 id=\"为什么要有aidl-\"\u003e为什么要有aidl ?\u003c/h2\u003e\n\u003cp\u003e用于两个App之间交换数据的场景\n为什么不能直接通讯?\n在 Android 上，一个进程通常无法访问另一个进程的内存, 而AIDL只是Android中众多进程间通讯方式中的一种方式\u003c/p\u003e\n\u003ch2 id=\"使用方法\"\u003e使用方法\u003c/h2\u003e\n\u003ch3 id=\"服务端aidlapp1\"\u003e服务端AidlApp1\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e使用Android Studio在Service服务端创建aidl文件: IUserAidlInterface, 然后build一下\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kn\"\u003epackage\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nn\"\u003ecom.joshkryo.aidl\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003einterface\u003c/span\u003e \u003cspan class=\"nc\"\u003eIUserAidlInterface\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003egetUserInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euid\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"2\"\u003e\n\u003cli\u003e创建Service实现类\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eUserAidlService\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003eextends\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eService\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"kd\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003estatic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efinal\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eTAG\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;UserAidlService\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nd\"\u003e@Nullable\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"nd\"\u003e@Override\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIBinder\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eonBind\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eIntent\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eintent\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"n\"\u003eLog\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003ed\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTAG\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;onBind: \u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eintent\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emBinder\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"kd\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003efinal\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIUserAidlInterface\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eStub\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emBinder\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIUserAidlInterface\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eStub\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nd\"\u003e@Override\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eString\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003egetUserInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"kt\"\u003eint\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euid\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kd\"\u003ethrows\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eRemoteException\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;{\\\u0026#34;id\\\u0026#34;:\u0026#34;\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e+\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34; ,name\\\u0026#34;:\\\u0026#34;Tom\\\u0026#34;,\\\u0026#34;age\\\u0026#34;:18}\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"3\"\u003e\n\u003cli\u003e注册Service\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-xml\" data-lang=\"xml\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;service\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"na\"\u003eandroid:name=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;com.joshkryo.aidlapp1.service.UserAidlService\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"na\"\u003eandroid:enabled=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;true\u0026#34;\u003c/span\u003e\u003cspan class=\"nt\"\u003e\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;intent-filter\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nt\"\u003e\u0026lt;action\u003c/span\u003e \u003cspan class=\"na\"\u003eandroid:name=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;com.joshkryo.aidlapp1.service.UserAidlService\u0026#34;\u003c/span\u003e\u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e        \u003cspan class=\"nt\"\u003e\u0026lt;category\u003c/span\u003e \u003cspan class=\"na\"\u003eandroid:name=\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;android.intent.category.DEFAULT\u0026#34;\u003c/span\u003e\u003cspan class=\"nt\"\u003e/\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e    \u003cspan class=\"nt\"\u003e\u0026lt;/intent-filter\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"nt\"\u003e\u0026lt;/service\u0026gt;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch3 id=\"客户端aidlapp2\"\u003e客户端AidlApp2\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003e复制AidlApp1的aidl文件到AidlApp2, build一下\u003c/li\u003e\n\u003cli\u003ebindService\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eBindService\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"kd\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003ebindAidlService\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"n\"\u003eIntent\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eintent\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIntent\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;com.joshkryo.aidlapp1.service.UserAidlService\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"c1\"\u003e// service配置的action\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"n\"\u003eintent\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003esetPackage\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;com.joshkryo.aidlapp1\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"c1\"\u003e//service服务端包名\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"n\"\u003ebindService\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eintent\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emAidlConn\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eContext\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eBIND_AUTO_CREATE\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"kd\"\u003eprivate\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eServiceConnection\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003emAidlConn\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003enew\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eServiceConnection\u003c/span\u003e\u003cspan class=\"p\"\u003e()\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nd\"\u003e@Override\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eonServiceConnected\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eComponentName\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIBinder\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eservice\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"n\"\u003eLog\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003ed\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTAG\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;onServiceConnected\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"n\"\u003euserAidlInterface\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eIUserAidlInterface\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eStub\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003easInterface\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eservice\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"nd\"\u003e@Override\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003eonServiceDisconnected\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eComponentName\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ename\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"n\"\u003eLog\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTAG\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;onServiceDisconnected: \u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"n\"\u003euserAidlInterface\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e=\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"p\"\u003e};\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003col start=\"3\"\u003e\n\u003cli\u003e使用aidl interface调用AidlApp1里的service\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" class=\"chroma\"\u003e\u003ccode class=\"language-java\" data-lang=\"java\"\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"kd\"\u003eclass\u003c/span\u003e \u003cspan class=\"nc\"\u003eTest\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"kd\"\u003epublic\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kt\"\u003evoid\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"nf\"\u003egetAidlUserInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eView\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ev\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"k\"\u003etry\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"k\"\u003eif\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003euserAidlInterface\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"o\"\u003e==\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"kc\"\u003enull\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e                \u003c/span\u003e\u003cspan class=\"n\"\u003eLog\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eTAG\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"s\"\u003e\u0026#34;onClick: null userAidlInterface instance\u0026#34;\u003c/span\u003e\u003cspan class=\"p\"\u003e);\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e                \u003c/span\u003e\u003cspan class=\"k\"\u003ereturn\u003c/span\u003e\u003cspan class=\"p\"\u003e;\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"n\"\u003eToast\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003emakeText\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eMainActivity\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003ethis\u003c/span\u003e\u003cspan class=\"p\"\u003e,\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003euserAidlInterface\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003egetUserInfo\u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003e1\u003c/span\u003e\u003cspan class=\"p\"\u003e),\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003eToast\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eLENGTH_SHORT\u003c/span\u003e\u003cspan class=\"p\"\u003e).\u003c/span\u003e\u003cspan class=\"na\"\u003eshow\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"k\"\u003ecatch\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e(\u003c/span\u003e\u003cspan class=\"n\"\u003eRemoteException\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e)\u003c/span\u003e\u003cspan class=\"w\"\u003e \u003c/span\u003e\u003cspan class=\"p\"\u003e{\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e            \u003c/span\u003e\u003cspan class=\"n\"\u003ee\u003c/span\u003e\u003cspan class=\"p\"\u003e.\u003c/span\u003e\u003cspan class=\"na\"\u003eprintStackTrace\u003c/span\u003e\u003cspan class=\"p\"\u003e();\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e        \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"w\"\u003e    \u003c/span\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003cspan class=\"line\"\u003e\u003cspan class=\"cl\"\u003e\u003cspan class=\"p\"\u003e}\u003c/span\u003e\u003cspan class=\"w\"\u003e\n\u003c/span\u003e\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"可能的错误\"\u003e可能的错误\u003c/h2\u003e\n\u003col\u003e\n\u003cli\u003eService Intent must be explicit\njava.lang.IllegalArgumentException: Service Intent must be explicit: Intent { act=com.joshkryo.aidlapp1 }\nat android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2854)\n原因:\nAndroid5.0之后service的intent一定要显性声明\u003c/li\u003e\n\u003cli\u003eonServiceConnected不调用\n可能原因:\u003c/li\u003e\n\u003c/ol\u003e\n\u003cul\u003e\n\u003cli\u003eservice 没有在manifest里面注册\u003c/li\u003e\n\u003cli\u003e服务端, 客户端的 intent action 不一致\u003c/li\u003e\n\u003c/ul\u003e","title":"Android OpenCV CMake 调优"}]