<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>网易内推联系我哦</title>
  
  <subtitle>网易无偿内推，点击下方【首页】置顶帖查看说明</subtitle>
  <link href="https://jueee.github.io/atom.xml" rel="self"/>
  
  <link href="https://jueee.github.io/"/>
  <updated>2026-01-21T01:49:22.522Z</updated>
  <id>https://jueee.github.io/</id>
  
  <author>
    <name>网易无偿内推</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>从本地仓库到私有仓库的完美解决方案</title>
    <link href="https://jueee.github.io/2026/01/2026-01-20-%E4%BB%8E%E6%9C%AC%E5%9C%B0%E4%BB%93%E5%BA%93%E5%88%B0%E7%A7%81%E6%9C%89%E4%BB%93%E5%BA%93%E7%9A%84%E5%AE%8C%E7%BE%8E%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/"/>
    <id>https://jueee.github.io/2026/01/2026-01-20-%E4%BB%8E%E6%9C%AC%E5%9C%B0%E4%BB%93%E5%BA%93%E5%88%B0%E7%A7%81%E6%9C%89%E4%BB%93%E5%BA%93%E7%9A%84%E5%AE%8C%E7%BE%8E%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/</id>
    <published>2026-01-20T00:00:00.000Z</published>
    <updated>2026-01-21T01:49:22.522Z</updated>
    
    <content type="html"><![CDATA[<h2 id="📖-背景介绍"><a href="#📖-背景介绍" class="headerlink" title="📖 背景介绍"></a>📖 背景介绍</h2><p>在 Java 开发过程中，我们经常需要将本地构建的 JAR 包部署到私有 Maven 仓库中，以便团队成员使用。</p><p>然而，手动部署过程繁琐且容易出错：</p><ul><li>需要手动提取 JAR 包中的 Maven 元数据信息</li><li>需要记住复杂的 Maven 部署命令</li><li> Maven 默认禁止从本地仓库直接部署到远程仓库</li><li>中文环境下容易出现编码问题</li></ul><p>为了解决这些痛点，我开发了一个自动化的批处理脚本，能够智能解析 JAR 包信息并自动部署到多个 Maven 仓库。</p><a id="more"></a><h2 id="🎯-解决方案概览"><a href="#🎯-解决方案概览" class="headerlink" title="🎯 解决方案概览"></a>🎯 解决方案概览</h2><p>该脚本主要实现以下功能：</p><ol><li><strong>自动解析 JAR 包元数据</strong>：从 JAR 包中提取 groupId、artifactId、version 信息</li><li><strong>智能 POM 文件处理</strong>：自动查找同目录下的 POM 文件并一同部署</li><li><strong>绕过本地仓库限制</strong>：通过临时文件机制解决 Maven 的安全限制</li><li><strong>多仓库同步部署</strong>：支持同时部署到多个 Maven 仓库</li><li><strong>完善的错误处理</strong>：提供友好的用户交互和错误提示</li></ol><h2 id="🔧-核心技术实现"><a href="#🔧-核心技术实现" class="headerlink" title="🔧 核心技术实现"></a>🔧 核心技术实现</h2><h3 id="1-编码问题解决"><a href="#1-编码问题解决" class="headerlink" title="1. 编码问题解决"></a>1. 编码问题解决</h3><pre class="language-batch" data-language="batch"><code class="language-batch"><span class="token operator">@</span><span class="token command"><span class="token keyword">echo</span> off</span><span class="token command"><span class="token keyword">chcp</span> <span class="token number">65001</span> &gt;nul <span class="token number">2</span>&gt;</span><span class="token operator">&amp;</span><span class="token command"><span class="token keyword">1</span></span><span class="token command"><span class="token keyword">setlocal</span> enabledelayedexpansion</span></code></pre><p><strong>技术解析</strong>：</p><ul><li><code>chcp 65001</code>：将控制台编码页设置为 UTF-8，解决中文乱码问题</li><li><code>&gt;nul 2&gt;&amp;1</code>：隐藏编码设置的输出信息，保持界面整洁</li><li><code>setlocal enabledelayedexpansion</code>：启用延迟变量扩展，支持在循环中动态修改变量</li></ul><h3 id="2-参数验证与文件检查"><a href="#2-参数验证与文件检查" class="headerlink" title="2. 参数验证与文件检查"></a>2. 参数验证与文件检查</h3><pre class="language-batch" data-language="batch"><code class="language-batch"><span class="token command"><span class="token keyword">if</span> <span class="token string">"%~1"</span><span class="token operator">==</span><span class="token string">""</span></span> <span class="token punctuation">(</span>    <span class="token command"><span class="token keyword">echo</span> 用法: <span class="token variable">%~nx0</span> <span class="token operator">^</span>&lt;JAR文件路径<span class="token operator">^</span>&gt;</span>    <span class="token command"><span class="token keyword">echo</span> 示例: <span class="token variable">%~nx0</span> C:\path\to\your.jar</span>    <span class="token command"><span class="token keyword">exit</span> <span class="token parameter attr-name">/b</span> <span class="token number">1</span></span><span class="token punctuation">)</span><span class="token command"><span class="token keyword">set</span> <span class="token string">"filepath=%~1"</span></span><span class="token command"><span class="token keyword">if</span> <span class="token keyword">not</span> <span class="token keyword">exist</span> <span class="token string">"%filepath%"</span></span> <span class="token punctuation">(</span>    <span class="token command"><span class="token keyword">echo</span> 错误: 文件不存在: <span class="token variable">%filepath%</span></span>    <span class="token command"><span class="token keyword">exit</span> <span class="token parameter attr-name">/b</span> <span class="token number">1</span></span><span class="token punctuation">)</span><span class="token command"><span class="token keyword">if</span> <span class="token parameter attr-name">/i</span> <span class="token keyword">not</span> <span class="token string">"%~x1"</span><span class="token operator">==</span><span class="token string">".jar"</span></span> <span class="token punctuation">(</span>    <span class="token command"><span class="token keyword">echo</span> 错误: 文件必须是JAR格式</span>    <span class="token command"><span class="token keyword">exit</span> <span class="token parameter attr-name">/b</span> <span class="token number">1</span></span><span class="token punctuation">)</span></code></pre><p><strong>技术要点</strong>：</p><ul><li><code>%~nx0</code>：获取脚本文件名（不含路径）</li><li><code>%~1</code>：获取第一个参数，<code>%~x1</code>：获取第一个参数的文件扩展名</li><li><code>/i</code>：不区分大小写的比较</li><li><code>exit /b 1</code>：以错误码 1 退出，但不关闭父窗口</li></ul><h3 id="3-PowerShell与批处理混合编程"><a href="#3-PowerShell与批处理混合编程" class="headerlink" title="3. PowerShell与批处理混合编程"></a>3. PowerShell 与批处理混合编程</h3><pre class="language-batch" data-language="batch"><code class="language-batch"><span class="token command"><span class="token keyword">powershell</span> -NoProfile -ExecutionPolicy Bypass -Command <span class="token operator">^</span>    <span class="token string">"[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; "</span> <span class="token operator">^</span>    <span class="token string">"Add-Type -AssemblyName System.IO.Compression.FileSystem; "</span> <span class="token operator">^</span>    <span class="token string">"$zip = [System.IO.Compression.ZipFile]::OpenRead('%filepath%'); "</span> <span class="token operator">^</span>    <span class="token string">"$pomEntry = $zip.Entries | Where-Object { $_.FullName -match 'META-INF/maven/.*/pom.properties$' } | Select-Object -First 1; "</span> <span class="token operator">^</span>    <span class="token string">"if ($pomEntry) { "</span> <span class="token operator">^</span>        <span class="token string">"$stream = $pomEntry.Open(); "</span> <span class="token operator">^</span>        <span class="token string">"$reader = New-Object System.IO.StreamReader($stream); "</span> <span class="token operator">^</span>        <span class="token string">"$content = $reader.ReadToEnd(); "</span> <span class="token operator">^</span>        <span class="token string">"$reader.Close(); "</span> <span class="token operator">^</span>        <span class="token string">"$stream.Close(); "</span> <span class="token operator">^</span>        <span class="token string">"$content | Out-File -FilePath '%tempDir%\pom.properties' -Encoding UTF8; "</span> <span class="token operator">^</span>        <span class="token string">"Write-Host 'SUCCESS: pom.properties found' -ForegroundColor Green; "</span> <span class="token operator">^</span>    <span class="token string">"} else { "</span> <span class="token operator">^</span>        <span class="token string">"Write-Host 'WARNING: pom.properties not found' -ForegroundColor Yellow; "</span> <span class="token operator">^</span>    <span class="token string">"} "</span> <span class="token operator">^</span>    <span class="token string">"$zip.Dispose();"</span></span></code></pre><p><strong>技术亮点</strong>：</p><ul><li><code>-NoProfile</code>：跳过 PowerShell 配置文件，加快启动速度</li><li><code>-ExecutionPolicy Bypass</code>：绕过执行策略限制</li><li><code>^</code>：批处理中的行继续符，用于多行命令</li><li><code>System.IO.Compression.ZipFile</code>：.NET 的 ZIP 文件操作类</li><li>正则表达式匹配：<code>META-INF/maven/.*/pom.properties$</code></li><li><code>$zip.Dispose()</code>：正确释放 ZIP 文件资源（而不是 <code>Close()</code>）</li></ul><h3 id="4-文件解析与变量处理"><a href="#4-文件解析与变量处理" class="headerlink" title="4. 文件解析与变量处理"></a>4. 文件解析与变量处理</h3><pre class="language-batch" data-language="batch"><code class="language-batch"><span class="token command"><span class="token keyword">set</span> <span class="token string">"groupId="</span></span><span class="token command"><span class="token keyword">set</span> <span class="token string">"artifactId="</span></span><span class="token command"><span class="token keyword">set</span> <span class="token string">"version="</span></span><span class="token command"><span class="token keyword">if</span> <span class="token keyword">exist</span> <span class="token string">"%tempDir%\pom.properties"</span></span> <span class="token punctuation">(</span>    <span class="token command"><span class="token keyword">for</span> <span class="token parameter attr-name">/f</span> <span class="token string">"usebackq tokens=1,2 delims=="</span> <span class="token variable">%%a</span> <span class="token keyword">in</span> <span class="token punctuation">(</span><span class="token string">"%tempDir%\pom.properties"</span><span class="token punctuation">)</span> <span class="token keyword">do</span></span> <span class="token punctuation">(</span>        <span class="token command"><span class="token keyword">if</span> <span class="token string">"%%a"</span><span class="token operator">==</span><span class="token string">"groupId"</span></span> <span class="token command"><span class="token keyword">set</span> <span class="token string">"groupId=%%b"</span></span>        <span class="token command"><span class="token keyword">if</span> <span class="token string">"%%a"</span><span class="token operator">==</span><span class="token string">"artifactId"</span></span> <span class="token command"><span class="token keyword">set</span> <span class="token string">"artifactId=%%b"</span></span>        <span class="token command"><span class="token keyword">if</span> <span class="token string">"%%a"</span><span class="token operator">==</span><span class="token string">"version"</span></span> <span class="token command"><span class="token keyword">set</span> <span class="token string">"version=%%b"</span></span>    <span class="token punctuation">)</span><span class="token punctuation">)</span></code></pre><p><strong>解析机制</strong>：</p><ul><li><code>usebackq</code>：允许使用引号括起文件名</li><li><code>tokens=1,2</code>：分割每行为两个 token</li><li><code>delims==</code>：使用等号作为分隔符</li><li><code>%%a</code> 和 <code>%%b</code>：循环变量，分别代表键和值</li></ul><h3 id="5-绕过Maven本地仓库限制"><a href="#5-绕过Maven本地仓库限制" class="headerlink" title="5. 绕过Maven本地仓库限制"></a>5. 绕过 Maven 本地仓库限制</h3><pre class="language-batch" data-language="batch"><code class="language-batch"><span class="token command"><span class="token keyword">set</span> <span class="token string">"tempUploadDir=%TEMP%\maven_upload_%RANDOM%"</span></span><span class="token command"><span class="token keyword">mkdir</span> <span class="token string">"%tempUploadDir%"</span></span><span class="token command"><span class="token keyword">set</span> <span class="token string">"tempJarPath=%tempUploadDir%\%artifactId%-%version%.jar"</span></span><span class="token command"><span class="token keyword">copy</span> <span class="token string">"%filepath%"</span> <span class="token string">"%tempJarPath%"</span> &gt;nul</span></code></pre><p><strong>技术原理</strong>：</p><ul><li>Maven 禁止直接从<code>.m2/repository</code> 目录部署文件到远程仓库</li><li>通过创建临时目录并复制文件来绕过这个限制</li><li><code>%RANDOM%</code>：生成随机数，确保临时目录名唯一</li><li>文件重命名为标准格式：<code>artifactId-version.jar</code></li></ul><h3 id="6-智能POM文件检测"><a href="#6-智能POM文件检测" class="headerlink" title="6. 智能POM文件检测"></a>6. 智能 POM 文件检测</h3><pre class="language-batch" data-language="batch"><code class="language-batch"><span class="token command"><span class="token keyword">set</span> <span class="token string">"pomFilePath=%filepath:.jar=.pom%"</span></span><span class="token command"><span class="token keyword">set</span> <span class="token string">"pomFileExists=false"</span></span><span class="token command"><span class="token keyword">if</span> <span class="token keyword">exist</span> <span class="token string">"%pomFilePath%"</span></span> <span class="token punctuation">(</span>    <span class="token command"><span class="token keyword">echo</span> 找到对应的POM文件: <span class="token variable">%pomFilePath%</span></span>    <span class="token command"><span class="token keyword">set</span> <span class="token string">"pomFileExists=true"</span></span>    <span class="token command"><span class="token keyword">set</span> <span class="token string">"tempPomPath=%tempUploadDir%\%artifactId%-%version%.pom"</span></span>    <span class="token command"><span class="token keyword">copy</span> <span class="token string">"%pomFilePath%"</span> <span class="token string">"!tempPomPath!"</span> &gt;nul</span><span class="token punctuation">)</span> <span class="token command"><span class="token keyword">else</span></span> <span class="token punctuation">(</span>    <span class="token command"><span class="token keyword">echo</span> 未找到对应的POM文件: <span class="token variable">%pomFilePath%</span></span>    <span class="token command"><span class="token keyword">echo</span> 将仅上传JAR文件</span><span class="token punctuation">)</span></code></pre><p><strong>实现逻辑</strong>：</p><ul><li><code>%filepath:.jar=.pom%</code>：字符串替换，将<code>.jar</code> 替换为<code>.pom</code></li><li>延迟变量扩展：使用 <code>!tempPomPath!</code> 而不是 <code>%tempPomPath%</code></li><li>条件处理：根据 POM 文件存在与否采用不同的部署策略</li></ul><h3 id="7-条件化Maven部署命令"><a href="#7-条件化Maven部署命令" class="headerlink" title="7. 条件化Maven部署命令"></a>7. 条件化 Maven 部署命令</h3><pre class="language-batch" data-language="batch"><code class="language-batch"><span class="token command"><span class="token keyword">if</span> <span class="token string">"%pomFileExists%"</span><span class="token operator">==</span><span class="token string">"true"</span></span> <span class="token punctuation">(</span>    <span class="token command"><span class="token keyword">set</span> <span class="token string">"deployCmd1=mvn deploy:deploy-file -Dmaven.test.skip=true -DgroupId=%groupId% -DartifactId=%artifactId% -Dversion=%version% -Dpackaging=jar -Dfile="</span><span class="token variable">!tempJarPath!</span><span class="token string">" -DpomFile="</span><span class="token variable">!tempPomPath!</span><span class="token string">" -Durl=http://repo1.example.com/repository/maven-releases -DrepositoryId=maven-public"</span></span><span class="token punctuation">)</span> <span class="token command"><span class="token keyword">else</span></span> <span class="token punctuation">(</span>    <span class="token command"><span class="token keyword">set</span> <span class="token string">"deployCmd1=mvn deploy:deploy-file -Dmaven.test.skip=true -DgroupId=%groupId% -DartifactId=%artifactId% -Dversion=%version% -Dpackaging=jar -Dfile="</span><span class="token variable">!tempJarPath!</span><span class="token string">" -Durl=http://repo1.example.com/repository/maven-releases -DrepositoryId=maven-public"</span></span><span class="token punctuation">)</span></code></pre><p><strong>参数说明</strong>：</p><ul><li><code>-Dmaven.test.skip=true</code>：跳过测试阶段，加快部署速度</li><li><code>-DgroupId/-DartifactId/-Dversion</code>：Maven 坐标信息</li><li><code>-Dpackaging=jar</code>：指定打包类型</li><li><code>-Dfile</code>：要部署的文件路径</li><li><code>-DpomFile</code>：可选，POM 文件路径（仅在存在时添加）</li><li><code>-Durl</code>：目标仓库 URL</li><li><code>-DrepositoryId</code>：仓库 ID，需要在 Maven settings.xml 中配置认证信息</li></ul><h3 id="8-并发部署与资源清理"><a href="#8-并发部署与资源清理" class="headerlink" title="8. 并发部署与资源清理"></a>8. 并发部署与资源清理</h3><pre class="language-batch" data-language="batch"><code class="language-batch"><span class="token command"><span class="token keyword">start</span> <span class="token string">"Maven Deploy 1"</span> <span class="token variable">!deployCmd1!</span></span><span class="token command"><span class="token keyword">timeout</span> <span class="token parameter attr-name">/t</span> <span class="token number">1</span> <span class="token parameter attr-name">/nobreak</span> &gt;nul</span><span class="token command"><span class="token keyword">start</span> <span class="token string">"Maven Deploy 2"</span> <span class="token variable">!deployCmd2!</span></span><span class="token command"><span class="token keyword">timeout</span> <span class="token parameter attr-name">/t</span> <span class="token number">3</span> <span class="token parameter attr-name">/nobreak</span> &gt;nul</span><span class="token command"><span class="token keyword">rmdir</span> <span class="token parameter attr-name">/s</span> <span class="token parameter attr-name">/q</span> <span class="token string">"%tempUploadDir%"</span></span></code></pre><p><strong>设计考虑</strong>：</p><ul><li><code>start</code>：在新窗口中执行命令，实现并发部署</li><li><code>timeout</code>：等待命令启动后再清理资源</li><li><code>/nobreak</code>：防止用户按键中断等待</li><li><code>/s /q</code>：静默递归删除临时目录</li></ul><h2 id="🎨-用户体验优化"><a href="#🎨-用户体验优化" class="headerlink" title="🎨 用户体验优化"></a>🎨 用户体验优化</h2><h3 id="1-友好的交互界面"><a href="#1-友好的交互界面" class="headerlink" title="1. 友好的交互界面"></a>1. 友好的交互界面</h3><pre class="language-batch" data-language="batch"><code class="language-batch"><span class="token command"><span class="token keyword">echo</span>.</span><span class="token command"><span class="token keyword">echo</span> 解析结果:</span><span class="token command"><span class="token keyword">echo</span>   GroupId: <span class="token variable">%groupId%</span></span><span class="token command"><span class="token keyword">echo</span>   ArtifactId: <span class="token variable">%artifactId%</span></span><span class="token command"><span class="token keyword">echo</span>   Version: <span class="token variable">%version%</span></span><span class="token command"><span class="token keyword">echo</span>   文件路径: <span class="token variable">%filepath%</span></span><span class="token command"><span class="token keyword">echo</span>.</span><span class="token command"><span class="token keyword">set</span> <span class="token parameter attr-name">/p</span> "<span class="token variable">confirm</span><span class="token operator">=</span>是否继续上传到Maven仓库? <span class="token punctuation">(</span>y<span class="token parameter attr-name">/N</span></span><span class="token punctuation">)</span>: "<span class="token command"><span class="token keyword">if</span> <span class="token parameter attr-name">/i</span> <span class="token keyword">not</span> <span class="token string">"%confirm%"</span><span class="token operator">==</span><span class="token string">"y"</span></span> <span class="token punctuation">(</span>    <span class="token command"><span class="token keyword">echo</span> 取消上传</span>    <span class="token command"><span class="token keyword">exit</span> <span class="token parameter attr-name">/b</span> <span class="token number">0</span></span><span class="token punctuation">)</span></code></pre><h3 id="2-彩色状态输出"><a href="#2-彩色状态输出" class="headerlink" title="2. 彩色状态输出"></a>2. 彩色状态输出</h3><p>PowerShell 部分使用了颜色输出：</p><ul><li>绿色：成功信息（<code>-ForegroundColor Green</code>）</li><li>黄色：警告信息（<code>-ForegroundColor Yellow</code>）</li></ul><h2 id="📋-配置参数详解"><a href="#📋-配置参数详解" class="headerlink" title="📋 配置参数详解"></a>📋 配置参数详解</h2><table><thead><tr><th>参数</th><th>作用</th><th>示例值</th></tr></thead><tbody><tr><td><code>chcp 65001</code></td><td>设置 UTF-8 编码</td><td>解决中文乱码</td></tr><tr><td><code>enabledelayedexpansion</code></td><td>启用延迟变量扩展</td><td>支持动态变量修改</td></tr><tr><td><code>-NoProfile</code></td><td>跳过 PowerShell 配置文件</td><td>提升启动速度</td></tr><tr><td><code>-ExecutionPolicy Bypass</code></td><td>绕过执行策略</td><td>确保脚本能够执行</td></tr><tr><td><code>%RANDOM%</code></td><td>生成随机数</td><td>创建唯一临时目录</td></tr><tr><td><code>-Dmaven.test.skip=true</code></td><td>跳过测试</td><td>加快部署速度</td></tr><tr><td><code>-DrepositoryId</code></td><td>仓库标识</td><td>关联 settings.xml 认证</td></tr></tbody></table><h2 id="⚡-性能与安全特性"><a href="#⚡-性能与安全特性" class="headerlink" title="⚡ 性能与安全特性"></a>⚡ 性能与安全特性</h2><h3 id="1-性能优化"><a href="#1-性能优化" class="headerlink" title="1. 性能优化"></a>1. 性能优化</h3><ul><li><strong>并发部署</strong>：同时向多个仓库部署，节省时间</li><li><strong>临时文件机制</strong>：避免修改原始文件</li><li><strong>资源自动清理</strong>：防止磁盘空间浪费</li></ul><h3 id="2-安全特性"><a href="#2-安全特性" class="headerlink" title="2. 安全特性"></a>2. 安全特性</h3><ul><li><strong>参数验证</strong>：防止恶意输入</li><li><strong>文件类型检查</strong>：确保只处理 JAR 文件</li><li><strong>临时目录隔离</strong>：避免文件冲突</li><li><strong>错误处理</strong>：优雅处理各种异常情况</li></ul><h2 id="🎯-使用效果"><a href="#🎯-使用效果" class="headerlink" title="🎯 使用效果"></a>🎯 使用效果</h2><h3 id="使用前（手动操作）："><a href="#使用前（手动操作）：" class="headerlink" title="使用前（手动操作）："></a>使用前（手动操作）：</h3><ol><li>手动解压 JAR 包查看 META-INF 信息</li><li>记录 groupId、artifactId、version</li><li> 构造复杂的 Maven 命令</li><li>分别执行多个部署命令</li><li>手动处理编码问题</li></ol><h3 id="使用后（一键完成）："><a href="#使用后（一键完成）：" class="headerlink" title="使用后（一键完成）："></a>使用后（一键完成）：</h3><pre class="language-cmd" data-language="cmd"><code class="language-cmd">upload-jar.cmd "C:\path\to\test-api-1.1.3.jar"</code></pre><p><strong>输出示例</strong>：</p><pre class="language-none"><code class="language-none">正在解析JAR文件: C:\path\to\test-api-1.1.3.jarSUCCESS: pom.properties found找到对应的POM文件: C:\path\to\test-api-1.1.3.pom已复制POM文件到临时目录解析结果:  GroupId: com.example  ArtifactId: test-api    Version: 1.1.3  文件路径: C:\path\to\test-api-1.1.3.jar是否继续上传到Maven仓库? (y/N): y开始上传到Maven仓库...已复制JAR文件到临时目录上传到仓库1: http://repo1.example.com/repository/maven-releases上传到仓库2: http://repo2.example.com/repository/maven-releases清理临时文件...上传命令已启动，请查看弹出的命令行窗口获取上传结果。</code></pre><h2 id="🚀-扩展建议"><a href="#🚀-扩展建议" class="headerlink" title="🚀 扩展建议"></a>🚀 扩展建议</h2><ol><li><strong>配置文件支持</strong>：将仓库地址提取到配置文件</li><li><strong>日志记录</strong>：添加详细的操作日志</li><li><strong>批量处理</strong>：支持一次处理多个 JAR 文件</li><li><strong> GUI 界面</strong>：开发图形用户界面</li><li><strong> Jenkins 集成</strong>：作为 CI/CD 流水线的一部分</li></ol><h2 id="📝-总结"><a href="#📝-总结" class="headerlink" title="📝 总结"></a>📝 总结</h2><p>这个自动化部署脚本通过巧妙结合批处理、PowerShell 等技术，完美解决了 Maven JAR 包部署过程中的各种痛点。它不仅提升了开发效率，还减少了人为错误，是 DevOps 自动化的一个优秀实践案例。</p><p><strong>关键技术收获</strong>：</p><ul><li>批处理与 PowerShell 的混合编程技巧</li><li> Maven 部署机制的深度理解</li><li>文件系统操作的安全实践</li><li>用户体验设计的重要性</li></ul><p>通过这个项目，我们可以看到，即使是看似简单的自动化任务，也蕴含着丰富的技术细节和设计思考。好的工具不仅要解决问题，更要让使用者感到愉悦。</p>]]></content>
    
    
    <summary type="html">&lt;h2 id=&quot;📖-背景介绍&quot;&gt;&lt;a href=&quot;#📖-背景介绍&quot; class=&quot;headerlink&quot; title=&quot;📖 背景介绍&quot;&gt;&lt;/a&gt;📖 背景介绍&lt;/h2&gt;&lt;p&gt;在 Java 开发过程中，我们经常需要将本地构建的 JAR 包部署到私有 Maven 仓库中，以便团队成员使用。&lt;/p&gt;
&lt;p&gt;然而，手动部署过程繁琐且容易出错：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需要手动提取 JAR 包中的 Maven 元数据信息&lt;/li&gt;
&lt;li&gt;需要记住复杂的 Maven 部署命令&lt;/li&gt;
&lt;li&gt; Maven 默认禁止从本地仓库直接部署到远程仓库&lt;/li&gt;
&lt;li&gt;中文环境下容易出现编码问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为了解决这些痛点，我开发了一个自动化的批处理脚本，能够智能解析 JAR 包信息并自动部署到多个 Maven 仓库。&lt;/p&gt;</summary>
    
    
    
    <category term="OS" scheme="https://jueee.github.io/categories/OS/"/>
    
    <category term="Shell" scheme="https://jueee.github.io/categories/OS/Shell/"/>
    
    
    <category term="OS" scheme="https://jueee.github.io/tags/OS/"/>
    
    <category term="Shell" scheme="https://jueee.github.io/tags/Shell/"/>
    
  </entry>
  
  <entry>
    <title>前端用户行为数据收集与 Kafka 集成的技术实践</title>
    <link href="https://jueee.github.io/2026/01/2026-01-09-%E5%89%8D%E7%AB%AF%E7%94%A8%E6%88%B7%E8%A1%8C%E4%B8%BA%E6%95%B0%E6%8D%AE%E6%94%B6%E9%9B%86%E4%B8%8EKafka%E9%9B%86%E6%88%90%E7%9A%84%E6%8A%80%E6%9C%AF%E5%AE%9E%E8%B7%B5/"/>
    <id>https://jueee.github.io/2026/01/2026-01-09-%E5%89%8D%E7%AB%AF%E7%94%A8%E6%88%B7%E8%A1%8C%E4%B8%BA%E6%95%B0%E6%8D%AE%E6%94%B6%E9%9B%86%E4%B8%8EKafka%E9%9B%86%E6%88%90%E7%9A%84%E6%8A%80%E6%9C%AF%E5%AE%9E%E8%B7%B5/</id>
    <published>2026-01-09T00:00:00.000Z</published>
    <updated>2026-01-21T01:52:07.420Z</updated>
    
    <content type="html"><![CDATA[<p>在现代 Web 应用中，用户行为数据收集是产品优化和业务分析的重要环节。</p><p>本文将详细介绍如何在前端收集用户操作数据，并通过后端 API 安全地发送到 Kafka 消息队列中，实现实时数据流处理。</p><a id="more"></a><h2 id="技术背景"><a href="#技术背景" class="headerlink" title="技术背景"></a>技术背景</h2><h3 id="为什么不能在前端直接连接Kafka？"><a href="#为什么不能在前端直接连接Kafka？" class="headerlink" title="为什么不能在前端直接连接Kafka？"></a>为什么不能在前端直接连接 Kafka？</h3><p>很多开发者可能会问：既然要发送数据到 Kafka，为什么不在前端直接连接 Kafka 呢？</p><p>这主要有以下几个重要原因：</p><h4 id="1-安全性问题"><a href="#1-安全性问题" class="headerlink" title="1. 安全性问题"></a>1. 安全性问题</h4><ul><li><strong>凭据暴露风险</strong>：Kafka 连接需要 broker 地址、认证信息等敏感配置，这些信息在前端代码中完全暴露</li><li><strong>无法进行访问控制</strong>：前端无法实现细粒度的权限控制和数据验证</li><li><strong>跨域限制</strong>：浏览器的 CORS 策略会阻止直接连接到 Kafka 集群</li></ul><h4 id="2-网络架构限制"><a href="#2-网络架构限制" class="headerlink" title="2. 网络架构限制"></a>2. 网络架构限制</h4><ul><li><strong>防火墙和网络隔离</strong>：生产环境中 Kafka 集群通常在内网，前端无法直接访问</li><li><strong>负载均衡复杂性</strong>：Kafka 集群的负载均衡机制不适合直接暴露给前端</li></ul><h4 id="3-性能和可靠性"><a href="#3-性能和可靠性" class="headerlink" title="3. 性能和可靠性"></a>3. 性能和可靠性</h4><ul><li><strong>连接管理</strong>：每个用户都直连 Kafka 会产生大量连接，影响集群性能</li><li><strong>数据一致性</strong>：缺少服务端验证和数据清洗环节</li><li><strong>错误处理</strong>：前端无法处理复杂的重试和容错逻辑</li></ul><h3 id="推荐架构：前端-→-API-Gateway-→-Kafka"><a href="#推荐架构：前端-→-API-Gateway-→-Kafka" class="headerlink" title="推荐架构：前端 → API Gateway → Kafka"></a>推荐架构：前端 → API Gateway → Kafka</h3><pre class="language-none"><code class="language-none">前端应用 → 后端API → Kafka集群 → 数据处理服务</code></pre><p>这种架构的优势：</p><ul><li>✅ 安全：敏感配置保存在服务端</li><li>✅ 可控：统一的数据验证和格式化</li><li>✅ 高效：连接复用和批量处理</li><li>✅ 可维护：集中的错误处理和监控</li></ul><h2 id="前端实现"><a href="#前端实现" class="headerlink" title="前端实现"></a>前端实现</h2><h3 id="1-创建数据收集工具类"><a href="#1-创建数据收集工具类" class="headerlink" title="1. 创建数据收集工具类"></a>1. 创建数据收集工具类</h3><p>首先创建一个专门的工具类来处理用户行为数据的收集和发送：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// src/utils/userDataCollector.js</span><span class="token keyword">import</span> axios <span class="token keyword">from</span> <span class="token string">'axios'</span><span class="token punctuation">;</span><span class="token comment">/** * 用户数据收集工具类 * 通过后端API发送用户行为数据到消息队列 */</span><span class="token keyword">class</span> <span class="token class-name">UserDataCollector</span> <span class="token punctuation">{</span>  <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token comment">// 前端通过API调用，无需消息队列配置</span>  <span class="token punctuation">}</span>  <span class="token comment">/**   * 通用的数据发送方法   * @param {string} topic - 数据主题   * @param {Object|string} data - 要发送的数据   * @param {string} key - 数据标识（可选）   */</span>  <span class="token keyword">async</span> <span class="token function">sendData</span><span class="token punctuation">(</span><span class="token parameter">topic<span class="token punctuation">,</span> data<span class="token punctuation">,</span> key <span class="token operator">=</span> <span class="token keyword">null</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">try</span> <span class="token punctuation">{</span>      <span class="token keyword">const</span> dataString <span class="token operator">=</span> <span class="token keyword">typeof</span> data <span class="token operator">===</span> <span class="token string">'string'</span> <span class="token operator">?</span> data <span class="token operator">:</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">sendViaAPI</span><span class="token punctuation">(</span><span class="token punctuation">{</span>        topic<span class="token operator">:</span> topic<span class="token punctuation">,</span>        message<span class="token operator">:</span> dataString<span class="token punctuation">,</span>        key<span class="token operator">:</span> key      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token keyword">if</span> <span class="token punctuation">(</span>process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">NODE_ENV</span> <span class="token operator">===</span> <span class="token string">'development'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">数据已发送到主题[</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>topic<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">]:</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> data<span class="token punctuation">)</span><span class="token punctuation">;</span>      <span class="token punctuation">}</span>            <span class="token keyword">return</span> response<span class="token punctuation">;</span>    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>      console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">发送数据到主题[</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>topic<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">]失败:</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span>      <span class="token comment">// 发送失败不影响主要业务流程</span>      <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>  <span class="token punctuation">}</span>  <span class="token comment">/**   * 发送用户操作数据   * @param {Object} actionInfo - 操作信息对象   * @param {string} actionInfo.actionId - 操作ID   * @param {string} actionInfo.module - 模块名称   * @param {string} actionInfo.userId - 用户ID   * @param {number} actionInfo.timestamp - 时间戳   * @param {string} topic - 自定义主题（可选）   */</span>  <span class="token keyword">async</span> <span class="token function">sendUserAction</span><span class="token punctuation">(</span>actionInfo<span class="token punctuation">,</span> topic <span class="token operator">=</span> <span class="token string">'user-behavior'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">const</span> message <span class="token operator">=</span> <span class="token punctuation">{</span>      actionId<span class="token operator">:</span> actionInfo<span class="token punctuation">.</span>actionId<span class="token punctuation">,</span>      module<span class="token operator">:</span> actionInfo<span class="token punctuation">.</span>module<span class="token punctuation">,</span>      userId<span class="token operator">:</span> actionInfo<span class="token punctuation">.</span>userId<span class="token punctuation">,</span>      timestamp<span class="token operator">:</span> actionInfo<span class="token punctuation">.</span>timestamp<span class="token punctuation">,</span>      eventType<span class="token operator">:</span> <span class="token string">'user_action'</span><span class="token punctuation">,</span>      source<span class="token operator">:</span> <span class="token string">'web_frontend'</span><span class="token punctuation">,</span>      sessionId<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getSessionId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>      userAgent<span class="token operator">:</span> navigator<span class="token punctuation">.</span>userAgent    <span class="token punctuation">}</span><span class="token punctuation">;</span>    <span class="token keyword">return</span> <span class="token keyword">await</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">sendData</span><span class="token punctuation">(</span>topic<span class="token punctuation">,</span> message<span class="token punctuation">,</span> actionInfo<span class="token punctuation">.</span>userId<span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token punctuation">}</span>  <span class="token comment">/**   * 通过后端API发送数据   */</span>  <span class="token keyword">async</span> <span class="token function">sendViaAPI</span><span class="token punctuation">(</span><span class="token parameter">payload</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">try</span> <span class="token punctuation">{</span>      <span class="token keyword">return</span> <span class="token keyword">await</span> axios<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/api/datasync/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>payload<span class="token punctuation">.</span>topic<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> payload<span class="token punctuation">.</span>message<span class="token punctuation">,</span> <span class="token punctuation">{</span>        headers<span class="token operator">:</span> <span class="token punctuation">{</span>          <span class="token string">'Content-Type'</span><span class="token operator">:</span> <span class="token string">'application/json'</span>        <span class="token punctuation">}</span>      <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>      <span class="token keyword">if</span> <span class="token punctuation">(</span>process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">NODE_ENV</span> <span class="token operator">===</span> <span class="token string">'development'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        console<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">数据发送接口暂不可用，主题: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>payload<span class="token punctuation">.</span>topic<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">, 数据:</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> payload<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>      <span class="token punctuation">}</span>      <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>  <span class="token punctuation">}</span>  <span class="token comment">/**   * 获取会话ID   */</span>  <span class="token function">getSessionId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">let</span> sessionId <span class="token operator">=</span> sessionStorage<span class="token punctuation">.</span><span class="token function">getItem</span><span class="token punctuation">(</span><span class="token string">'sessionId'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>sessionId<span class="token punctuation">)</span> <span class="token punctuation">{</span>      sessionId <span class="token operator">=</span> <span class="token string">'session_'</span> <span class="token operator">+</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">'_'</span> <span class="token operator">+</span> Math<span class="token punctuation">.</span><span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token number">36</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">substr</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">)</span><span class="token punctuation">;</span>      sessionStorage<span class="token punctuation">.</span><span class="token function">setItem</span><span class="token punctuation">(</span><span class="token string">'sessionId'</span><span class="token punctuation">,</span> sessionId<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>    <span class="token keyword">return</span> sessionId<span class="token punctuation">;</span>  <span class="token punctuation">}</span>  <span class="token comment">/**   * 批量发送数据   */</span>  <span class="token keyword">async</span> <span class="token function">sendBatchData</span><span class="token punctuation">(</span><span class="token parameter">topic<span class="token punctuation">,</span> dataList<span class="token punctuation">,</span> keyExtractor <span class="token operator">=</span> <span class="token keyword">null</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">const</span> promises <span class="token operator">=</span> dataList<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">data<span class="token punctuation">,</span> index</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>      <span class="token keyword">const</span> key <span class="token operator">=</span> keyExtractor <span class="token operator">?</span> <span class="token function">keyExtractor</span><span class="token punctuation">(</span>data<span class="token punctuation">,</span> index<span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">;</span>      <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">sendData</span><span class="token punctuation">(</span>topic<span class="token punctuation">,</span> data<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">return</span> <span class="token keyword">await</span> Promise<span class="token punctuation">.</span><span class="token function">allSettled</span><span class="token punctuation">(</span>promises<span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">// 导出单例实例</span><span class="token keyword">let</span> instance <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span><span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">getUserDataCollector</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>instance<span class="token punctuation">)</span> <span class="token punctuation">{</span>    instance <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">UserDataCollector</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token punctuation">}</span>  <span class="token keyword">return</span> instance<span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>  getUserDataCollector<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre><h3 id="2-在Vue组件中使用"><a href="#2-在Vue组件中使用" class="headerlink" title="2. 在Vue组件中使用"></a>2. 在 Vue 组件中使用</h3><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// src/App.vue</span><span class="token operator">&lt;</span>template<span class="token operator">&gt;</span>  <span class="token operator">&lt;</span>div id<span class="token operator">=</span><span class="token string">"app"</span><span class="token operator">&gt;</span>    <span class="token operator">&lt;</span><span class="token operator">!</span><span class="token operator">--</span> 应用内容 <span class="token operator">--</span><span class="token operator">&gt;</span>  <span class="token operator">&lt;</span><span class="token operator">/</span>div<span class="token operator">&gt;</span><span class="token operator">&lt;</span><span class="token operator">/</span>template<span class="token operator">&gt;</span><span class="token operator">&lt;</span>script<span class="token operator">&gt;</span><span class="token keyword">import</span> <span class="token punctuation">{</span> getUserDataCollector <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@/utils/userDataCollector'</span><span class="token punctuation">;</span><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>  name<span class="token operator">:</span> <span class="token string">'App'</span><span class="token punctuation">,</span>  <span class="token keyword">async</span> <span class="token function">created</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token comment">// 应用启动时发送用户访问数据</span>    <span class="token keyword">await</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">sendUserVisitInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token punctuation">}</span><span class="token punctuation">,</span>  methods<span class="token operator">:</span> <span class="token punctuation">{</span>    <span class="token keyword">async</span> <span class="token function">sendUserVisitInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>      <span class="token keyword">const</span> collector <span class="token operator">=</span> <span class="token function">getUserDataCollector</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token comment">// 从路由获取页面信息</span>      <span class="token keyword">const</span> pageInfo <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$route<span class="token punctuation">.</span>query<span class="token punctuation">.</span>page <span class="token operator">||</span> <span class="token string">'dashboard'</span><span class="token punctuation">;</span>      <span class="token keyword">const</span> moduleInfo <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$route<span class="token punctuation">.</span>query<span class="token punctuation">.</span>module <span class="token operator">||</span> <span class="token string">'main'</span><span class="token punctuation">;</span>            <span class="token comment">// 从状态管理获取用户信息</span>      <span class="token keyword">const</span> userInfo <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>$store<span class="token punctuation">.</span>state<span class="token punctuation">.</span>user <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>            <span class="token comment">// 构建用户访问数据</span>      <span class="token keyword">const</span> visitData <span class="token operator">=</span> <span class="token punctuation">{</span>        actionId<span class="token operator">:</span> pageInfo<span class="token punctuation">,</span>        module<span class="token operator">:</span> moduleInfo<span class="token punctuation">,</span>        userId<span class="token operator">:</span> userInfo<span class="token punctuation">.</span>id <span class="token operator">||</span> <span class="token string">'anonymous'</span><span class="token punctuation">,</span>        timestamp<span class="token operator">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span>      <span class="token punctuation">}</span><span class="token punctuation">;</span>      <span class="token keyword">try</span> <span class="token punctuation">{</span>        <span class="token keyword">await</span> collector<span class="token punctuation">.</span><span class="token function">sendUserAction</span><span class="token punctuation">(</span>visitData<span class="token punctuation">,</span> <span class="token string">'page-visit-log'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'用户访问信息已记录'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>      <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>        console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'发送用户访问信息失败:'</span><span class="token punctuation">,</span> error<span class="token punctuation">)</span><span class="token punctuation">;</span>      <span class="token punctuation">}</span>    <span class="token punctuation">}</span>  <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token operator">&lt;</span><span class="token operator">/</span>script<span class="token operator">&gt;</span></code></pre><h3 id="3-路由级别的数据收集"><a href="#3-路由级别的数据收集" class="headerlink" title="3. 路由级别的数据收集"></a>3. 路由级别的数据收集</h3><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// src/router/index.js</span><span class="token keyword">import</span> <span class="token punctuation">{</span> getUserDataCollector <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@/utils/userDataCollector'</span><span class="token punctuation">;</span><span class="token keyword">const</span> router <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">VueRouter</span><span class="token punctuation">(</span><span class="token punctuation">{</span>  routes<span class="token operator">:</span> <span class="token punctuation">[</span>    <span class="token comment">// 路由配置</span>  <span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 路由守卫中收集页面访问数据</span>router<span class="token punctuation">.</span><span class="token function">afterEach</span><span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token punctuation">(</span><span class="token parameter">to<span class="token punctuation">,</span> <span class="token keyword">from</span></span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>  <span class="token keyword">const</span> collector <span class="token operator">=</span> <span class="token function">getUserDataCollector</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">const</span> navigationData <span class="token operator">=</span> <span class="token punctuation">{</span>    actionId<span class="token operator">:</span> to<span class="token punctuation">.</span>name <span class="token operator">||</span> to<span class="token punctuation">.</span>path<span class="token punctuation">,</span>    module<span class="token operator">:</span> to<span class="token punctuation">.</span>meta<span class="token operator">?.</span>module <span class="token operator">||</span> <span class="token string">'unknown'</span><span class="token punctuation">,</span>    userId<span class="token operator">:</span> store<span class="token punctuation">.</span>state<span class="token punctuation">.</span>user<span class="token operator">?.</span>id <span class="token operator">||</span> <span class="token string">'anonymous'</span><span class="token punctuation">,</span>    timestamp<span class="token operator">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>    fromPage<span class="token operator">:</span> <span class="token keyword">from</span><span class="token punctuation">.</span>name <span class="token operator">||</span> <span class="token keyword">from</span><span class="token punctuation">.</span>path<span class="token punctuation">,</span>    toPage<span class="token operator">:</span> to<span class="token punctuation">.</span>name <span class="token operator">||</span> to<span class="token punctuation">.</span>path  <span class="token punctuation">}</span><span class="token punctuation">;</span>  <span class="token keyword">await</span> collector<span class="token punctuation">.</span><span class="token function">sendUserAction</span><span class="token punctuation">(</span>navigationData<span class="token punctuation">,</span> <span class="token string">'navigation-log'</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">export</span> <span class="token keyword">default</span> router<span class="token punctuation">;</span></code></pre><h2 id="后端实现"><a href="#后端实现" class="headerlink" title="后端实现"></a>后端实现</h2><h3 id="1-数据同步控制器"><a href="#1-数据同步控制器" class="headerlink" title="1. 数据同步控制器"></a>1. 数据同步控制器</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>api<span class="token punctuation">.</span>controller</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>system<span class="token punctuation">.</span>bean<span class="token punctuation">.</span></span><span class="token class-name">ResponseBean</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>service<span class="token punctuation">.</span></span><span class="token class-name">MessageProducer</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">lombok<span class="token punctuation">.</span></span><span class="token class-name">RequiredArgsConstructor</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">lombok<span class="token punctuation">.</span>extern<span class="token punctuation">.</span>slf4j<span class="token punctuation">.</span></span><span class="token class-name">Slf4j</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>bind<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span>UUID<span class="token punctuation">;</span><span class="token annotation punctuation">@Slf4j</span><span class="token annotation punctuation">@RestController</span><span class="token annotation punctuation">@RequiredArgsConstructor</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DataSyncController</span> <span class="token punctuation">{</span>    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">MessageProducer</span> messageProducer<span class="token punctuation">;</span>    <span class="token annotation punctuation">@PostMapping</span><span class="token punctuation">(</span><span class="token string">"/api/datasync/{topicName}"</span><span class="token punctuation">)</span>    <span class="token keyword">public</span> <span class="token class-name">ResponseBean</span> <span class="token function">syncData</span><span class="token punctuation">(</span><span class="token annotation punctuation">@PathVariable</span> <span class="token class-name">String</span> topicName<span class="token punctuation">,</span>                                 <span class="token annotation punctuation">@RequestBody</span> <span class="token class-name">String</span> dataJson<span class="token punctuation">)</span> <span class="token punctuation">{</span>        log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"接收数据同步请求 - 主题:{}, 数据:{}"</span><span class="token punctuation">,</span> topicName<span class="token punctuation">,</span> dataJson<span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token keyword">try</span> <span class="token punctuation">{</span>            <span class="token comment">// 数据验证</span>            <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">isValidTopic</span><span class="token punctuation">(</span>topicName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                <span class="token keyword">return</span> <span class="token class-name">ResponseBean</span><span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"无效的数据主题"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token punctuation">}</span>                        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">isValidJson</span><span class="token punctuation">(</span>dataJson<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                <span class="token keyword">return</span> <span class="token class-name">ResponseBean</span><span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"数据格式错误"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token punctuation">}</span>                        <span class="token comment">// 发送到消息队列</span>            <span class="token class-name">String</span> messageKey <span class="token operator">=</span> UUID<span class="token punctuation">.</span><span class="token function">randomUUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            messageProducer<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>topicName<span class="token punctuation">,</span> messageKey<span class="token punctuation">,</span> dataJson<span class="token punctuation">)</span><span class="token punctuation">;</span>                        <span class="token comment">// 记录统计信息</span>            <span class="token function">recordMetrics</span><span class="token punctuation">(</span>topicName<span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                        <span class="token keyword">return</span> <span class="token class-name">ResponseBean</span><span class="token punctuation">.</span><span class="token function">success</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>            log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"数据同步失败 - 主题:{}, 错误:{}"</span><span class="token punctuation">,</span> topicName<span class="token punctuation">,</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token function">recordMetrics</span><span class="token punctuation">(</span>topicName<span class="token punctuation">,</span> <span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token keyword">return</span> <span class="token class-name">ResponseBean</span><span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"数据同步失败"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span>    <span class="token punctuation">}</span>        <span class="token keyword">private</span> <span class="token keyword">boolean</span> <span class="token function">isValidTopic</span><span class="token punctuation">(</span><span class="token class-name">String</span> topicName<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token comment">// 验证主题名称是否在允许列表中</span>        <span class="token keyword">return</span> topicName<span class="token punctuation">.</span><span class="token function">matches</span><span class="token punctuation">(</span><span class="token string">"^[a-zA-Z0-9\\-_]+$"</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>                topicName<span class="token punctuation">.</span><span class="token function">length</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&lt;=</span> <span class="token number">50</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>        <span class="token keyword">private</span> <span class="token keyword">boolean</span> <span class="token function">isValidJson</span><span class="token punctuation">(</span><span class="token class-name">String</span> json<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token comment">// 验证JSON格式</span>        <span class="token keyword">try</span> <span class="token punctuation">{</span>            <span class="token comment">// 可以使用Jackson或其他JSON库进行验证</span>            <span class="token keyword">return</span> json <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>json<span class="token punctuation">.</span><span class="token function">trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>            <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span>    <span class="token punctuation">}</span>        <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">recordMetrics</span><span class="token punctuation">(</span><span class="token class-name">String</span> topicName<span class="token punctuation">,</span> <span class="token keyword">boolean</span> success<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token comment">// 记录监控指标</span>        <span class="token comment">// 例如：成功/失败次数、响应时间等</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h3 id="2-消息生产者服务"><a href="#2-消息生产者服务" class="headerlink" title="2. 消息生产者服务"></a>2. 消息生产者服务</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>service</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">lombok<span class="token punctuation">.</span>extern<span class="token punctuation">.</span>slf4j<span class="token punctuation">.</span></span><span class="token class-name">Slf4j</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>stereotype<span class="token punctuation">.</span></span><span class="token class-name">Service</span><span class="token punctuation">;</span><span class="token annotation punctuation">@Slf4j</span><span class="token annotation punctuation">@Service</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MessageProducer</span> <span class="token punctuation">{</span>        <span class="token comment">// 注入Kafka生产者或其他消息队列客户端</span>        <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">send</span><span class="token punctuation">(</span><span class="token class-name">String</span> topic<span class="token punctuation">,</span> <span class="token class-name">String</span> key<span class="token punctuation">,</span> <span class="token class-name">String</span> message<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">try</span> <span class="token punctuation">{</span>            <span class="token comment">// 发送到消息队列的具体实现</span>            <span class="token comment">// kafkaTemplate.send(topic, key, message);</span>            log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"消息已发送 - 主题:{}, 键:{}"</span><span class="token punctuation">,</span> topic<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>            log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"发送消息失败 - 主题:{}, 错误:{}"</span><span class="token punctuation">,</span> topic<span class="token punctuation">,</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token keyword">throw</span> e<span class="token punctuation">;</span>        <span class="token punctuation">}</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h2 id="最佳实践"><a href="#最佳实践" class="headerlink" title="最佳实践"></a>最佳实践</h2><h3 id="1-错误处理策略"><a href="#1-错误处理策略" class="headerlink" title="1. 错误处理策略"></a>1. 错误处理策略</h3><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 前端错误处理</span><span class="token keyword">class</span> <span class="token class-name">UserDataCollector</span> <span class="token punctuation">{</span>  <span class="token keyword">async</span> <span class="token function">sendData</span><span class="token punctuation">(</span><span class="token parameter">topic<span class="token punctuation">,</span> data<span class="token punctuation">,</span> key <span class="token operator">=</span> <span class="token keyword">null</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">try</span> <span class="token punctuation">{</span>      <span class="token keyword">return</span> <span class="token keyword">await</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">sendViaAPI</span><span class="token punctuation">(</span><span class="token punctuation">{</span>topic<span class="token punctuation">,</span> message<span class="token operator">:</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">,</span> key<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>      <span class="token comment">// 静默失败，不影响用户体验</span>      <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">handleError</span><span class="token punctuation">(</span>error<span class="token punctuation">,</span> topic<span class="token punctuation">,</span> data<span class="token punctuation">)</span><span class="token punctuation">;</span>      <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>  <span class="token punctuation">}</span>    <span class="token function">handleError</span><span class="token punctuation">(</span><span class="token parameter">error<span class="token punctuation">,</span> topic<span class="token punctuation">,</span> data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token comment">// 本地存储失败的数据，后续重试</span>    <span class="token keyword">const</span> failedData <span class="token operator">=</span> <span class="token punctuation">{</span>      topic<span class="token punctuation">,</span>      data<span class="token punctuation">,</span>      timestamp<span class="token operator">:</span> Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>      error<span class="token operator">:</span> error<span class="token punctuation">.</span>message    <span class="token punctuation">}</span><span class="token punctuation">;</span>        <span class="token keyword">const</span> failures <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>localStorage<span class="token punctuation">.</span><span class="token function">getItem</span><span class="token punctuation">(</span><span class="token string">'failed_data'</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token string">'[]'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    failures<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>failedData<span class="token punctuation">)</span><span class="token punctuation">;</span>    localStorage<span class="token punctuation">.</span><span class="token function">setItem</span><span class="token punctuation">(</span><span class="token string">'failed_data'</span><span class="token punctuation">,</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>failures<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token comment">// 定期重试逻辑</span>    <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">scheduleRetry</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h3 id="2-性能优化"><a href="#2-性能优化" class="headerlink" title="2. 性能优化"></a>2. 性能优化</h3><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 批量发送和防抖</span><span class="token keyword">class</span> <span class="token class-name">UserDataCollector</span> <span class="token punctuation">{</span>  <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">this</span><span class="token punctuation">.</span>buffer <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>    <span class="token keyword">this</span><span class="token punctuation">.</span>batchSize <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>    <span class="token keyword">this</span><span class="token punctuation">.</span>flushInterval <span class="token operator">=</span> <span class="token number">5000</span><span class="token punctuation">;</span> <span class="token comment">// 5秒</span>        <span class="token comment">// 定期刷新缓冲区</span>    <span class="token function">setInterval</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">flush</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>flushInterval<span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token punctuation">}</span>    <span class="token keyword">async</span> <span class="token function">sendData</span><span class="token punctuation">(</span><span class="token parameter">topic<span class="token punctuation">,</span> data<span class="token punctuation">,</span> key <span class="token operator">=</span> <span class="token keyword">null</span></span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token comment">// 添加到缓冲区</span>    <span class="token keyword">this</span><span class="token punctuation">.</span>buffer<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token punctuation">{</span>topic<span class="token punctuation">,</span> data<span class="token punctuation">,</span> key<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token comment">// 达到批次大小时立即发送</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>buffer<span class="token punctuation">.</span>length <span class="token operator">&gt;=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>batchSize<span class="token punctuation">)</span> <span class="token punctuation">{</span>      <span class="token keyword">await</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">flush</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>  <span class="token punctuation">}</span>    <span class="token keyword">async</span> <span class="token function">flush</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>buffer<span class="token punctuation">.</span>length <span class="token operator">===</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>        <span class="token keyword">const</span> batch <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>buffer<span class="token punctuation">.</span><span class="token function">splice</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">try</span> <span class="token punctuation">{</span>      <span class="token keyword">await</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">sendBatch</span><span class="token punctuation">(</span>batch<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>      <span class="token comment">// 批次发送失败，重新加入缓冲区</span>      <span class="token keyword">this</span><span class="token punctuation">.</span>buffer<span class="token punctuation">.</span><span class="token function">unshift</span><span class="token punctuation">(</span><span class="token operator">...</span>batch<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>  <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h3 id="3-数据脱敏"><a href="#3-数据脱敏" class="headerlink" title="3. 数据脱敏"></a>3. 数据脱敏</h3><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 敏感数据处理</span><span class="token keyword">class</span> <span class="token class-name">UserDataCollector</span> <span class="token punctuation">{</span>  <span class="token function">sanitizeData</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">const</span> sanitized <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token operator">...</span>data<span class="token punctuation">}</span><span class="token punctuation">;</span>        <span class="token comment">// 移除敏感字段</span>    <span class="token keyword">delete</span> sanitized<span class="token punctuation">.</span>password<span class="token punctuation">;</span>    <span class="token keyword">delete</span> sanitized<span class="token punctuation">.</span>token<span class="token punctuation">;</span>        <span class="token comment">// 脱敏处理</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span>sanitized<span class="token punctuation">.</span>email<span class="token punctuation">)</span> <span class="token punctuation">{</span>      sanitized<span class="token punctuation">.</span>email <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">maskEmail</span><span class="token punctuation">(</span>sanitized<span class="token punctuation">.</span>email<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span>sanitized<span class="token punctuation">.</span>phone<span class="token punctuation">)</span> <span class="token punctuation">{</span>      sanitized<span class="token punctuation">.</span>phone <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">maskPhone</span><span class="token punctuation">(</span>sanitized<span class="token punctuation">.</span>phone<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>        <span class="token keyword">return</span> sanitized<span class="token punctuation">;</span>  <span class="token punctuation">}</span>    <span class="token function">maskEmail</span><span class="token punctuation">(</span><span class="token parameter">email</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">const</span> <span class="token punctuation">[</span>name<span class="token punctuation">,</span> domain<span class="token punctuation">]</span> <span class="token operator">=</span> email<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">'@'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">const</span> maskedName <span class="token operator">=</span> name<span class="token punctuation">.</span><span class="token function">charAt</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">'***'</span> <span class="token operator">+</span> name<span class="token punctuation">.</span><span class="token function">slice</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>maskedName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">@</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>domain<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>  <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h2 id="监控和日志"><a href="#监控和日志" class="headerlink" title="监控和日志"></a>监控和日志</h2><h3 id="前端监控"><a href="#前端监控" class="headerlink" title="前端监控"></a>前端监控</h3><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// 添加性能监控</span><span class="token keyword">class</span> <span class="token class-name">UserDataCollector</span> <span class="token punctuation">{</span>  <span class="token keyword">async</span> <span class="token function">sendViaAPI</span><span class="token punctuation">(</span><span class="token parameter">payload</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">const</span> startTime <span class="token operator">=</span> performance<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">try</span> <span class="token punctuation">{</span>      <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> axios<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">/api/datasync/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>payload<span class="token punctuation">.</span>topic<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span> payload<span class="token punctuation">.</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token comment">// 记录成功指标</span>      <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">recordMetric</span><span class="token punctuation">(</span><span class="token string">'api_call_success'</span><span class="token punctuation">,</span> performance<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> startTime<span class="token punctuation">,</span> payload<span class="token punctuation">.</span>topic<span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token keyword">return</span> response<span class="token punctuation">;</span>    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>error<span class="token punctuation">)</span> <span class="token punctuation">{</span>      <span class="token comment">// 记录失败指标</span>      <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">recordMetric</span><span class="token punctuation">(</span><span class="token string">'api_call_failure'</span><span class="token punctuation">,</span> performance<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> startTime<span class="token punctuation">,</span> payload<span class="token punctuation">.</span>topic<span class="token punctuation">)</span><span class="token punctuation">;</span>      <span class="token keyword">throw</span> error<span class="token punctuation">;</span>    <span class="token punctuation">}</span>  <span class="token punctuation">}</span>    <span class="token function">recordMetric</span><span class="token punctuation">(</span><span class="token parameter">type<span class="token punctuation">,</span> duration<span class="token punctuation">,</span> topic</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token comment">// 发送到监控系统</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span>window<span class="token punctuation">.</span>performance <span class="token operator">&amp;&amp;</span> window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span>mark<span class="token punctuation">)</span> <span class="token punctuation">{</span>      window<span class="token punctuation">.</span>performance<span class="token punctuation">.</span><span class="token function">mark</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>type<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">_</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>topic<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">_</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>Date<span class="token punctuation">.</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>  <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h3 id="后端监控"><a href="#后端监控" class="headerlink" title="后端监控"></a>后端监控</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@PostMapping</span><span class="token punctuation">(</span><span class="token string">"/api/datasync/{topicName}"</span><span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token class-name">ResponseBean</span> <span class="token function">syncData</span><span class="token punctuation">(</span><span class="token annotation punctuation">@PathVariable</span> <span class="token class-name">String</span> topicName<span class="token punctuation">,</span> <span class="token annotation punctuation">@RequestBody</span> <span class="token class-name">String</span> dataJson<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">long</span> startTime <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">try</span> <span class="token punctuation">{</span>        <span class="token comment">// 业务逻辑</span>        messageProducer<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>topicName<span class="token punctuation">,</span> UUID<span class="token punctuation">.</span><span class="token function">randomUUID</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> dataJson<span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token comment">// 记录成功指标</span>        <span class="token function">recordMetrics</span><span class="token punctuation">(</span><span class="token string">"sync_success"</span><span class="token punctuation">,</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> startTime<span class="token punctuation">,</span> topicName<span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token keyword">return</span> <span class="token class-name">ResponseBean</span><span class="token punctuation">.</span><span class="token function">success</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token comment">// 记录失败指标</span>        <span class="token function">recordMetrics</span><span class="token punctuation">(</span><span class="token string">"sync_failure"</span><span class="token punctuation">,</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> startTime<span class="token punctuation">,</span> topicName<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">throw</span> e<span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>通过前后端协作的方式收集用户行为数据有以下优势：</p><ol><li><strong>安全可控</strong>：敏感配置和认证信息保存在服务端</li><li><strong>性能优化</strong>：批量处理和连接复用</li><li><strong>数据质量</strong>：统一的验证和格式化</li><li><strong>可扩展性</strong>：易于添加新的数据处理逻辑</li><li><strong>监控完善</strong>：全链路的监控和告警</li></ol><p>这种架构模式在实际项目中得到了广泛应用，能够有效支撑大规模用户行为数据的收集和处理需求。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;在现代 Web 应用中，用户行为数据收集是产品优化和业务分析的重要环节。&lt;/p&gt;
&lt;p&gt;本文将详细介绍如何在前端收集用户操作数据，并通过后端 API 安全地发送到 Kafka 消息队列中，实现实时数据流处理。&lt;/p&gt;</summary>
    
    
    
    <category term="Java" scheme="https://jueee.github.io/categories/Java/"/>
    
    <category term="JavaClass" scheme="https://jueee.github.io/categories/Java/JavaClass/"/>
    
    <category term="前端" scheme="https://jueee.github.io/categories/%E5%89%8D%E7%AB%AF/"/>
    
    <category term="Node.js" scheme="https://jueee.github.io/categories/%E5%89%8D%E7%AB%AF/Node-js/"/>
    
    
    <category term="Java" scheme="https://jueee.github.io/tags/Java/"/>
    
    <category term="JavaClass" scheme="https://jueee.github.io/tags/JavaClass/"/>
    
  </entry>
  
  <entry>
    <title>微服务架构下的熔断器模式实现与应用</title>
    <link href="https://jueee.github.io/2026/01/2026-01-08-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84%E4%B8%8B%E7%9A%84%E7%86%94%E6%96%AD%E5%99%A8%E6%A8%A1%E5%BC%8F%E5%AE%9E%E7%8E%B0%E4%B8%8E%E5%BA%94%E7%94%A8/"/>
    <id>https://jueee.github.io/2026/01/2026-01-08-%E5%BE%AE%E6%9C%8D%E5%8A%A1%E6%9E%B6%E6%9E%84%E4%B8%8B%E7%9A%84%E7%86%94%E6%96%AD%E5%99%A8%E6%A8%A1%E5%BC%8F%E5%AE%9E%E7%8E%B0%E4%B8%8E%E5%BA%94%E7%94%A8/</id>
    <published>2026-01-08T00:00:00.000Z</published>
    <updated>2026-01-08T09:42:46.598Z</updated>
    
    <content type="html"><![CDATA[<h2 id="引言"><a href="#引言" class="headerlink" title="引言"></a>引言</h2><p>在现代微服务架构中，服务间的网络调用是不可避免的。然而，网络的不稳定性和外部服务的不可靠性可能导致级联故障，最终影响整个系统的可用性。</p><p>为了解决这一问题，<strong>熔断器模式（Circuit Breaker Pattern）</strong>应运而生，它能够在检测到故障时快速失败，防止故障传播，并提供服务降级的能力。</p><p>本文将详细介绍如何实现一个通用的熔断器工具类，并展示其在实际项目中的应用。</p><h2 id="什么是熔断器模式"><a href="#什么是熔断器模式" class="headerlink" title="什么是熔断器模式"></a>什么是熔断器模式</h2><p>熔断器模式的灵感来源于电路中的断路器。当电路中的电流过大时，断路器会自动切断电路，保护电器设备不受损害。</p><p>在软件系统中，熔断器同样起到保护作用：</p><ul><li><strong>正常状态（Closed）</strong>：请求正常通过，熔断器处于关闭状态</li><li><strong>故障检测</strong>：当失败次数达到阈值时，熔断器打开</li><li><strong>熔断状态（Open）</strong>：后续请求直接返回失败，不再调用下游服务</li><li><strong>半开状态（Half-Open）</strong>：经过一定时间后，尝试少量请求来检测服务是否恢复</li></ul><h2 id="设计思路"><a href="#设计思路" class="headerlink" title="设计思路"></a>设计思路</h2><h3 id="核心需求分析"><a href="#核心需求分析" class="headerlink" title="核心需求分析"></a>核心需求分析</h3><ol><li><strong>多服务支持</strong>：一个系统中可能有多个外部服务调用，需要独立管理每个服务的熔断状态</li><li><strong>配置灵活性</strong>：不同服务可能需要不同的超时阈值和熔断时间</li><li><strong>线程安全</strong>：在高并发环境下，熔断器状态的维护必须是线程安全的</li><li><strong>监控报警</strong>：当熔断器被触发时，需要及时通知相关人员</li><li><strong>易于集成</strong>：对现有代码的侵入性要最小</li></ol><h3 id="技术选型"><a href="#技术选型" class="headerlink" title="技术选型"></a>技术选型</h3><ul><li><strong>Java 8 函数式编程</strong>：使用 <code>Supplier&lt;T&gt;</code> 接口，支持任意类型的调用封装</li><li><strong> ConcurrentHashMap</strong>：保证多服务状态管理的线程安全</li><li><strong> AtomicLong</strong>：原子性地处理计数和时间戳</li><li><strong> Volatile</strong>：确保熔断状态的可见性</li></ul><h2 id="核心实现"><a href="#核心实现" class="headerlink" title="核心实现"></a>核心实现</h2><h3 id="1-熔断器状态管理"><a href="#1-熔断器状态管理" class="headerlink" title="1. 熔断器状态管理"></a>1. 熔断器状态管理</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">CircuitBreakerState</span> <span class="token punctuation">{</span>    <span class="token keyword">private</span> <span class="token keyword">volatile</span> <span class="token keyword">boolean</span> <span class="token keyword">open</span> <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>           <span class="token comment">// 熔断器是否打开</span>    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">AtomicLong</span> startTime <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AtomicLong</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// 熔断开始时间</span>    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">AtomicLong</span> timeoutCount <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AtomicLong</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 超时次数计数</span>    <span class="token keyword">private</span> <span class="token keyword">volatile</span> <span class="token keyword">boolean</span> alertSent <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>      <span class="token comment">// 是否已发送报警</span>    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">String</span> serviceName<span class="token punctuation">;</span>                <span class="token comment">// 服务名称</span>        <span class="token keyword">public</span> <span class="token class-name">CircuitBreakerState</span><span class="token punctuation">(</span><span class="token class-name">String</span> serviceName<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">this</span><span class="token punctuation">.</span>serviceName <span class="token operator">=</span> serviceName<span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>这个内部类封装了每个服务的熔断状态，使用 <code>volatile</code> 关键字确保状态变更的可见性，<code>AtomicLong</code> 保证计数的原子性。</p><h3 id="2-配置抽象"><a href="#2-配置抽象" class="headerlink" title="2. 配置抽象"></a>2. 配置抽象</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">CircuitBreakerConfig</span> <span class="token punctuation">{</span>    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token keyword">int</span> timeoutThresholdMs<span class="token punctuation">;</span>        <span class="token comment">// 超时阈值（毫秒）</span>    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token keyword">long</span> circuitBreakerDurationMs<span class="token punctuation">;</span> <span class="token comment">// 熔断持续时间（毫秒）</span>    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token keyword">int</span> failureThreshold<span class="token punctuation">;</span>          <span class="token comment">// 失败次数阈值</span>        <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">CircuitBreakerConfig</span> <span class="token function">defaultConfig</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">CircuitBreakerConfig</span><span class="token punctuation">(</span><span class="token number">30000</span><span class="token punctuation">,</span> <span class="token number">10</span> <span class="token operator">*</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>配置类采用不可变设计，提供默认配置的同时支持自定义参数。</p><h3 id="3-核心执行逻辑"><a href="#3-核心执行逻辑" class="headerlink" title="3. 核心执行逻辑"></a>3. 核心执行逻辑</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">executeWithCircuitBreaker</span><span class="token punctuation">(</span><span class="token class-name">String</span> serviceName<span class="token punctuation">,</span>                                              <span class="token class-name">Supplier</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> httpSupplier<span class="token punctuation">,</span>                                              <span class="token class-name">CircuitBreakerConfig</span> config<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token class-name">CircuitBreakerState</span> state <span class="token operator">=</span> circuitBreakerStates<span class="token punctuation">.</span><span class="token function">computeIfAbsent</span><span class="token punctuation">(</span>serviceName<span class="token punctuation">,</span>                                                                     <span class="token class-name">CircuitBreakerState</span><span class="token operator">::</span><span class="token keyword">new</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token comment">// 检查熔断状态</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isCircuitBreakerOpen</span><span class="token punctuation">(</span>state<span class="token punctuation">,</span> config<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">"Circuit breaker is open for service: {}"</span><span class="token punctuation">,</span> serviceName<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>        <span class="token keyword">long</span> startTime <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">try</span> <span class="token punctuation">{</span>        <span class="token class-name">String</span> result <span class="token operator">=</span> httpSupplier<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">long</span> duration <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> startTime<span class="token punctuation">;</span>                <span class="token comment">// 成功调用后的处理逻辑</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span>duration <span class="token operator">&gt;</span> config<span class="token punctuation">.</span>timeoutThresholdMs<span class="token punctuation">)</span> <span class="token punctuation">{</span>            <span class="token function">handleTimeout</span><span class="token punctuation">(</span>state<span class="token punctuation">,</span> serviceName<span class="token punctuation">,</span> duration<span class="token punctuation">,</span> config<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>            <span class="token function">resetCircuitBreaker</span><span class="token punctuation">(</span>state<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span>                <span class="token keyword">return</span> result<span class="token punctuation">;</span>            <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">long</span> duration <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> startTime<span class="token punctuation">;</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span>duration <span class="token operator">&gt;</span> config<span class="token punctuation">.</span>timeoutThresholdMs<span class="token punctuation">)</span> <span class="token punctuation">{</span>            <span class="token function">handleTimeout</span><span class="token punctuation">(</span>state<span class="token punctuation">,</span> serviceName<span class="token punctuation">,</span> duration<span class="token punctuation">,</span> config<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span>        <span class="token keyword">throw</span> e<span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h3 id="4-状态转换机制"><a href="#4-状态转换机制" class="headerlink" title="4. 状态转换机制"></a>4. 状态转换机制</h3><h4 id="熔断检测"><a href="#熔断检测" class="headerlink" title="熔断检测"></a>熔断检测</h4><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">boolean</span> <span class="token function">isCircuitBreakerOpen</span><span class="token punctuation">(</span><span class="token class-name">CircuitBreakerState</span> state<span class="token punctuation">,</span> <span class="token class-name">CircuitBreakerConfig</span> config<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>state<span class="token punctuation">.</span><span class="token keyword">open</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>        <span class="token keyword">long</span> currentTime <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">long</span> elapsedTime <span class="token operator">=</span> currentTime <span class="token operator">-</span> state<span class="token punctuation">.</span>startTime<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token comment">// 检查是否到达自动恢复时间</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span>elapsedTime <span class="token operator">&gt;=</span> config<span class="token punctuation">.</span>circuitBreakerDurationMs<span class="token punctuation">)</span> <span class="token punctuation">{</span>        log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"Circuit breaker timeout period elapsed for service: {}"</span><span class="token punctuation">,</span> state<span class="token punctuation">.</span>serviceName<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token function">resetCircuitBreaker</span><span class="token punctuation">(</span>state<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>        <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h4 id="超时处理"><a href="#超时处理" class="headerlink" title="超时处理"></a>超时处理</h4><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">handleTimeout</span><span class="token punctuation">(</span><span class="token class-name">CircuitBreakerState</span> state<span class="token punctuation">,</span> <span class="token class-name">String</span> serviceName<span class="token punctuation">,</span>                                 <span class="token keyword">long</span> duration<span class="token punctuation">,</span> <span class="token class-name">CircuitBreakerConfig</span> config<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">long</span> timeouts <span class="token operator">=</span> state<span class="token punctuation">.</span>timeoutCount<span class="token punctuation">.</span><span class="token function">incrementAndGet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">"HTTP request timeout for service: {}, duration: {}ms, timeout count: {}"</span><span class="token punctuation">,</span>             serviceName<span class="token punctuation">,</span> duration<span class="token punctuation">,</span> timeouts<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span>timeouts <span class="token operator">&gt;=</span> config<span class="token punctuation">.</span>failureThreshold<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token function">triggerCircuitBreaker</span><span class="token punctuation">(</span>state<span class="token punctuation">,</span> serviceName<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h4 id="熔断触发"><a href="#熔断触发" class="headerlink" title="熔断触发"></a>熔断触发</h4><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">triggerCircuitBreaker</span><span class="token punctuation">(</span><span class="token class-name">CircuitBreakerState</span> state<span class="token punctuation">,</span> <span class="token class-name">String</span> serviceName<span class="token punctuation">)</span> <span class="token punctuation">{</span>    state<span class="token punctuation">.</span><span class="token keyword">open</span> <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>    state<span class="token punctuation">.</span>startTime<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"Circuit breaker OPENED for service: {}"</span><span class="token punctuation">,</span> serviceName<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>state<span class="token punctuation">.</span>alertSent<span class="token punctuation">)</span> <span class="token punctuation">{</span>        state<span class="token punctuation">.</span>alertSent <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span>        <span class="token function">sendAlert</span><span class="token punctuation">(</span>serviceName<span class="token punctuation">,</span> state<span class="token punctuation">.</span>timeoutCount<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h2 id="使用方式"><a href="#使用方式" class="headerlink" title="使用方式"></a>使用方式</h2><h3 id="1-基础用法"><a href="#1-基础用法" class="headerlink" title="1. 基础用法"></a>1. 基础用法</h3><p>最简单的使用方式，采用默认配置（30 秒超时，10 分钟熔断，1 次失败即触发）：</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token class-name">String</span> result <span class="token operator">=</span> <span class="token class-name">CircuitBreakerUtils</span><span class="token punctuation">.</span><span class="token function">executeWithCircuitBreaker</span><span class="token punctuation">(</span>    <span class="token string">"user-service"</span><span class="token punctuation">,</span>  <span class="token comment">// 服务标识</span>    <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token class-name">HttpClientUtils</span><span class="token punctuation">.</span><span class="token function">httpPost</span><span class="token punctuation">(</span><span class="token string">"http://user-service/api/user"</span><span class="token punctuation">,</span> userJson<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span>result <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token comment">// 熔断器打开，执行降级逻辑</span>    <span class="token keyword">return</span> <span class="token function">getDefaultUserInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h3 id="2-自定义配置"><a href="#2-自定义配置" class="headerlink" title="2. 自定义配置"></a>2. 自定义配置</h3><p>根据不同服务的特性，可以自定义熔断参数：</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token comment">// AI推理服务通常需要更长的处理时间</span><span class="token class-name">CircuitBreakerConfig</span> aiConfig <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CircuitBreakerConfig</span><span class="token punctuation">(</span>    <span class="token number">60000</span><span class="token punctuation">,</span>          <span class="token comment">// 60秒超时阈值</span>    <span class="token number">15</span> <span class="token operator">*</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">,</span> <span class="token comment">// 15分钟熔断时间</span>    <span class="token number">3</span>               <span class="token comment">// 失败3次后熔断</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token class-name">String</span> aiResult <span class="token operator">=</span> <span class="token class-name">CircuitBreakerUtils</span><span class="token punctuation">.</span><span class="token function">executeWithCircuitBreaker</span><span class="token punctuation">(</span>    <span class="token string">"ai-inference-service"</span><span class="token punctuation">,</span>    <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token class-name">HttpClientUtils</span><span class="token punctuation">.</span><span class="token function">httpPost</span><span class="token punctuation">(</span><span class="token string">"http://ai-service/infer"</span><span class="token punctuation">,</span> inputData<span class="token punctuation">)</span><span class="token punctuation">,</span>    aiConfig<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><h3 id="3-集成现有代码"><a href="#3-集成现有代码" class="headerlink" title="3. 集成现有代码"></a>3. 集成现有代码</h3><p>将现有的 HTTP 调用代码进行简单改造：</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token comment">// 改造前</span><span class="token class-name">String</span> response <span class="token operator">=</span> <span class="token class-name">HttpClientUtils</span><span class="token punctuation">.</span><span class="token function">httpPost</span><span class="token punctuation">(</span>url<span class="token punctuation">,</span> jsonRequest<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 改造后</span><span class="token class-name">String</span> response <span class="token operator">=</span> <span class="token class-name">CircuitBreakerUtils</span><span class="token punctuation">.</span><span class="token function">executeWithCircuitBreaker</span><span class="token punctuation">(</span>    <span class="token string">"external-api"</span><span class="token punctuation">,</span>     <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token class-name">HttpClientUtils</span><span class="token punctuation">.</span><span class="token function">httpPost</span><span class="token punctuation">(</span>url<span class="token punctuation">,</span> jsonRequest<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><h3 id="4-批量处理"><a href="#4-批量处理" class="headerlink" title="4. 批量处理"></a>4. 批量处理</h3><p>在批量调用场景下，每个服务都可以独立熔断：</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">processBatch</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> urls<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> urls<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">final</span> <span class="token class-name">String</span> url <span class="token operator">=</span> urls<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>i<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">final</span> <span class="token class-name">String</span> serviceName <span class="token operator">=</span> <span class="token string">"batch-service-"</span> <span class="token operator">+</span> i<span class="token punctuation">;</span>                <span class="token class-name">String</span> result <span class="token operator">=</span> <span class="token class-name">CircuitBreakerUtils</span><span class="token punctuation">.</span><span class="token function">executeWithCircuitBreaker</span><span class="token punctuation">(</span>            serviceName<span class="token punctuation">,</span>            <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token class-name">HttpClientUtils</span><span class="token punctuation">.</span><span class="token function">httpGet</span><span class="token punctuation">(</span>url<span class="token punctuation">)</span>        <span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token keyword">if</span> <span class="token punctuation">(</span>result <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>            <span class="token function">processSingleResult</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>            log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">"Service {} is circuit-broken, skipping"</span><span class="token punctuation">,</span> serviceName<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h2 id="监控与运维"><a href="#监控与运维" class="headerlink" title="监控与运维"></a>监控与运维</h2><h3 id="1-状态查询"><a href="#1-状态查询" class="headerlink" title="1. 状态查询"></a>1. 状态查询</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token comment">// 检查特定服务的熔断状态</span><span class="token keyword">boolean</span> isOpen <span class="token operator">=</span> <span class="token class-name">CircuitBreakerUtils</span><span class="token punctuation">.</span><span class="token function">isCircuitBreakerOpen</span><span class="token punctuation">(</span><span class="token string">"user-service"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 打印所有服务的熔断状态</span><span class="token class-name">CircuitBreakerUtils</span><span class="token punctuation">.</span><span class="token function">printCircuitBreakerStatus</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><h3 id="2-手动控制"><a href="#2-手动控制" class="headerlink" title="2. 手动控制"></a>2. 手动控制</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token comment">// 手动重置熔断器（例如在服务修复后）</span><span class="token class-name">CircuitBreakerUtils</span><span class="token punctuation">.</span><span class="token function">resetCircuitBreaker</span><span class="token punctuation">(</span><span class="token string">"user-service"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><h3 id="3-报警机制"><a href="#3-报警机制" class="headerlink" title="3. 报警机制"></a>3. 报警机制</h3><p>当熔断器被触发时，系统会自动发送报警信息：</p><pre class="language-none"><code class="language-none">【熔断器告警】服务接口超时熔断服务名称: user-service超时次数: 3熔断时间: 10分钟触发时间: 2026-01-08 17:30:15</code></pre><h2 id="实际应用场景"><a href="#实际应用场景" class="headerlink" title="实际应用场景"></a>实际应用场景</h2><h3 id="1-URL数据查询服务"><a href="#1-URL数据查询服务" class="headerlink" title="1. URL数据查询服务"></a>1. URL 数据查询服务</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">ForbiddenURL</span><span class="token punctuation">&gt;</span></span> <span class="token function">processBatch</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> urls<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token class-name">String</span> requestJson <span class="token operator">=</span> <span class="token function">buildRequestJson</span><span class="token punctuation">(</span>urls<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token class-name">String</span> responseJson <span class="token operator">=</span> <span class="token class-name">CircuitBreakerUtils</span><span class="token punctuation">.</span><span class="token function">executeWithCircuitBreaker</span><span class="token punctuation">(</span>        <span class="token string">"url-data-query"</span><span class="token punctuation">,</span>         <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token class-name">HttpClientUtils</span><span class="token punctuation">.</span><span class="token function">httpPost</span><span class="token punctuation">(</span>URL_DATA_QUERY<span class="token punctuation">,</span> requestJson<span class="token punctuation">)</span>    <span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">isBlank</span><span class="token punctuation">(</span>responseJson<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">"URL query service unavailable, returning empty result"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>    <span class="token keyword">return</span> <span class="token function">parseResponse</span><span class="token punctuation">(</span>responseJson<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h3 id="2-数据库代理服务"><a href="#2-数据库代理服务" class="headerlink" title="2. 数据库代理服务"></a>2. 数据库代理服务</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">queryDatabase</span><span class="token punctuation">(</span><span class="token class-name">String</span> sql<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">return</span> <span class="token class-name">CircuitBreakerUtils</span><span class="token punctuation">.</span><span class="token function">executeWithCircuitBreaker</span><span class="token punctuation">(</span>        <span class="token string">"database-proxy"</span><span class="token punctuation">,</span>        <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>            <span class="token comment">// 可能的慢查询</span>            <span class="token keyword">return</span> httpClient<span class="token punctuation">.</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string">"/database/query"</span><span class="token punctuation">,</span> sql<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span><span class="token punctuation">,</span>        <span class="token keyword">new</span> <span class="token class-name">CircuitBreakerConfig</span><span class="token punctuation">(</span><span class="token number">45000</span><span class="token punctuation">,</span> <span class="token number">5</span> <span class="token operator">*</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token comment">// 45秒超时，5分钟熔断</span>    <span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h3 id="3-第三方API集成"><a href="#3-第三方API集成" class="headerlink" title="3. 第三方API集成"></a>3. 第三方 API 集成</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token class-name">PaymentResult</span> <span class="token function">processPayment</span><span class="token punctuation">(</span><span class="token class-name">PaymentRequest</span> request<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token class-name">String</span> result <span class="token operator">=</span> <span class="token class-name">CircuitBreakerUtils</span><span class="token punctuation">.</span><span class="token function">executeWithCircuitBreaker</span><span class="token punctuation">(</span>        <span class="token string">"payment-gateway"</span><span class="token punctuation">,</span>        <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> paymentGateway<span class="token punctuation">.</span><span class="token function">charge</span><span class="token punctuation">(</span>request<span class="token punctuation">)</span>    <span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span>result <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token comment">// 支付网关不可用，记录订单并稍后重试</span>        <span class="token keyword">return</span> <span class="token class-name">PaymentResult</span><span class="token punctuation">.</span><span class="token function">pending</span><span class="token punctuation">(</span><span class="token string">"Payment gateway temporarily unavailable"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>        <span class="token keyword">return</span> <span class="token function">parsePaymentResult</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h2 id="性能考虑"><a href="#性能考虑" class="headerlink" title="性能考虑"></a>性能考虑</h2><h3 id="1-内存使用"><a href="#1-内存使用" class="headerlink" title="1. 内存使用"></a>1. 内存使用</h3><p>每个服务只维护一个 <code>CircuitBreakerState</code> 对象，内存占用极小。使用 <code>ConcurrentHashMap</code> 进行状态管理，在服务数量不多的情况下，性能开销可以忽略不计。</p><h3 id="2-线程安全"><a href="#2-线程安全" class="headerlink" title="2. 线程安全"></a>2. 线程安全</h3><ul><li>使用 <code>volatile</code> 确保状态变更的可见性</li><li>使用 <code>AtomicLong</code> 进行无锁的原子操作</li><li><code>ConcurrentHashMap</code> 提供线程安全的服务映射</li></ul><h3 id="3-性能优化建议"><a href="#3-性能优化建议" class="headerlink" title="3. 性能优化建议"></a>3. 性能优化建议</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token comment">// 对于高频调用，可以预先创建配置对象</span><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">CircuitBreakerConfig</span> HIGH_FREQ_CONFIG <span class="token operator">=</span>     <span class="token keyword">new</span> <span class="token class-name">CircuitBreakerConfig</span><span class="token punctuation">(</span><span class="token number">5000</span><span class="token punctuation">,</span> <span class="token number">2</span> <span class="token operator">*</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">1000</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">// 避免在循环中重复创建配置</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">batchProcess</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Request</span><span class="token punctuation">&gt;</span></span> requests<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Request</span> req <span class="token operator">:</span> requests<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token class-name">CircuitBreakerUtils</span><span class="token punctuation">.</span><span class="token function">executeWithCircuitBreaker</span><span class="token punctuation">(</span>            <span class="token string">"batch-service"</span><span class="token punctuation">,</span>             <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token function">processRequest</span><span class="token punctuation">(</span>req<span class="token punctuation">)</span><span class="token punctuation">,</span>            HIGH_FREQ_CONFIG  <span class="token comment">// 复用配置对象</span>        <span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h2 id="扩展与改进"><a href="#扩展与改进" class="headerlink" title="扩展与改进"></a>扩展与改进</h2><h3 id="1-支持更多的熔断策略"><a href="#1-支持更多的熔断策略" class="headerlink" title="1. 支持更多的熔断策略"></a>1. 支持更多的熔断策略</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token comment">// 可以扩展支持基于错误率的熔断</span><span class="token keyword">public</span> <span class="token keyword">enum</span> <span class="token class-name">CircuitBreakerStrategy</span> <span class="token punctuation">{</span>    TIMEOUT_BASED<span class="token punctuation">,</span>     <span class="token comment">// 基于超时</span>    ERROR_RATE_BASED<span class="token punctuation">,</span>  <span class="token comment">// 基于错误率</span>    RESPONSE_TIME_BASED <span class="token comment">// 基于响应时间</span><span class="token punctuation">}</span></code></pre><h3 id="2-集成度量系统"><a href="#2-集成度量系统" class="headerlink" title="2. 集成度量系统"></a>2. 集成度量系统</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token comment">// 集成Micrometer进行度量</span><span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">recordMetrics</span><span class="token punctuation">(</span><span class="token class-name">String</span> serviceName<span class="token punctuation">,</span> <span class="token keyword">long</span> duration<span class="token punctuation">,</span> <span class="token keyword">boolean</span> success<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token class-name">Timer</span><span class="token punctuation">.</span><span class="token class-name">Sample</span> sample <span class="token operator">=</span> <span class="token class-name">Timer</span><span class="token punctuation">.</span><span class="token function">start</span><span class="token punctuation">(</span>meterRegistry<span class="token punctuation">)</span><span class="token punctuation">;</span>    sample<span class="token punctuation">.</span><span class="token function">stop</span><span class="token punctuation">(</span><span class="token class-name">Timer</span><span class="token punctuation">.</span><span class="token function">builder</span><span class="token punctuation">(</span><span class="token string">"http.request"</span><span class="token punctuation">)</span>        <span class="token punctuation">.</span><span class="token function">tag</span><span class="token punctuation">(</span><span class="token string">"service"</span><span class="token punctuation">,</span> serviceName<span class="token punctuation">)</span>        <span class="token punctuation">.</span><span class="token function">tag</span><span class="token punctuation">(</span><span class="token string">"success"</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>success<span class="token punctuation">)</span><span class="token punctuation">)</span>        <span class="token punctuation">.</span><span class="token function">register</span><span class="token punctuation">(</span>meterRegistry<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h3 id="3-支持异步调用"><a href="#3-支持异步调用" class="headerlink" title="3. 支持异步调用"></a>3. 支持异步调用</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token comment">// 支持CompletableFuture</span><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token class-name">CompletableFuture</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token function">executeAsync</span><span class="token punctuation">(</span><span class="token class-name">String</span> serviceName<span class="token punctuation">,</span>                                                    <span class="token class-name">Supplier</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">CompletableFuture</span><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> asyncSupplier<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token comment">// 异步熔断器实现</span><span class="token punctuation">}</span></code></pre><h2 id="最佳实践"><a href="#最佳实践" class="headerlink" title="最佳实践"></a>最佳实践</h2><h3 id="1-服务命名规范"><a href="#1-服务命名规范" class="headerlink" title="1. 服务命名规范"></a>1. 服务命名规范</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token comment">// 推荐的服务命名方式</span><span class="token string">"user-service"</span>           <span class="token comment">// 简单服务</span><span class="token string">"payment-gateway-alipay"</span> <span class="token comment">// 区分不同的支付网关</span><span class="token string">"database-read-replica"</span>  <span class="token comment">// 区分读写数据库</span></code></pre><h3 id="2-配置参数选择"><a href="#2-配置参数选择" class="headerlink" title="2. 配置参数选择"></a>2. 配置参数选择</h3><ul><li><strong>超时阈值</strong>：通常设置为 P99 响应时间的 1.5-2 倍</li><li><strong>熔断时间</strong>：考虑服务恢复时间，通常 5-15 分钟</li><li><strong>失败阈值</strong>：对于关键服务建议设置为 1，非关键服务可以设置为 2-3</li></ul><h3 id="3-降级策略"><a href="#3-降级策略" class="headerlink" title="3. 降级策略"></a>3. 降级策略</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token class-name">UserInfo</span> <span class="token function">getUserInfo</span><span class="token punctuation">(</span><span class="token class-name">String</span> userId<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token class-name">String</span> result <span class="token operator">=</span> <span class="token class-name">CircuitBreakerUtils</span><span class="token punctuation">.</span><span class="token function">executeWithCircuitBreaker</span><span class="token punctuation">(</span>        <span class="token string">"user-service"</span><span class="token punctuation">,</span>        <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> userServiceClient<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span>    <span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span>result <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token comment">// 多级降级策略</span>        <span class="token comment">// 1. 尝试从缓存获取</span>        <span class="token class-name">UserInfo</span> cached <span class="token operator">=</span> cacheService<span class="token punctuation">.</span><span class="token function">getUser</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span>cached <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span> cached<span class="token punctuation">;</span>                <span class="token comment">// 2. 返回默认用户信息</span>        <span class="token keyword">return</span> <span class="token class-name">UserInfo</span><span class="token punctuation">.</span><span class="token function">defaultUser</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>        <span class="token keyword">return</span> <span class="token function">parseUserInfo</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>本文介绍的熔断器工具类具有以下优势：</p><ol><li><strong>轻量级</strong>：代码简洁，依赖最小，易于集成</li><li><strong>高性能</strong>：使用无锁算法，对业务代码性能影响极小</li><li><strong>易扩展</strong>：支持自定义配置，可根据业务需求灵活调整</li><li><strong>生产就绪</strong>：包含完整的监控、报警和运维支持</li></ol><p>通过合理使用熔断器模式，可以显著提高微服务架构的稳定性和可用性。在实际应用中，建议结合业务特点选择合适的配置参数，并制定完善的降级策略，以确保在外部服务不可用时，系统仍能提供基本的服务能力。</p><p>熔断器只是微服务容错的手段之一，在实际项目中，还应该配合重试机制、超时控制、限流器等措施，构建完整的容错体系。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;引言&quot;&gt;&lt;a href=&quot;#引言&quot; class=&quot;headerlink&quot; title=&quot;引言&quot;&gt;&lt;/a&gt;引言&lt;/h2&gt;&lt;p&gt;在现代微服务架构中，服务间的网络调用是不可避免的。然而，网络的不稳定性和外部服务的不可靠性可能导致级联故障，最终影响整个系统的可用性。&lt;/p</summary>
      
    
    
    
    <category term="Java" scheme="https://jueee.github.io/categories/Java/"/>
    
    <category term="JavaClass" scheme="https://jueee.github.io/categories/Java/JavaClass/"/>
    
    
    <category term="Java" scheme="https://jueee.github.io/tags/Java/"/>
    
    <category term="JavaClass" scheme="https://jueee.github.io/tags/JavaClass/"/>
    
  </entry>
  
  <entry>
    <title>SQL 关联更新操作指南</title>
    <link href="https://jueee.github.io/2025/12/2025-12-24-SQL%E5%85%B3%E8%81%94%E6%9B%B4%E6%96%B0%E6%93%8D%E4%BD%9C%E6%8C%87%E5%8D%97/"/>
    <id>https://jueee.github.io/2025/12/2025-12-24-SQL%E5%85%B3%E8%81%94%E6%9B%B4%E6%96%B0%E6%93%8D%E4%BD%9C%E6%8C%87%E5%8D%97/</id>
    <published>2025-12-24T00:00:00.000Z</published>
    <updated>2025-12-24T06:54:56.088Z</updated>
    
    <content type="html"><![CDATA[<p>在数据库管理中，更新一张表的字段值通常是一个常见的需求。</p><p>特别是当需要根据另一张表中相关字段的值来更新数据时，使用 SQL 的关联更新（JOIN）功能可以大大简化这一过程。</p><p>下面，我们将探讨如何使用 SQL 语句进行表的关联更新。</p><a id="more"></a><h2 id="示例场景"><a href="#示例场景" class="headerlink" title="示例场景"></a>示例场景</h2><p>假设我们有两张表：</p><ul><li><strong>表 A</strong>：存储模型信息</li><li><strong>表 B</strong>：存储模型测试信息</li></ul><p>这两张表都有一个共同的字段 <code>model_id</code>，我们希望根据表 A 中的 <code>model_name</code> 更新表 B 中的 <code>model_name</code>。</p><h2 id="SQL-更新语句"><a href="#SQL-更新语句" class="headerlink" title="SQL 更新语句"></a>SQL 更新语句</h2><p>以下是一个 SQL 语句示例，展示如何通过关联来更新表 B 的 <code>model_name</code> 字段：</p><pre class="language-sql" data-language="sql"><code class="language-sql"><span class="token keyword">UPDATE</span> table_b <span class="token keyword">AS</span> b<span class="token keyword">JOIN</span> table_a <span class="token keyword">AS</span> a<span class="token keyword">ON</span> b<span class="token punctuation">.</span>model_id <span class="token operator">=</span> a<span class="token punctuation">.</span>model_id<span class="token keyword">SET</span> b<span class="token punctuation">.</span>model_name <span class="token operator">=</span> a<span class="token punctuation">.</span>model_name<span class="token keyword">WHERE</span> b<span class="token punctuation">.</span>model_id <span class="token operator">IS</span> <span class="token operator">NOT</span> <span class="token boolean">NULL</span><span class="token punctuation">;</span>  <span class="token comment">-- 可选条件，确保 model_id 不为空</span></code></pre><h3 id="语句解析"><a href="#语句解析" class="headerlink" title="语句解析"></a>语句解析</h3><ol><li><strong>UPDATE 语句</strong>: 使用 <code>UPDATE</code> 来指定需要更新的表（在本例中为 <code>table_b</code>）。</li><li><strong>JOIN</strong>: 使用 <code>JOIN</code> 语句将表 A 和表 B 关联起来，基于共同的字段 <code>model_id</code>。</li><li><strong>SET</strong>: 使用 <code>SET</code> 指定需要更新的字段，将表 B 的 <code>model_name</code> 更新为表 A 的 <code>model_name</code>。</li><li><strong>WHERE</strong>: 该条件是可选的，用于确保只更新那些 <code>model_id</code> 不为空的记录。</li></ol><h2 id="执行更新前的注意事项"><a href="#执行更新前的注意事项" class="headerlink" title="执行更新前的注意事项"></a>执行更新前的注意事项</h2><p>在执行更新操作之前，建议采取以下步骤：</p><ul><li><p><strong>备份数据</strong>: 确保在进行大规模更新之前备份重要数据，以防止数据丢失。</p></li><li><p><strong>验证更新</strong>: 在更新之前，可以通过一个 <code>SELECT</code> 查询来验证将要更新的数据。例如：</p>  <pre class="language-sql" data-language="sql"><code class="language-sql"><span class="token keyword">SELECT</span> b<span class="token punctuation">.</span>model_id<span class="token punctuation">,</span> b<span class="token punctuation">.</span>model_name<span class="token punctuation">,</span> a<span class="token punctuation">.</span>model_name<span class="token keyword">FROM</span> table_b <span class="token keyword">AS</span> b<span class="token keyword">JOIN</span> table_a <span class="token keyword">AS</span> a<span class="token keyword">ON</span> b<span class="token punctuation">.</span>model_id <span class="token operator">=</span> a<span class="token punctuation">.</span>model_id<span class="token punctuation">;</span></code></pre><p>  这将帮助您查看即将被更新的记录，以确保更新操作的准确性。</p></li></ul><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>通过 SQL 的关联更新功能，我们可以高效地根据另一张表的字段值更新数据。</p><p>这种方法在处理大量数据时尤其有效，可以节省时间并减少手动更新的错误。</p><p>希望本指南能帮助您更好地理解 SQL 关联更新的使用。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;在数据库管理中，更新一张表的字段值通常是一个常见的需求。&lt;/p&gt;
&lt;p&gt;特别是当需要根据另一张表中相关字段的值来更新数据时，使用 SQL 的关联更新（JOIN）功能可以大大简化这一过程。&lt;/p&gt;
&lt;p&gt;下面，我们将探讨如何使用 SQL 语句进行表的关联更新。&lt;/p&gt;</summary>
    
    
    
    <category term="Blog" scheme="https://jueee.github.io/categories/Blog/"/>
    
    
    <category term="Blog" scheme="https://jueee.github.io/tags/Blog/"/>
    
  </entry>
  
  <entry>
    <title>python 创建简单的 HTTP 服务器下载</title>
    <link href="https://jueee.github.io/2025/11/2025-11-07-python%E5%88%9B%E5%BB%BA%E7%AE%80%E5%8D%95%E7%9A%84HTTP%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8B%E8%BD%BD/"/>
    <id>https://jueee.github.io/2025/11/2025-11-07-python%E5%88%9B%E5%BB%BA%E7%AE%80%E5%8D%95%E7%9A%84HTTP%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8B%E8%BD%BD/</id>
    <published>2025-11-07T00:00:00.000Z</published>
    <updated>2025-11-07T06:26:12.483Z</updated>
    
    <content type="html"><![CDATA[<p>在软件开发过程中，有时我们需要快速启动一个简单的 HTTP 服务器来测试或展示静态文件。</p><p>Python 提供了一个便捷的方法来实现这一点，但随着 Python 2 和 Python 3 的语法差异，实现方式略有不同。</p><p>本文将介绍如何在 Python 2 和 Python 3 中创建一个简单的 HTTP 服务器。</p><a id="more"></a><h2 id="Python-2-方法"><a href="#Python-2-方法" class="headerlink" title="Python 2 方法"></a>Python 2 方法</h2><p>在 Python 2 中，我们可以使用 <code>SimpleHTTPServer</code> 模块来创建一个基本的 HTTP 服务器。以下是实现方法：</p><pre class="language-python" data-language="python"><code class="language-python">python <span class="token operator">-</span>m SimpleHTTPServer <span class="token number">9000</span></code></pre><p>这个命令会在当前目录启动一个 HTTP 服务器，监听 9000 端口。</p><h2 id="Python-3-方法"><a href="#Python-3-方法" class="headerlink" title="Python 3 方法"></a>Python 3 方法</h2><p>Python 3 对模块进行了重组，<code>SimpleHTTPServer</code> 被整合到了 <code>http.server</code> 模块中。使用以下命令：</p><pre class="language-python" data-language="python"><code class="language-python">python <span class="token operator">-</span>m http<span class="token punctuation">.</span>server <span class="token number">9000</span></code></pre><p>这个命令同样会在当前目录启动一个 HTTP 服务器，监听 9000 端口。</p><h2 id="通用脚本"><a href="#通用脚本" class="headerlink" title="通用脚本"></a>通用脚本</h2><p>为了方便使用，我们可以创建一个脚本，它能够自动检测 Python 版本并使用相应的方法启动服务器：</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token comment">#!/usr/bin/env python</span><span class="token keyword">import</span> sys<span class="token keyword">def</span> <span class="token function">start_server</span><span class="token punctuation">(</span>port<span class="token operator">=</span><span class="token number">9000</span><span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token keyword">try</span><span class="token punctuation">:</span>        <span class="token keyword">if</span> sys<span class="token punctuation">.</span>version_info<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token operator">&lt;</span> <span class="token number">3</span><span class="token punctuation">:</span>            <span class="token comment"># Python 2</span>            <span class="token keyword">import</span> SimpleHTTPServer            <span class="token keyword">import</span> SocketServer            Handler <span class="token operator">=</span> SimpleHTTPServer<span class="token punctuation">.</span>SimpleHTTPRequestHandler            httpd <span class="token operator">=</span> SocketServer<span class="token punctuation">.</span>TCPServer<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">,</span> port<span class="token punctuation">)</span><span class="token punctuation">,</span> Handler<span class="token punctuation">)</span>            <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"Serving on port %s (Python 2)"</span> <span class="token operator">%</span> port<span class="token punctuation">)</span>            httpd<span class="token punctuation">.</span>serve_forever<span class="token punctuation">(</span><span class="token punctuation">)</span>        <span class="token keyword">else</span><span class="token punctuation">:</span>            <span class="token comment"># Python 3</span>            <span class="token keyword">import</span> http<span class="token punctuation">.</span>server            <span class="token keyword">import</span> socketserver            Handler <span class="token operator">=</span> http<span class="token punctuation">.</span>server<span class="token punctuation">.</span>SimpleHTTPRequestHandler            <span class="token keyword">with</span> socketserver<span class="token punctuation">.</span>TCPServer<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">,</span> port<span class="token punctuation">)</span><span class="token punctuation">,</span> Handler<span class="token punctuation">)</span> <span class="token keyword">as</span> httpd<span class="token punctuation">:</span>                <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"Serving on port %s (Python 3)"</span> <span class="token operator">%</span> port<span class="token punctuation">)</span>                httpd<span class="token punctuation">.</span>serve_forever<span class="token punctuation">(</span><span class="token punctuation">)</span>    <span class="token keyword">except</span> KeyboardInterrupt<span class="token punctuation">:</span>        <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string">"\nServer stopped."</span><span class="token punctuation">)</span><span class="token keyword">if</span> __name__ <span class="token operator">==</span> <span class="token string">"__main__"</span><span class="token punctuation">:</span>    start_server<span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre><p>将此脚本保存为 <code>simple_server.py</code>，然后可以通过以下方式运行：</p><pre class="language-none"><code class="language-none">python simple_server.py</code></pre><p>这个脚本会自动检测 Python 版本并使用适当的方法启动服务器，默认端口为 9000。</p><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><ol><li>确保您有权限在指定的端口上启动服务器。</li><li>这个简单的 HTTP 服务器主要用于开发和测试目的，不建议在生产环境中使用。</li><li>默认情况下，服务器会暴露当前目录下的所有文件，请注意信息安全。</li></ol><p>通过这种方法，无论您使用的是 Python 2 还是 Python 3，都可以快速启动一个简单的 HTTP 服务器，方便进行开发测试或文件共享。</p><p>希望这个教程对您有所帮助！如果您有任何疑问，欢迎在评论区留言。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;在软件开发过程中，有时我们需要快速启动一个简单的 HTTP 服务器来测试或展示静态文件。&lt;/p&gt;
&lt;p&gt;Python 提供了一个便捷的方法来实现这一点，但随着 Python 2 和 Python 3 的语法差异，实现方式略有不同。&lt;/p&gt;
&lt;p&gt;本文将介绍如何在 Python 2 和 Python 3 中创建一个简单的 HTTP 服务器。&lt;/p&gt;</summary>
    
    
    
    <category term="python" scheme="https://jueee.github.io/categories/python/"/>
    
    
    <category term="python" scheme="https://jueee.github.io/tags/python/"/>
    
  </entry>
  
  <entry>
    <title>Spring Boot 中实现流式输出的方案总结</title>
    <link href="https://jueee.github.io/2025/10/2025-10-31-Spring%20Boot%E4%B8%AD%E5%AE%9E%E7%8E%B0%E6%B5%81%E5%BC%8F%E8%BE%93%E5%87%BA%E7%9A%84%E6%96%B9%E6%A1%88%E6%80%BB%E7%BB%93/"/>
    <id>https://jueee.github.io/2025/10/2025-10-31-Spring%20Boot%E4%B8%AD%E5%AE%9E%E7%8E%B0%E6%B5%81%E5%BC%8F%E8%BE%93%E5%87%BA%E7%9A%84%E6%96%B9%E6%A1%88%E6%80%BB%E7%BB%93/</id>
    <published>2025-10-31T00:00:00.000Z</published>
    <updated>2025-10-31T08:36:11.494Z</updated>
    
    <content type="html"><![CDATA[<p>在现代 Web 应用程序中，实时数据流和长时间运行的操作变得越来越普遍。</p><p>Spring Boot 提供了多种方法来实现流式输出，使得服务器可以逐步向客户端发送数据，而不是等待整个响应准备就绪。</p><p>本文将介绍 5 种在 Spring Boot 中实现流式输出的方法，从传统的 Server-Sent Events (SSE) 到更现代的响应式编程方法。</p><a id="more"></a><h3 id="流式输出方案对比"><a href="#流式输出方案对比" class="headerlink" title="流式输出方案对比"></a>流式输出方案对比</h3><p>五种流式输出方法的主要优缺点：</p><table><thead><tr><th>方法</th><th>优点</th><th>缺点</th></tr></thead><tbody><tr><td> SseEmitter</td><td>・支持 SSE，适合实时数据流・客户端易处理事件流・长连接，减少网络开销</td><td>・仅支持文本数据・部分旧浏览器可能不支持 SSE</td></tr><tr><td>ResponseBodyEmitter</td><td>・支持二进制数据流・灵活性高，可发送不同类型数据</td><td>・客户端需自行处理数据流・可能需额外客户端逻辑解析数据</td></tr><tr><td> DeferredResult</td><td>・支持异步处理・可一次性返回所有数据</td><td>・不支持实时流式传输・可能占用较多服务器内存</td></tr><tr><td> Flux</td><td>・支持响应式编程・非阻塞式，效率高・支持背压・易于处理错误和异常</td><td>・需要响应式编程知识・可能增加系统复杂性</td></tr><tr><td> AsyncContext</td><td>・直接操作底层 Servlet API，控制力强・可处理大量并发请求</td><td>・代码复杂度较高・错误处理相对困难・不如高级抽象易用</td></tr></tbody></table><h3 id="方案实现方式"><a href="#方案实现方式" class="headerlink" title="方案实现方式"></a>方案实现方式</h3><h4 id="1-使用SseEmitter实现Server-Sent-Events"><a href="#1-使用SseEmitter实现Server-Sent-Events" class="headerlink" title="1. 使用SseEmitter实现Server-Sent Events"></a>1. 使用 SseEmitter 实现 Server-Sent Events</h4><p>Server-Sent Events (SSE) 是一种允许服务器向客户端推送数据的技术。Spring 框架提供了 <code>SseEmitter</code> 类来简化 SSE 的实现。</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@PostMapping</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"/chatStream"</span><span class="token punctuation">,</span> produces <span class="token operator">=</span> <span class="token class-name">MediaType</span><span class="token punctuation">.</span>TEXT_EVENT_STREAM_VALUE<span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token class-name">SseEmitter</span> <span class="token function">chatStream</span><span class="token punctuation">(</span><span class="token annotation punctuation">@RequestBody</span> <span class="token annotation punctuation">@Validated</span> <span class="token class-name">GetAiAuditRequest</span> dto<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token class-name">SseEmitter</span> emitter <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SseEmitter</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">1L</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 设置无超时</span>    response<span class="token punctuation">.</span><span class="token function">setContentType</span><span class="token punctuation">(</span><span class="token string">"text/event-stream"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    response<span class="token punctuation">.</span><span class="token function">setCharacterEncoding</span><span class="token punctuation">(</span><span class="token string">"UTF-8"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token class-name">CompletableFuture</span><span class="token punctuation">.</span><span class="token function">runAsync</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>        <span class="token keyword">try</span> <span class="token punctuation">{</span>            <span class="token class-name">TestClass</span><span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span>dto<span class="token punctuation">.</span><span class="token function">getPrompt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> chunk <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>                <span class="token keyword">try</span> <span class="token punctuation">{</span>                    emitter<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>chunk<span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>                    log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"Error sending SSE event"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token punctuation">}</span>            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>            emitter<span class="token punctuation">.</span><span class="token function">completeWithError</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>            emitter<span class="token punctuation">.</span><span class="token function">complete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span>    <span class="token punctuation">}</span><span class="token punctuation">,</span> asyncExecutor<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">return</span> emitter<span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p>这种方法使用 <code>SseEmitter</code> 来发送事件流，适合需要实时更新的场景。</p><h4 id="2-使用ResponseBodyEmitter模拟SSE"><a href="#2-使用ResponseBodyEmitter模拟SSE" class="headerlink" title="2. 使用ResponseBodyEmitter模拟SSE"></a>2. 使用 ResponseBodyEmitter 模拟 SSE</h4><p>有时候，我们可能需要使用不同的内容类型，但仍然希望保持类似 SSE 的行为。这时可以使用 <code>ResponseBodyEmitter</code>。</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@PostMapping</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"/chatStream2"</span><span class="token punctuation">,</span> produces <span class="token operator">=</span> <span class="token class-name">MediaType</span><span class="token punctuation">.</span>APPLICATION_OCTET_STREAM_VALUE<span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token class-name">ResponseBodyEmitter</span> <span class="token function">chatStream2</span><span class="token punctuation">(</span><span class="token annotation punctuation">@RequestBody</span> <span class="token annotation punctuation">@Validated</span> <span class="token class-name">GetAiAuditRequest</span> dto<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token class-name">ResponseBodyEmitter</span> emitter <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ResponseBodyEmitter</span><span class="token punctuation">(</span><span class="token operator">-</span><span class="token number">1L</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    response<span class="token punctuation">.</span><span class="token function">setContentType</span><span class="token punctuation">(</span><span class="token class-name">MediaType</span><span class="token punctuation">.</span>APPLICATION_OCTET_STREAM_VALUE<span class="token punctuation">)</span><span class="token punctuation">;</span>    response<span class="token punctuation">.</span><span class="token function">setCharacterEncoding</span><span class="token punctuation">(</span><span class="token string">"UTF-8"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token class-name">CompletableFuture</span><span class="token punctuation">.</span><span class="token function">runAsync</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>        <span class="token keyword">try</span> <span class="token punctuation">{</span>            <span class="token class-name">TestClass</span><span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span>dto<span class="token punctuation">.</span><span class="token function">getPrompt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> chunk <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>                <span class="token keyword">try</span> <span class="token punctuation">{</span>                    <span class="token class-name">String</span> sseFormattedData <span class="token operator">=</span> <span class="token string">"data:"</span> <span class="token operator">+</span> chunk <span class="token operator">+</span> <span class="token string">"\n\n"</span><span class="token punctuation">;</span>                    emitter<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>sseFormattedData<span class="token punctuation">.</span><span class="token function">getBytes</span><span class="token punctuation">(</span><span class="token class-name">StandardCharsets</span><span class="token punctuation">.</span>UTF_8<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">MediaType</span><span class="token punctuation">.</span>APPLICATION_OCTET_STREAM<span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>                    log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"Error sending chunk"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token punctuation">}</span>            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>            emitter<span class="token punctuation">.</span><span class="token function">completeWithError</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>            emitter<span class="token punctuation">.</span><span class="token function">complete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span>    <span class="token punctuation">}</span><span class="token punctuation">,</span> asyncExecutor<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">return</span> emitter<span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p>这种方法允许我们使用自定义的内容类型，同时保持类似 SSE 的数据格式。</p><h4 id="3-使用Reactive-Streams和ServerSentEvent"><a href="#3-使用Reactive-Streams和ServerSentEvent" class="headerlink" title="3. 使用Reactive Streams和ServerSentEvent"></a>3. 使用 Reactive Streams 和 ServerSentEvent</h4><p>Spring WebFlux 提供了响应式编程的支持，我们可以使用 <code>Flux</code> 和 <code>ServerSentEvent</code> 来实现流式输出。</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@PostMapping</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"/chatStream3"</span><span class="token punctuation">,</span> produces <span class="token operator">=</span> <span class="token class-name">MediaType</span><span class="token punctuation">.</span>TEXT_EVENT_STREAM_VALUE<span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token class-name">Flux</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">ServerSentEvent</span><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> <span class="token function">chatStream3</span><span class="token punctuation">(</span><span class="token annotation punctuation">@RequestBody</span> <span class="token annotation punctuation">@Validated</span> <span class="token class-name">GetAiAuditRequest</span> dto<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">return</span> <span class="token class-name">Flux</span><span class="token punctuation">.</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">ServerSentEvent</span><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span><span class="token function">create</span><span class="token punctuation">(</span>sink <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>                <span class="token class-name">TestClass</span><span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span>dto<span class="token punctuation">.</span><span class="token function">getPrompt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> chunk <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>                    sink<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token class-name">ServerSentEvent</span><span class="token punctuation">.</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span><span class="token function">builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span>                            <span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span>chunk<span class="token punctuation">)</span>                            <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                sink<span class="token punctuation">.</span><span class="token function">complete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">subscribeOn</span><span class="token punctuation">(</span><span class="token class-name">Schedulers</span><span class="token punctuation">.</span><span class="token function">fromExecutor</span><span class="token punctuation">(</span>asyncExecutor<span class="token punctuation">)</span><span class="token punctuation">)</span>            <span class="token punctuation">.</span><span class="token function">onErrorResume</span><span class="token punctuation">(</span>e <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>                log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"Error in chatStream3"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token keyword">return</span> <span class="token class-name">Flux</span><span class="token punctuation">.</span><span class="token function">just</span><span class="token punctuation">(</span><span class="token class-name">ServerSentEvent</span><span class="token punctuation">.</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span><span class="token function">builder</span><span class="token punctuation">(</span><span class="token punctuation">)</span>                        <span class="token punctuation">.</span><span class="token function">data</span><span class="token punctuation">(</span><span class="token string">"Error: "</span> <span class="token operator">+</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>                        <span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p>这种方法利用了响应式编程的特性，提供了更好的背压处理和资源管理。</p><h4 id="4-使用Flux直接输出数据"><a href="#4-使用Flux直接输出数据" class="headerlink" title="4. 使用Flux直接输出数据"></a>4. 使用 Flux 直接输出数据</h4><p>有时我们可能不需要完整的 SSE 格式，只需要直接输出数据流。这时可以使用 <code>Flux</code> 直接输出数据。</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@PostMapping</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"/chatStream4"</span><span class="token punctuation">,</span> produces <span class="token operator">=</span> <span class="token class-name">MediaType</span><span class="token punctuation">.</span>TEXT_EVENT_STREAM_VALUE<span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token class-name">Flux</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> <span class="token function">chatStream4</span><span class="token punctuation">(</span><span class="token annotation punctuation">@RequestBody</span> <span class="token annotation punctuation">@Validated</span> <span class="token class-name">GetAiAuditRequest</span> dto<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">return</span> <span class="token class-name">Flux</span><span class="token punctuation">.</span><span class="token function">create</span><span class="token punctuation">(</span>sink <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>                <span class="token class-name">TestClass</span><span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span>dto<span class="token punctuation">.</span><span class="token function">getPrompt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> chunk <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>                    sink<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span>chunk<span class="token punctuation">)</span><span class="token punctuation">;</span>                    sink<span class="token punctuation">.</span><span class="token function">next</span><span class="token punctuation">(</span><span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// 添加换行符以确保立即刷新</span>                <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                sink<span class="token punctuation">.</span><span class="token function">complete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">subscribeOn</span><span class="token punctuation">(</span><span class="token class-name">Schedulers</span><span class="token punctuation">.</span><span class="token function">fromExecutor</span><span class="token punctuation">(</span>asyncExecutor<span class="token punctuation">)</span><span class="token punctuation">)</span>            <span class="token punctuation">.</span><span class="token function">onErrorResume</span><span class="token punctuation">(</span>e <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>                log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"Error in chatStream4"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token keyword">return</span> <span class="token class-name">Flux</span><span class="token punctuation">.</span><span class="token function">just</span><span class="token punctuation">(</span><span class="token string">"Error: "</span> <span class="token operator">+</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p>这种方法更加灵活，允许我们自定义输出格式。</p><h4 id="5-使用AsyncContext和ServletOutputStream"><a href="#5-使用AsyncContext和ServletOutputStream" class="headerlink" title="5. 使用AsyncContext和ServletOutputStream"></a>5. 使用 AsyncContext 和 ServletOutputStream</h4><p>最后，我们可以使用传统的 Servlet API 来实现流式输出，这种方法提供了最大的灵活性。</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@PostMapping</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"/chatStream5"</span><span class="token punctuation">,</span> produces <span class="token operator">=</span> <span class="token class-name">MediaType</span><span class="token punctuation">.</span>TEXT_EVENT_STREAM_VALUE<span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">chatStream5</span><span class="token punctuation">(</span><span class="token annotation punctuation">@RequestBody</span> <span class="token annotation punctuation">@Validated</span> <span class="token class-name">GetAiAuditRequest</span> dto<span class="token punctuation">,</span> <span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span>    <span class="token class-name">AsyncContext</span> asyncContext <span class="token operator">=</span> request<span class="token punctuation">.</span><span class="token function">startAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    asyncContext<span class="token punctuation">.</span><span class="token function">setTimeout</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 无超时</span>    response<span class="token punctuation">.</span><span class="token function">setContentType</span><span class="token punctuation">(</span><span class="token string">"text/event-stream"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    response<span class="token punctuation">.</span><span class="token function">setCharacterEncoding</span><span class="token punctuation">(</span><span class="token string">"UTF-8"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    asyncExecutor<span class="token punctuation">.</span><span class="token function">execute</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>        <span class="token keyword">try</span> <span class="token punctuation">{</span>            <span class="token class-name">PrintWriter</span> writer <span class="token operator">=</span> response<span class="token punctuation">.</span><span class="token function">getWriter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token class-name">TestClass</span><span class="token punctuation">.</span><span class="token function">invoke</span><span class="token punctuation">(</span>dto<span class="token punctuation">.</span><span class="token function">getPrompt</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> chunk <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>                <span class="token keyword">try</span> <span class="token punctuation">{</span>                    writer<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span><span class="token string">"data:"</span> <span class="token operator">+</span> chunk <span class="token operator">+</span> <span class="token string">"\n\n"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                    writer<span class="token punctuation">.</span><span class="token function">flush</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>                    log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"Error writing chunk"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token punctuation">}</span>            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>            log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"Error in chat stream"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>            asyncContext<span class="token punctuation">.</span><span class="token function">complete</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span>    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p>这种方法使用 <code>AsyncContext</code> 和 <code>PrintWriter</code> 直接写入响应，提供了最大的控制权。</p><h3 id="效果测试"><a href="#效果测试" class="headerlink" title="效果测试"></a>效果测试</h3><h4 id="curl-测试"><a href="#curl-测试" class="headerlink" title="curl 测试"></a>curl 测试</h4><pre class="language-shell" data-language="shell"><code class="language-shell"><span class="token function">curl</span> -X POST <span class="token punctuation">\</span>     -H <span class="token string">"Accept: text/event-stream"</span> <span class="token punctuation">\</span>     -H <span class="token string">"Cache-Control: no-cache"</span> <span class="token punctuation">\</span>     -H <span class="token string">"Connection: keep-alive"</span> <span class="token punctuation">\</span>     -H <span class="token string">"Content-Type: application/json"</span> <span class="token punctuation">\</span>     -d <span class="token string">'{"prompt":"What is public in Java?"}'</span> <span class="token punctuation">\</span>     --no-buffer <span class="token punctuation">\</span>     http://127.0.0.1/view/data/chatStream <span class="token operator">|</span> <span class="token punctuation">\</span><span class="token function">sed</span> <span class="token string">'s/^data://; s/#￥#/<span class="token entity" title="\n">\n</span>/g'</span> <span class="token operator">|</span> <span class="token function">tr</span> -d <span class="token string">'<span class="token entity" title="\n">\n</span>'</span><span class="token function">curl</span> -X POST <span class="token punctuation">\</span>     -H <span class="token string">"Accept: application/octet-stream"</span> <span class="token punctuation">\</span>     -H <span class="token string">"Content-Type: application/json"</span> <span class="token punctuation">\</span>     -d <span class="token string">'{"prompt":"What is public in Java?"}'</span> <span class="token punctuation">\</span>     --no-buffer <span class="token punctuation">\</span>     http://127.0.0.1/view/data/chatStream2 <span class="token operator">|</span> <span class="token punctuation">\</span><span class="token function">sed</span> <span class="token string">'s/^data://; s/#￥#/<span class="token entity" title="\n">\n</span>/g'</span> <span class="token operator">|</span> <span class="token function">tr</span> -d <span class="token string">'<span class="token entity" title="\n">\n</span>'</span></code></pre><h4 id="Java-测试："><a href="#Java-测试：" class="headerlink" title="Java 测试："></a>Java 测试：</h4><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span><span class="token class-name">BufferedReader</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span><span class="token class-name">InputStreamReader</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span><span class="token class-name">OutputStream</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>net<span class="token punctuation">.</span></span><span class="token class-name">HttpURLConnection</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>net<span class="token punctuation">.</span></span>URL<span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>nio<span class="token punctuation">.</span>charset<span class="token punctuation">.</span></span><span class="token class-name">StandardCharsets</span><span class="token punctuation">;</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SseClientControllerTest</span> <span class="token punctuation">{</span>    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">String</span> URL_STRING <span class="token operator">=</span> <span class="token string">"http://127.0.0.1:18083/view/data/chatStream2"</span><span class="token punctuation">;</span>        <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">try</span> <span class="token punctuation">{</span>            <span class="token keyword">long</span> startTime <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-</span>startTime<span class="token punctuation">)</span><span class="token operator">+</span><span class="token string">"----"</span><span class="token operator">+</span><span class="token string">"步骤1: 准备连接SSE端点"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token class-name">String</span> jsonBody <span class="token operator">=</span> <span class="token string">"{\"prompt\":\"What is public in Java?\"}"</span><span class="token punctuation">;</span>            <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> postData <span class="token operator">=</span> jsonBody<span class="token punctuation">.</span><span class="token function">getBytes</span><span class="token punctuation">(</span><span class="token class-name">StandardCharsets</span><span class="token punctuation">.</span>UTF_8<span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token class-name">URL</span> url <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token function">URL</span><span class="token punctuation">(</span>URL_STRING<span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token class-name">HttpURLConnection</span> conn <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">HttpURLConnection</span><span class="token punctuation">)</span> url<span class="token punctuation">.</span><span class="token function">openConnection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            conn<span class="token punctuation">.</span><span class="token function">setRequestMethod</span><span class="token punctuation">(</span><span class="token string">"POST"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// 如果服务器支持 POST 方式的 SSE</span>            <span class="token keyword">if</span><span class="token punctuation">(</span>URL_STRING<span class="token punctuation">.</span><span class="token function">endsWith</span><span class="token punctuation">(</span><span class="token string">"chatStream2"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>                conn<span class="token punctuation">.</span><span class="token function">setRequestProperty</span><span class="token punctuation">(</span><span class="token string">"Accept"</span><span class="token punctuation">,</span> <span class="token string">"application/octet-stream"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>                conn<span class="token punctuation">.</span><span class="token function">setRequestProperty</span><span class="token punctuation">(</span><span class="token string">"Accept"</span><span class="token punctuation">,</span> <span class="token string">"text/event-stream"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                conn<span class="token punctuation">.</span><span class="token function">setRequestProperty</span><span class="token punctuation">(</span><span class="token string">"Cache-Control"</span><span class="token punctuation">,</span> <span class="token string">"no-cache"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                conn<span class="token punctuation">.</span><span class="token function">setRequestProperty</span><span class="token punctuation">(</span><span class="token string">"Connection"</span><span class="token punctuation">,</span> <span class="token string">"keep-alive"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token punctuation">}</span>            conn<span class="token punctuation">.</span><span class="token function">setReadTimeout</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token comment">// 无限读取超时</span>            conn<span class="token punctuation">.</span><span class="token function">setRequestMethod</span><span class="token punctuation">(</span><span class="token string">"POST"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            conn<span class="token punctuation">.</span><span class="token function">setRequestProperty</span><span class="token punctuation">(</span><span class="token string">"Content-Type"</span><span class="token punctuation">,</span> <span class="token string">"application/json"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            conn<span class="token punctuation">.</span><span class="token function">setRequestProperty</span><span class="token punctuation">(</span><span class="token string">"Content-Length"</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>postData<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            conn<span class="token punctuation">.</span><span class="token function">setDoOutput</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-</span>startTime<span class="token punctuation">)</span><span class="token operator">+</span><span class="token string">"----"</span><span class="token operator">+</span><span class="token string">"步骤2: 发送POST请求到SSE端点"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token keyword">try</span> <span class="token punctuation">(</span><span class="token class-name">OutputStream</span> os <span class="token operator">=</span> conn<span class="token punctuation">.</span><span class="token function">getOutputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                os<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span>postData<span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token punctuation">}</span>            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-</span>startTime<span class="token punctuation">)</span><span class="token operator">+</span><span class="token string">"----"</span><span class="token operator">+</span><span class="token string">"步骤3: 收到响应，状态码: "</span> <span class="token operator">+</span> conn<span class="token punctuation">.</span><span class="token function">getResponseCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token keyword">if</span> <span class="token punctuation">(</span>conn<span class="token punctuation">.</span><span class="token function">getResponseCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token class-name">HttpURLConnection</span><span class="token punctuation">.</span>HTTP_OK<span class="token punctuation">)</span> <span class="token punctuation">{</span>                <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">RuntimeException</span><span class="token punctuation">(</span><span class="token string">"HTTP error! status: "</span> <span class="token operator">+</span> conn<span class="token punctuation">.</span><span class="token function">getResponseCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token punctuation">}</span>            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-</span>startTime<span class="token punctuation">)</span><span class="token operator">+</span><span class="token string">"----"</span><span class="token operator">+</span><span class="token string">"步骤4: 开始读取SSE流"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token keyword">try</span> <span class="token punctuation">(</span><span class="token class-name">BufferedReader</span> reader <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">BufferedReader</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">InputStreamReader</span><span class="token punctuation">(</span>conn<span class="token punctuation">.</span><span class="token function">getInputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                <span class="token class-name">String</span> line<span class="token punctuation">;</span>                <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>line <span class="token operator">=</span> reader<span class="token punctuation">.</span><span class="token function">readLine</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>line<span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">print</span><span class="token punctuation">(</span>line<span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">"data:"</span><span class="token punctuation">,</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">replace</span><span class="token punctuation">(</span><span class="token string">"#￥#"</span><span class="token punctuation">,</span><span class="token string">"\n"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                    <span class="token punctuation">}</span>                <span class="token punctuation">}</span>            <span class="token punctuation">}</span>            <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-</span>startTime<span class="token punctuation">)</span><span class="token operator">+</span><span class="token string">"----"</span><span class="token operator">+</span><span class="token string">"步骤6: SSE流结束"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>            <span class="token class-name">System</span><span class="token punctuation">.</span>err<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"发生错误: "</span> <span class="token operator">+</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>这五种方法展示了 Spring Boot 中实现流式输出的不同方式，从传统的 SSE 到现代的响应式编程。选择哪种方法取决于你的具体需求，如性能要求、兼容性考虑、以及与现有代码的集成等因素。无论选择哪种方法，流式输出都能显著提升实时数据处理和长时间运行任务的用户体验。</p><p>在实际应用中，记得要考虑错误处理、资源管理和性能优化。同时，客户端的实现也需要相应地调整以正确处理这些流式数据。</p><p>希望这篇文章能帮助你在 Spring Boot 项目中实现高效的流式输出！</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;在现代 Web 应用程序中，实时数据流和长时间运行的操作变得越来越普遍。&lt;/p&gt;
&lt;p&gt;Spring Boot 提供了多种方法来实现流式输出，使得服务器可以逐步向客户端发送数据，而不是等待整个响应准备就绪。&lt;/p&gt;
&lt;p&gt;本文将介绍 5 种在 Spring Boot 中实现流式输出的方法，从传统的 Server-Sent Events (SSE) 到更现代的响应式编程方法。&lt;/p&gt;</summary>
    
    
    
    <category term="Java" scheme="https://jueee.github.io/categories/Java/"/>
    
    <category term="SpringBoot" scheme="https://jueee.github.io/categories/Java/SpringBoot/"/>
    
    
    <category term="Java" scheme="https://jueee.github.io/tags/Java/"/>
    
    <category term="SpringBoot" scheme="https://jueee.github.io/tags/SpringBoot/"/>
    
  </entry>
  
  <entry>
    <title>获取本地内网 IP 地址的方法</title>
    <link href="https://jueee.github.io/2025/10/2025-10-13-%E8%8E%B7%E5%8F%96%E6%9C%AC%E5%9C%B0%E5%86%85%E7%BD%91IP%E5%9C%B0%E5%9D%80%E7%9A%84%E6%96%B9%E6%B3%95/"/>
    <id>https://jueee.github.io/2025/10/2025-10-13-%E8%8E%B7%E5%8F%96%E6%9C%AC%E5%9C%B0%E5%86%85%E7%BD%91IP%E5%9C%B0%E5%9D%80%E7%9A%84%E6%96%B9%E6%B3%95/</id>
    <published>2025-10-13T00:00:00.000Z</published>
    <updated>2025-10-13T11:28:43.129Z</updated>
    
    <content type="html"><![CDATA[<p>Java 获取本地内网 IP 地址的方法。</p><a id="more"></a><h2 id="获取本地内网IP地址的方法"><a href="#获取本地内网IP地址的方法" class="headerlink" title="获取本地内网IP地址的方法"></a>获取本地内网 IP 地址的方法</h2><h4 id="获取第一个内网IP"><a href="#获取第一个内网IP" class="headerlink" title="获取第一个内网IP"></a>获取第一个内网 IP</h4><p><strong>行为特征：</strong></p><ul><li>遍历网络接口，返回<strong>第一个</strong>符合条件的内网 IP</li><li> 顺序依赖于系统网络接口的枚举顺序</li><li>不保证返回的是 "最佳"IP</li></ul><p><strong>适用场景：</strong> 只需要一个可用的内网 IP，对具体是哪个网段不敏感</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token comment">/** * 获取本地内网IP地址 * @return 本地内网IP地址 */</span><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getLocalIntranetIp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">try</span> <span class="token punctuation">{</span>        <span class="token class-name">Enumeration</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">NetworkInterface</span><span class="token punctuation">&gt;</span></span> networkInterfaces <span class="token operator">=</span> <span class="token class-name">NetworkInterface</span><span class="token punctuation">.</span><span class="token function">getNetworkInterfaces</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">while</span> <span class="token punctuation">(</span>networkInterfaces<span class="token punctuation">.</span><span class="token function">hasMoreElements</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>            <span class="token class-name">NetworkInterface</span> networkInterface <span class="token operator">=</span> networkInterfaces<span class="token punctuation">.</span><span class="token function">nextElement</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                        <span class="token comment">// 跳过回环接口和非激活接口</span>            <span class="token keyword">if</span> <span class="token punctuation">(</span>networkInterface<span class="token punctuation">.</span><span class="token function">isLoopback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token operator">!</span>networkInterface<span class="token punctuation">.</span><span class="token function">isUp</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                <span class="token keyword">continue</span><span class="token punctuation">;</span>            <span class="token punctuation">}</span>                        <span class="token class-name">Enumeration</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">InetAddress</span><span class="token punctuation">&gt;</span></span> inetAddresses <span class="token operator">=</span> networkInterface<span class="token punctuation">.</span><span class="token function">getInetAddresses</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token keyword">while</span> <span class="token punctuation">(</span>inetAddresses<span class="token punctuation">.</span><span class="token function">hasMoreElements</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                <span class="token class-name">InetAddress</span> inetAddress <span class="token operator">=</span> inetAddresses<span class="token punctuation">.</span><span class="token function">nextElement</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                                <span class="token comment">// 只处理IPv4地址且非回环地址</span>                <span class="token keyword">if</span> <span class="token punctuation">(</span>inetAddress <span class="token keyword">instanceof</span> <span class="token class-name">Inet4Address</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>inetAddress<span class="token punctuation">.</span><span class="token function">isLoopbackAddress</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                    <span class="token class-name">String</span> ip <span class="token operator">=</span> inetAddress<span class="token punctuation">.</span><span class="token function">getHostAddress</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                    <span class="token comment">// 判断是否为内网IP</span>                    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isInnerIP</span><span class="token punctuation">(</span>ip<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                        <span class="token keyword">return</span> ip<span class="token punctuation">;</span>                    <span class="token punctuation">}</span>                <span class="token punctuation">}</span>            <span class="token punctuation">}</span>        <span class="token punctuation">}</span>    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>        log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"获取本地内网IP失败"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>    <span class="token keyword">return</span> <span class="token string">"127.0.0.1"</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h4 id="获取所有内网IP"><a href="#获取所有内网IP" class="headerlink" title="获取所有内网IP"></a>获取所有内网 IP</h4><p><strong>行为特征：</strong></p><ul><li>遍历所有网络接口，收集<strong>所有</strong>内网 IP</li><li> 包含多网卡、虚拟网卡、VPN 等产生的 IP</li><li> 提供完整的网络环境视图</li></ul><p><strong>适用场景：</strong> 需要了解完整网络环境，或让用户选择特定网卡</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token comment">/** * 获取所有本地内网IP地址 * @return 本地内网IP地址列表 */</span><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> <span class="token function">getAllLocalIntranetIps</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> ipList <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">try</span> <span class="token punctuation">{</span>        <span class="token class-name">Enumeration</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">NetworkInterface</span><span class="token punctuation">&gt;</span></span> networkInterfaces <span class="token operator">=</span> <span class="token class-name">NetworkInterface</span><span class="token punctuation">.</span><span class="token function">getNetworkInterfaces</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">while</span> <span class="token punctuation">(</span>networkInterfaces<span class="token punctuation">.</span><span class="token function">hasMoreElements</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>            <span class="token class-name">NetworkInterface</span> networkInterface <span class="token operator">=</span> networkInterfaces<span class="token punctuation">.</span><span class="token function">nextElement</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                        <span class="token comment">// 跳过回环接口和非激活接口</span>            <span class="token keyword">if</span> <span class="token punctuation">(</span>networkInterface<span class="token punctuation">.</span><span class="token function">isLoopback</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">||</span> <span class="token operator">!</span>networkInterface<span class="token punctuation">.</span><span class="token function">isUp</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                <span class="token keyword">continue</span><span class="token punctuation">;</span>            <span class="token punctuation">}</span>                        <span class="token class-name">Enumeration</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">InetAddress</span><span class="token punctuation">&gt;</span></span> inetAddresses <span class="token operator">=</span> networkInterface<span class="token punctuation">.</span><span class="token function">getInetAddresses</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token keyword">while</span> <span class="token punctuation">(</span>inetAddresses<span class="token punctuation">.</span><span class="token function">hasMoreElements</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                <span class="token class-name">InetAddress</span> inetAddress <span class="token operator">=</span> inetAddresses<span class="token punctuation">.</span><span class="token function">nextElement</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                                <span class="token comment">// 只处理IPv4地址且非回环地址</span>                <span class="token keyword">if</span> <span class="token punctuation">(</span>inetAddress <span class="token keyword">instanceof</span> <span class="token class-name">Inet4Address</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>inetAddress<span class="token punctuation">.</span><span class="token function">isLoopbackAddress</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                    <span class="token class-name">String</span> ip <span class="token operator">=</span> inetAddress<span class="token punctuation">.</span><span class="token function">getHostAddress</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                    <span class="token comment">// 判断是否为内网IP</span>                    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isInnerIP</span><span class="token punctuation">(</span>ip<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                        ipList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>ip<span class="token punctuation">)</span><span class="token punctuation">;</span>                    <span class="token punctuation">}</span>                <span class="token punctuation">}</span>            <span class="token punctuation">}</span>        <span class="token punctuation">}</span>    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>        log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"获取所有本地内网IP失败"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>    <span class="token keyword">return</span> ipList<span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h4 id="获取首选内网IP"><a href="#获取首选内网IP" class="headerlink" title="获取首选内网IP"></a>获取首选内网 IP</h4><p><strong>行为特征：</strong></p><ul><li>智能选择最适合的 IP 地址</li><li>优先选择家庭 / 办公室常用的 192.168 网段</li><li>避免返回 Docker、VM 等虚拟网络的 IP</li></ul><p><strong>适用场景：</strong> 需要一个 "最佳" 的本地 IP，用于服务绑定、日志记录等</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token comment">/** * 获取首选的本地内网IP（优先级：192.168.x.x &gt; 10.x.x.x &gt; 172.16-31.x.x） * @return 首选的本地内网IP地址 */</span><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getPreferredLocalIntranetIp</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> ipList <span class="token operator">=</span> <span class="token function">getAllLocalIntranetIps</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span>ipList<span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">return</span> <span class="token string">"127.0.0.1"</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>        <span class="token comment">// 优先返回192.168网段的IP</span>    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">String</span> ip <span class="token operator">:</span> ipList<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span>ip<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">"192.168."</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>            <span class="token keyword">return</span> ip<span class="token punctuation">;</span>        <span class="token punctuation">}</span>    <span class="token punctuation">}</span>        <span class="token comment">// 其次返回10网段的IP</span>    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">String</span> ip <span class="token operator">:</span> ipList<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span>ip<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">"10."</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>            <span class="token keyword">return</span> ip<span class="token punctuation">;</span>        <span class="token punctuation">}</span>    <span class="token punctuation">}</span>        <span class="token comment">// 最后返回172.16-31网段的IP</span>    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">String</span> ip <span class="token operator">:</span> ipList<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span>ip<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">"172."</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>            <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> parts <span class="token operator">=</span> ip<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">"\\."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token keyword">if</span> <span class="token punctuation">(</span>parts<span class="token punctuation">.</span>length <span class="token operator">&gt;=</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                <span class="token keyword">int</span> secondOctet <span class="token operator">=</span> <span class="token class-name">Integer</span><span class="token punctuation">.</span><span class="token function">parseInt</span><span class="token punctuation">(</span>parts<span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token keyword">if</span> <span class="token punctuation">(</span>secondOctet <span class="token operator">&gt;=</span> <span class="token number">16</span> <span class="token operator">&amp;&amp;</span> secondOctet <span class="token operator">&lt;=</span> <span class="token number">31</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                    <span class="token keyword">return</span> ip<span class="token punctuation">;</span>                <span class="token punctuation">}</span>            <span class="token punctuation">}</span>        <span class="token punctuation">}</span>    <span class="token punctuation">}</span>        <span class="token comment">// 如果都没有，返回第一个</span>    <span class="token keyword">return</span> ipList<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h4 id="其他补充方法"><a href="#其他补充方法" class="headerlink" title="其他补充方法"></a>其他补充方法</h4><pre class="language-java" data-language="java"><code class="language-java"><span class="token comment">/** * 获取本地主机名 * @return 本地主机名 */</span><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getLocalHostName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token keyword">try</span> <span class="token punctuation">{</span>        <span class="token keyword">return</span> <span class="token class-name">InetAddress</span><span class="token punctuation">.</span><span class="token function">getLocalHost</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getHostName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">UnknownHostException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>        log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"获取本地主机名失败"</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">return</span> <span class="token string">"unknown"</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">/** * 获取本地IP和主机名信息 * @return 格式为 "IP(hostname)" 的字符串 */</span><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">getLocalIpWithHostName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token class-name">String</span> ip <span class="token operator">=</span> <span class="token function">getPreferredLocalIntranetIp</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token class-name">String</span> hostname <span class="token operator">=</span> <span class="token function">getLocalHostName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">return</span> ip <span class="token operator">+</span> <span class="token string">"("</span> <span class="token operator">+</span> hostname <span class="token operator">+</span> <span class="token string">")"</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h2 id="完整的导入语句"><a href="#完整的导入语句" class="headerlink" title="完整的导入语句"></a>完整的导入语句</h2><p>在文件顶部添加这些导入：</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>net<span class="token punctuation">.</span></span><span class="token class-name">NetworkInterface</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>net<span class="token punctuation">.</span></span><span class="token class-name">Inet4Address</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Enumeration</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">ArrayList</span><span class="token punctuation">;</span></code></pre><h2 id="使用示例"><a href="#使用示例" class="headerlink" title="使用示例"></a>使用示例</h2><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token comment">// 获取单个内网IP</span>    <span class="token class-name">String</span> localIp <span class="token operator">=</span> <span class="token function">getLocalIntranetIp</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"本地内网IP: {}"</span><span class="token punctuation">,</span> localIp<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token comment">// 获取所有内网IP</span>    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> allIps <span class="token operator">=</span> <span class="token function">getAllLocalIntranetIps</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"所有本地内网IP: {}"</span><span class="token punctuation">,</span> allIps<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token comment">// 获取首选内网IP</span>    <span class="token class-name">String</span> preferredIp <span class="token operator">=</span> <span class="token function">getPreferredLocalIntranetIp</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"首选内网IP: {}"</span><span class="token punctuation">,</span> preferredIp<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token comment">// 获取主机名</span>    <span class="token class-name">String</span> hostname <span class="token operator">=</span> <span class="token function">getLocalHostName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"本地主机名: {}"</span><span class="token punctuation">,</span> hostname<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token comment">// 获取IP和主机名</span>    <span class="token class-name">String</span> ipWithHostname <span class="token operator">=</span> <span class="token function">getLocalIpWithHostName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    log<span class="token punctuation">.</span><span class="token function">info</span><span class="token punctuation">(</span><span class="token string">"IP和主机名: {}"</span><span class="token punctuation">,</span> ipWithHostname<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p>这些方法会自动过滤掉回环地址和非内网地址，返回真正的本地内网 IP 地址。<code>getPreferredLocalIntranetIp()</code> 方法按照常用网段的优先级返回最合适的 IP 地址。</p><h2 id="典型场景下的不同结果"><a href="#典型场景下的不同结果" class="headerlink" title="典型场景下的不同结果"></a>典型场景下的不同结果</h2><h3 id="场景1：普通家用电脑"><a href="#场景1：普通家用电脑" class="headerlink" title="场景1：普通家用电脑"></a>场景 1：普通家用电脑</h3><pre class="language-none"><code class="language-none">第一个内网IP: 192.168.1.100所有内网IP: [192.168.1.100]首选内网IP: 192.168.1.100结果: 三个方法返回相同</code></pre><h3 id="场景2：开发者电脑（Docker-VPN）"><a href="#场景2：开发者电脑（Docker-VPN）" class="headerlink" title="场景2：开发者电脑（Docker + VPN）"></a>场景 2：开发者电脑（Docker + VPN）</h3><pre class="language-none"><code class="language-none">第一个内网IP: 172.17.0.1      (Docker网桥)所有内网IP: [172.17.0.1, 10.0.2.15, 192.168.1.100]首选内网IP: 192.168.1.100     (优先选择192.168网段)结果: 首选方法返回更合适的IP</code></pre><h3 id="场景3：服务器（多网卡）"><a href="#场景3：服务器（多网卡）" class="headerlink" title="场景3：服务器（多网卡）"></a>场景 3：服务器（多网卡）</h3><pre class="language-none"><code class="language-none">第一个内网IP: 10.0.1.50       (第一个网卡)所有内网IP: [10.0.1.50, 192.168.100.10, 172.20.0.5]首选内网IP: 192.168.100.10    (优先192.168网段)结果: 首选方法选择了业务网段</code></pre><h2 id="推荐使用场景"><a href="#推荐使用场景" class="headerlink" title="推荐使用场景"></a>推荐使用场景</h2><table><thead><tr><th>方法</th><th>适用场景</th><th>优点</th><th>缺点</th></tr></thead><tbody><tr><td><code>getLocalIntranetIp()</code></td><td>简单应用，只需一个 IP</td><td> 快速、简单</td><td>可能返回虚拟网络 IP</td></tr><tr><td><code>getAllLocalIntranetIps()</code></td><td>网络诊断、用户选择</td><td>信息完整</td><td>需要额外处理逻辑</td></tr><tr><td><code>getPreferredLocalIntranetIp()</code></td><td>服务绑定、配置生成</td><td>智能选择</td><td>逻辑相对复杂</td></tr></tbody></table><p><strong>建议：</strong> 大多数情况下使用 <code>getPreferredLocalIntranetIp()</code>，它能提供最合适的结果。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;Java 获取本地内网 IP 地址的方法。&lt;/p&gt;</summary>
    
    
    
    <category term="Java" scheme="https://jueee.github.io/categories/Java/"/>
    
    
    <category term="Java" scheme="https://jueee.github.io/tags/Java/"/>
    
  </entry>
  
  <entry>
    <title>对已有数据重建 ES 字段索引</title>
    <link href="https://jueee.github.io/2025/09/2025-09-16-%E5%AF%B9%E5%B7%B2%E6%9C%89%E6%95%B0%E6%8D%AE%E9%87%8D%E5%BB%BAES%E5%AD%97%E6%AE%B5%E7%B4%A2%E5%BC%95/"/>
    <id>https://jueee.github.io/2025/09/2025-09-16-%E5%AF%B9%E5%B7%B2%E6%9C%89%E6%95%B0%E6%8D%AE%E9%87%8D%E5%BB%BAES%E5%AD%97%E6%AE%B5%E7%B4%A2%E5%BC%95/</id>
    <published>2025-09-16T00:00:00.000Z</published>
    <updated>2025-09-16T11:37:48.685Z</updated>
    
    <content type="html"><![CDATA[<p><strong>重建 ES 字段索引，对已有数据生效。</strong></p><a id="more"></a><h2 id="方案1：添加multi-field-mapping（推荐）"><a href="#方案1：添加multi-field-mapping（推荐）" class="headerlink" title="方案1：添加multi-field mapping（推荐）"></a>方案 1：添加 multi-field mapping（推荐）</h2><h3 id="步骤1：更新mapping"><a href="#步骤1：更新mapping" class="headerlink" title="步骤1：更新mapping"></a>步骤 1：更新 mapping</h3><pre class="language-json" data-language="json"><code class="language-json">PUT your_index/_mapping<span class="token punctuation">{</span>  <span class="token property">"properties"</span><span class="token operator">:</span> <span class="token punctuation">{</span>    <span class="token property">"sendTime"</span><span class="token operator">:</span> <span class="token punctuation">{</span>      <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"text"</span><span class="token punctuation">,</span>      <span class="token property">"fields"</span><span class="token operator">:</span> <span class="token punctuation">{</span>        <span class="token property">"keyword"</span><span class="token operator">:</span> <span class="token punctuation">{</span>          <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"keyword"</span><span class="token punctuation">,</span>          <span class="token property">"ignore_above"</span><span class="token operator">:</span> <span class="token number">256</span>        <span class="token punctuation">}</span>      <span class="token punctuation">}</span>    <span class="token punctuation">}</span>  <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h3 id="步骤2：重建索引使mapping生效"><a href="#步骤2：重建索引使mapping生效" class="headerlink" title="步骤2：重建索引使mapping生效"></a>步骤 2：重建索引使 mapping 生效</h3><pre class="language-json" data-language="json"><code class="language-json">POST your_index/_update_by_query?refresh=<span class="token boolean">true</span><span class="token punctuation">{</span>  <span class="token property">"query"</span><span class="token operator">:</span> <span class="token punctuation">{</span>    <span class="token property">"match_all"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>  <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h2 id="方案2：零停机时间的安全做法"><a href="#方案2：零停机时间的安全做法" class="headerlink" title="方案2：零停机时间的安全做法"></a>方案 2：零停机时间的安全做法</h2><h3 id="步骤1：创建新索引模板"><a href="#步骤1：创建新索引模板" class="headerlink" title="步骤1：创建新索引模板"></a>步骤 1：创建新索引模板</h3><pre class="language-json" data-language="json"><code class="language-json">PUT _index_template/your_template<span class="token punctuation">{</span>  <span class="token property">"index_patterns"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"your_index_pattern*"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>  <span class="token property">"template"</span><span class="token operator">:</span> <span class="token punctuation">{</span>    <span class="token property">"mappings"</span><span class="token operator">:</span> <span class="token punctuation">{</span>      <span class="token property">"properties"</span><span class="token operator">:</span> <span class="token punctuation">{</span>        <span class="token property">"sendTime"</span><span class="token operator">:</span> <span class="token punctuation">{</span>          <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"text"</span><span class="token punctuation">,</span>          <span class="token property">"fields"</span><span class="token operator">:</span> <span class="token punctuation">{</span>            <span class="token property">"keyword"</span><span class="token operator">:</span> <span class="token punctuation">{</span>              <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"keyword"</span><span class="token punctuation">,</span>              <span class="token property">"ignore_above"</span><span class="token operator">:</span> <span class="token number">256</span>            <span class="token punctuation">}</span>          <span class="token punctuation">}</span>        <span class="token punctuation">}</span>      <span class="token punctuation">}</span>    <span class="token punctuation">}</span>  <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h3 id="步骤2：滚动更新（如果使用日期索引）"><a href="#步骤2：滚动更新（如果使用日期索引）" class="headerlink" title="步骤2：滚动更新（如果使用日期索引）"></a>步骤 2：滚动更新（如果使用日期索引）</h3><p>新的数据会自动应用新 mapping，旧数据保持不变。</p><h2 id="验证方法"><a href="#验证方法" class="headerlink" title="验证方法"></a>验证方法</h2><p>更新后验证是否生效：</p><pre class="language-json" data-language="json"><code class="language-json">GET your_index/_mapping/field/sendTime</code></pre><p>应该看到：</p><pre class="language-json" data-language="json"><code class="language-json"><span class="token punctuation">{</span>  <span class="token property">"your_index"</span><span class="token operator">:</span> <span class="token punctuation">{</span>    <span class="token property">"mappings"</span><span class="token operator">:</span> <span class="token punctuation">{</span>      <span class="token property">"sendTime"</span><span class="token operator">:</span> <span class="token punctuation">{</span>        <span class="token property">"full_name"</span><span class="token operator">:</span> <span class="token string">"sendTime"</span><span class="token punctuation">,</span>        <span class="token property">"mapping"</span><span class="token operator">:</span> <span class="token punctuation">{</span>          <span class="token property">"sendTime"</span><span class="token operator">:</span> <span class="token punctuation">{</span>            <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"text"</span><span class="token punctuation">,</span>            <span class="token property">"fields"</span><span class="token operator">:</span> <span class="token punctuation">{</span>              <span class="token property">"keyword"</span><span class="token operator">:</span> <span class="token punctuation">{</span>                <span class="token property">"type"</span><span class="token operator">:</span> <span class="token string">"keyword"</span><span class="token punctuation">,</span>                <span class="token property">"ignore_above"</span><span class="token operator">:</span> <span class="token number">256</span>              <span class="token punctuation">}</span>            <span class="token punctuation">}</span>          <span class="token punctuation">}</span>        <span class="token punctuation">}</span>      <span class="token punctuation">}</span>    <span class="token punctuation">}</span>  <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h2 id="在Java代码中使用"><a href="#在Java代码中使用" class="headerlink" title="在Java代码中使用"></a>在 Java 代码中使用</h2><pre class="language-java" data-language="java"><code class="language-java"><span class="token comment">// 更新mapping后，可以这样排序</span><span class="token class-name">SortBuilder</span> sortBuilder<span class="token punctuation">;</span><span class="token keyword">try</span> <span class="token punctuation">{</span>    sortBuilder <span class="token operator">=</span> <span class="token class-name">SortBuilders</span><span class="token punctuation">.</span><span class="token function">fieldSort</span><span class="token punctuation">(</span><span class="token string">"sendTime.keyword"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">order</span><span class="token punctuation">(</span><span class="token class-name">SortOrder</span><span class="token punctuation">.</span>DESC<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token comment">// 兜底方案</span>    sortBuilder <span class="token operator">=</span> <span class="token class-name">SortBuilders</span><span class="token punctuation">.</span><span class="token function">fieldSort</span><span class="token punctuation">(</span><span class="token string">"_id"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">order</span><span class="token punctuation">(</span><span class="token class-name">SortOrder</span><span class="token punctuation">.</span>ASC<span class="token punctuation">)</span><span class="token punctuation">;</span>    log<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token string">"sendTime.keyword字段不可用，使用_id排序"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h2 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h2><ol><li><strong>已有数据</strong>：需要<code>_update_by_query</code> 才能生效</li><li><strong>性能影响</strong>：重建过程中可能影响查询性能</li><li><strong>存储增加</strong>：keyword 字段会额外占用存储空间</li><li><strong>建议时机</strong>：在业务低峰期执行</li></ol><p><strong>最安全的方案</strong>：先在测试环境验证，确认无问题后再在生产环境执行。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;strong&gt;重建 ES 字段索引，对已有数据生效。&lt;/strong&gt;&lt;/p&gt;</summary>
    
    
    
    <category term="Database" scheme="https://jueee.github.io/categories/Database/"/>
    
    <category term="ElasticSearch" scheme="https://jueee.github.io/categories/Database/ElasticSearch/"/>
    
    
    <category term="Database" scheme="https://jueee.github.io/tags/Database/"/>
    
    <category term="ElasticSearch" scheme="https://jueee.github.io/tags/ElasticSearch/"/>
    
  </entry>
  
  <entry>
    <title>编写简易 WebSocket 测试页面</title>
    <link href="https://jueee.github.io/2025/09/2025-09-02-%E7%BC%96%E5%86%99%E7%AE%80%E6%98%93WebSocket%E6%B5%8B%E8%AF%95%E9%A1%B5%E9%9D%A2/"/>
    <id>https://jueee.github.io/2025/09/2025-09-02-%E7%BC%96%E5%86%99%E7%AE%80%E6%98%93WebSocket%E6%B5%8B%E8%AF%95%E9%A1%B5%E9%9D%A2/</id>
    <published>2025-09-02T00:00:00.000Z</published>
    <updated>2025-09-02T08:36:49.679Z</updated>
    
    <content type="html"><![CDATA[<p>以下是一个简单的 WebSocket 测试 HTML 示例，它包含一个消息输入框和一个按钮，用于向 WebSocket 服务器发送消息。此外，还会显示来自服务器的响应。</p><p>您可以根据实际的 WebSocket 服务器地址进行修改。</p><a id="more"></a><h3 id="示例代码"><a href="#示例代码" class="headerlink" title="示例代码"></a>示例代码</h3><pre class="language-html" data-language="html"><code class="language-html"><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">&gt;</span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>UTF-8<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>viewport<span class="token punctuation">"</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>width=device-width, initial-scale=1.0<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">&gt;</span></span>WebSocket Test<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">&gt;</span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span><span class="token punctuation">&gt;</span></span><span class="token style"><span class="token language-css">        <span class="token selector">body</span> <span class="token punctuation">{</span>            <span class="token property">font-family</span><span class="token punctuation">:</span> Arial<span class="token punctuation">,</span> sans-serif<span class="token punctuation">;</span>            <span class="token property">margin</span><span class="token punctuation">:</span> 20px<span class="token punctuation">;</span>        <span class="token punctuation">}</span>        <span class="token selector">#messages</span> <span class="token punctuation">{</span>            <span class="token property">border</span><span class="token punctuation">:</span> 1px solid #ccc<span class="token punctuation">;</span>            <span class="token property">padding</span><span class="token punctuation">:</span> 10px<span class="token punctuation">;</span>            <span class="token property">width</span><span class="token punctuation">:</span> 300px<span class="token punctuation">;</span>            <span class="token property">height</span><span class="token punctuation">:</span> 200px<span class="token punctuation">;</span>            <span class="token property">overflow-y</span><span class="token punctuation">:</span> scroll<span class="token punctuation">;</span>            <span class="token property">margin-bottom</span><span class="token punctuation">:</span> 10px<span class="token punctuation">;</span>        <span class="token punctuation">}</span>    </span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>h2</span><span class="token punctuation">&gt;</span></span>WebSocket Test Client<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>h2</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>messages<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>div</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>text<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>messageInput<span class="token punctuation">"</span></span> <span class="token attr-name">placeholder</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>Enter your message...<span class="token punctuation">"</span></span> <span class="token punctuation">/&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>button</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>sendButton<span class="token punctuation">"</span></span><span class="token punctuation">&gt;</span></span>Send<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>button</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">    <span class="token keyword">const</span> serverUrl <span class="token operator">=</span> <span class="token string">'wss://your_websocket_server_address'</span><span class="token punctuation">;</span> <span class="token comment">// 替换为您的 WebSocket 服务器地址</span>    <span class="token keyword">const</span> websocket <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">WebSocket</span><span class="token punctuation">(</span>serverUrl<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">const</span> messagesDiv <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'messages'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">const</span> messageInput <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'messageInput'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">const</span> sendButton <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'sendButton'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    websocket<span class="token punctuation">.</span><span class="token function-variable function">onopen</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        messagesDiv<span class="token punctuation">.</span>innerHTML <span class="token operator">+=</span> <span class="token string">'&lt;div&gt;Connected to WebSocket server.&lt;/div&gt;'</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">;</span>    websocket<span class="token punctuation">.</span><span class="token function-variable function">onmessage</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        messagesDiv<span class="token punctuation">.</span>innerHTML <span class="token operator">+=</span> <span class="token string">'&lt;div&gt;Received: '</span> <span class="token operator">+</span> event<span class="token punctuation">.</span>data <span class="token operator">+</span> <span class="token string">'&lt;/div&gt;'</span><span class="token punctuation">;</span>        messagesDiv<span class="token punctuation">.</span>scrollTop <span class="token operator">=</span> messagesDiv<span class="token punctuation">.</span>scrollHeight<span class="token punctuation">;</span> <span class="token comment">// 滚动到最新消息</span>    <span class="token punctuation">}</span><span class="token punctuation">;</span>    websocket<span class="token punctuation">.</span><span class="token function-variable function">onerror</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        messagesDiv<span class="token punctuation">.</span>innerHTML <span class="token operator">+=</span> <span class="token string">'&lt;div style="color: red;"&gt;Error: '</span> <span class="token operator">+</span> event<span class="token punctuation">.</span>message <span class="token operator">+</span> <span class="token string">'&lt;/div&gt;'</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">;</span>    websocket<span class="token punctuation">.</span><span class="token function-variable function">onclose</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">event</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        messagesDiv<span class="token punctuation">.</span>innerHTML <span class="token operator">+=</span> <span class="token string">'&lt;div&gt;Disconnected from WebSocket server.&lt;/div&gt;'</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">;</span>    sendButton<span class="token punctuation">.</span><span class="token function-variable function">onclick</span> <span class="token operator">=</span> <span class="token keyword">function</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">const</span> message <span class="token operator">=</span> messageInput<span class="token punctuation">.</span>value<span class="token punctuation">;</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span>message<span class="token punctuation">)</span> <span class="token punctuation">{</span>            websocket<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>message<span class="token punctuation">)</span><span class="token punctuation">;</span>            messagesDiv<span class="token punctuation">.</span>innerHTML <span class="token operator">+=</span> <span class="token string">'&lt;div&gt;Sent: '</span> <span class="token operator">+</span> message <span class="token operator">+</span> <span class="token string">'&lt;/div&gt;'</span><span class="token punctuation">;</span>            messageInput<span class="token punctuation">.</span>value <span class="token operator">=</span> <span class="token string">''</span><span class="token punctuation">;</span> <span class="token comment">// 清空输入框</span>        <span class="token punctuation">}</span>    <span class="token punctuation">}</span><span class="token punctuation">;</span></span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">&gt;</span></span></code></pre><h3 id="使用说明"><a href="#使用说明" class="headerlink" title="使用说明"></a>使用说明</h3><ol><li><p><strong>替换 WebSocket 服务器地址</strong>：</p><ul><li>在代码中，找到 <code>const serverUrl = 'wss://your_websocket_server_address';</code> 这一行，并将 <code>your_websocket_server_address</code> 替换为您实际的 WebSocket 服务器地址。</li></ul></li><li><p><strong>打开 HTML 文件</strong>：</p><ul><li>将上述代码复制到一个新的 <code>.html</code> 文件中，保存后用浏览器打开。</li></ul></li><li><p><strong>测试 WebSocket</strong>：</p><ul><li>输入消息并点击 “Send” 按钮，可以将消息发送到服务器。您将在消息框中看到发送的消息和接收到的服务器响应。</li></ul></li></ol><h3 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h3><ul><li>确保您的 WebSocket 服务器正在运行，并且可以接受连接。</li><li>如果使用的是 <code>wss://</code>，请确保您的服务器支持安全的 WebSocket 连接。</li><li>如果遇到连接问题，请检查浏览器的开发者工具中的控制台和网络选项卡，以获取更多错误信息。</li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;以下是一个简单的 WebSocket 测试 HTML 示例，它包含一个消息输入框和一个按钮，用于向 WebSocket 服务器发送消息。此外，还会显示来自服务器的响应。&lt;/p&gt;
&lt;p&gt;您可以根据实际的 WebSocket 服务器地址进行修改。&lt;/p&gt;</summary>
    
    
    
    <category term="WebSocket" scheme="https://jueee.github.io/categories/WebSocket/"/>
    
    
    <category term="WebSocket" scheme="https://jueee.github.io/tags/WebSocket/"/>
    
  </entry>
  
  <entry>
    <title>Linux 文件操作相关命令行汇总</title>
    <link href="https://jueee.github.io/2025/07/2025-07-29-Linux%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C%E7%9B%B8%E5%85%B3%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%B1%87%E6%80%BB/"/>
    <id>https://jueee.github.io/2025/07/2025-07-29-Linux%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C%E7%9B%B8%E5%85%B3%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%B1%87%E6%80%BB/</id>
    <published>2025-07-29T00:00:00.000Z</published>
    <updated>2025-07-29T09:09:12.397Z</updated>
    
    <content type="html"><![CDATA[<h3 id="替换文件中的文本"><a href="#替换文件中的文本" class="headerlink" title="替换文件中的文本"></a>替换文件中的文本</h3><p>在 Linux 中，您可以使用 <code>sed</code> 命令来替换文件中的文本。具体来说，如果您想将 <code>monitor-chart.vue</code> 文件中的所有 <code>mychart</code> 替换为 <code>myChart</code>，可以使用以下命令：</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">sed</span> -i <span class="token string">'s/mychart/myChart/g'</span> monitor-chart.vue</code></pre><a id="more"></a><h4 id="解释"><a href="#解释" class="headerlink" title="解释"></a>解释</h4><ul><li><code>sed</code> 是一个流编辑器，用于处理文本。</li><li><code>-i</code> 选项表示在文件中直接进行修改。</li><li><code>s/mychart/myChart/g</code> 是 <code>sed</code> 的替换命令：<ul><li><code>s</code> 表示替换。</li><li><code>mychart</code> 是要被替换的文本。</li><li><code>myChart</code> 是替换后的文本。</li><li><code>g</code> 表示全局替换，即替换文件中所有出现的 <code>mychart</code>。</li></ul></li></ul><h4 id="注意事项"><a href="#注意事项" class="headerlink" title="注意事项"></a>注意事项</h4><ul><li><p>在执行该命令之前，可以先备份原文件：</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">cp</span> monitor-chart.vue monitor-chart.vue.bak</code></pre></li><li><p>如果您希望在确认每个替换时手动检查，可以去掉 <code>g</code>，改为：</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">sed</span> -i <span class="token string">'s/mychart/myChart/g'</span> monitor-chart.vue</code></pre></li><li><p>如果您的 <code>mychart</code> 可能在不同的大小写环境中出现，您可能需要使用不区分大小写的选项：</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">sed</span> -i <span class="token string">'s/mychart/myChart/Ig'</span> monitor-chart.vue</code></pre></li></ul><p>请根据您的需求选择适合的命令。</p>]]></content>
    
    
    <summary type="html">&lt;h3 id=&quot;替换文件中的文本&quot;&gt;&lt;a href=&quot;#替换文件中的文本&quot; class=&quot;headerlink&quot; title=&quot;替换文件中的文本&quot;&gt;&lt;/a&gt;替换文件中的文本&lt;/h3&gt;&lt;p&gt;在 Linux 中，您可以使用 &lt;code&gt;sed&lt;/code&gt; 命令来替换文件中的文本。具体来说，如果您想将 &lt;code&gt;monitor-chart.vue&lt;/code&gt; 文件中的所有 &lt;code&gt;mychart&lt;/code&gt; 替换为 &lt;code&gt;myChart&lt;/code&gt;，可以使用以下命令：&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; -i &lt;span class=&quot;token string&quot;&gt;&#39;s/mychart/myChart/g&#39;&lt;/span&gt; monitor-chart.vue&lt;/code&gt;&lt;/pre&gt;</summary>
    
    
    
    <category term="Linux" scheme="https://jueee.github.io/categories/Linux/"/>
    
    
    <category term="Linux" scheme="https://jueee.github.io/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>Linux 使用 nc 同步文件命令行汇总</title>
    <link href="https://jueee.github.io/2025/07/2025-07-28-Linux%E4%BD%BF%E7%94%A8nc%E5%90%8C%E6%AD%A5%E6%96%87%E4%BB%B6%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%B1%87%E6%80%BB/"/>
    <id>https://jueee.github.io/2025/07/2025-07-28-Linux%E4%BD%BF%E7%94%A8nc%E5%90%8C%E6%AD%A5%E6%96%87%E4%BB%B6%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%B1%87%E6%80%BB/</id>
    <published>2025-07-28T00:00:00.000Z</published>
    <updated>2025-07-29T09:13:21.269Z</updated>
    
    <content type="html"><![CDATA[<h3 id="文件传输命令行"><a href="#文件传输命令行" class="headerlink" title="文件传输命令行"></a>文件传输命令行</h3><pre class="language-bash" data-language="bash"><code class="language-bash">同步：$ <span class="token function">tar</span> c test-file<span class="token operator">|</span><span class="token function">nc</span> -q <span class="token number">10</span> -lp <span class="token number">8899</span>接受：$ <span class="token function">nc</span> -w <span class="token number">10</span> <span class="token number">192.168</span>.0.1 <span class="token number">8899</span><span class="token operator">|</span><span class="token function">tar</span> x</code></pre><p>这两个命令行使用 <code>tar</code> 和 <code>nc</code>（netcat）工具在网络上进行文件的传输。</p><a id="more"></a><p>以下是对每个命令的详细解析：</p><h3 id="同步命令"><a href="#同步命令" class="headerlink" title="同步命令"></a>同步命令</h3><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">tar</span> c test-file <span class="token operator">|</span> <span class="token function">nc</span> -q <span class="token number">10</span> -lp <span class="token number">8899</span></code></pre><h4 id="解析："><a href="#解析：" class="headerlink" title="解析："></a>解析：</h4><ul><li><p><code>tar c test-file</code>：</p><ul><li><code>tar</code> 是一个用于打包和压缩文件的工具。</li><li><code>c</code> 表示创建一个新的 tar 归档。</li><li><code>test-file</code> 是要被打包的文件或目录（可以是单个文件，也可以是多个文件或目录，具体取决于实际情况）。</li></ul></li><li><p><code>|</code> （管道符）：</p><ul><li>将 <code>tar</code> 命令的输出传递给下一个命令。</li></ul></li><li><p><code>nc -q 10 -lp 8899</code>：</p><ul><li><code>nc</code>（netcat）是一个网络工具，用于读写网络连接。</li><li><code>-q 10</code> 表示在发送完数据后，等待 10 秒，然后关闭连接。</li><li><code>-l</code> 表示以监听模式运行。</li><li><code>-p 8899</code> 指定监听的端口为 8899。</li></ul></li></ul><h4 id="整体作用："><a href="#整体作用：" class="headerlink" title="整体作用："></a>整体作用：</h4><p>这个命令的作用是将 <code>test-file</code> 打包后通过 TCP 协议在本地端口 8899 发送。此命令会一直监听该端口，直到接收到连接并发送完数据。</p><h3 id="接收命令"><a href="#接收命令" class="headerlink" title="接收命令"></a>接收命令</h3><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">nc</span> -w <span class="token number">10</span> <span class="token number">192.168</span>.0.1 <span class="token number">8899</span> <span class="token operator">|</span> <span class="token function">tar</span> x</code></pre><h4 id="解析：-1"><a href="#解析：-1" class="headerlink" title="解析："></a>解析：</h4><ul><li><p><code>nc -w 10 192.168.0.1 8899</code>：</p><ul><li><code>nc</code> 用来创建网络连接。</li><li><code>-w 10</code> 表示在连接关闭后等待 10 秒。</li><li><code>192.168.0.1</code> 是发送请求的目标 IP 地址。</li><li><code>8899</code> 是目标端口。</li></ul></li><li><p><code>| tar x</code>：</p><ul><li><code>tar x</code> 用于解压缩和解包 tar 归档文件。</li><li><code>x</code> 表示提取文件。</li></ul></li></ul><h4 id="整体作用：-1"><a href="#整体作用：-1" class="headerlink" title="整体作用："></a>整体作用：</h4><p>这个命令的作用是连接到 <code>192.168.0.1</code> 的 8899 端口，接收从该端口发送过来的数据流（即 <code>test-file</code> 的 tar 归档），并将其解压到当前目录。</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>这两个命令组合的作用是通过网络将一个文件（<code>test-file</code>）从一台机器发送到另一台机器。第一台机器使用 <code>tar</code> 打包文件并通过 <code>nc</code> 发送，第二台机器使用 <code>nc</code> 接收数据并通过 <code>tar</code> 解压缩。此操作在文件传输和备份等场景中非常有用。</p>]]></content>
    
    
    <summary type="html">&lt;h3 id=&quot;文件传输命令行&quot;&gt;&lt;a href=&quot;#文件传输命令行&quot; class=&quot;headerlink&quot; title=&quot;文件传输命令行&quot;&gt;&lt;/a&gt;文件传输命令行&lt;/h3&gt;&lt;pre class=&quot;language-bash&quot; data-language=&quot;bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;同步：
$ &lt;span class=&quot;token function&quot;&gt;tar&lt;/span&gt; c test-file&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;nc&lt;/span&gt; -q &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; -lp &lt;span class=&quot;token number&quot;&gt;8899&lt;/span&gt;
接受：
$ &lt;span class=&quot;token function&quot;&gt;nc&lt;/span&gt; -w &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;192.168&lt;/span&gt;.0.1 &lt;span class=&quot;token number&quot;&gt;8899&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;tar&lt;/span&gt; x&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;这两个命令行使用 &lt;code&gt;tar&lt;/code&gt; 和 &lt;code&gt;nc&lt;/code&gt;（netcat）工具在网络上进行文件的传输。&lt;/p&gt;</summary>
    
    
    
    <category term="Linux" scheme="https://jueee.github.io/categories/Linux/"/>
    
    
    <category term="Linux" scheme="https://jueee.github.io/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>SpringBoot 中使用 Spring-Retry 重试框架</title>
    <link href="https://jueee.github.io/2025/06/2025-06-24-SpringBoot%E4%B8%AD%E4%BD%BF%E7%94%A8Spring-Retry%E9%87%8D%E8%AF%95%E6%A1%86%E6%9E%B6/"/>
    <id>https://jueee.github.io/2025/06/2025-06-24-SpringBoot%E4%B8%AD%E4%BD%BF%E7%94%A8Spring-Retry%E9%87%8D%E8%AF%95%E6%A1%86%E6%9E%B6/</id>
    <published>2025-06-24T00:00:00.000Z</published>
    <updated>2025-11-06T09:29:58.817Z</updated>
    
    <content type="html"><![CDATA[<p>-XX:G1HeapRegionSize=32M</p><h3 id="引入依赖"><a href="#引入依赖" class="headerlink" title="引入依赖"></a>引入依赖</h3><p>确保在你的项目中添加了 Spring Retry 依赖：</p><pre class="language-xml" data-language="xml"><code class="language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.retry<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-retry<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span></code></pre><a id="more"></a><h3 id="启用配置"><a href="#启用配置" class="headerlink" title="启用配置"></a>启用配置</h3><p>在你的 Spring 配置类中启用重试功能：</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Configuration</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>retry<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">EnableRetry</span><span class="token punctuation">;</span><span class="token annotation punctuation">@Configuration</span><span class="token annotation punctuation">@EnableRetry</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">RetryConfig</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code></pre><h3 id="为方法加入重试"><a href="#为方法加入重试" class="headerlink" title="为方法加入重试"></a>为方法加入重试</h3><p>为了在触发 JSONException 时暂停两分钟后重新请求，我们可以使用重试机制。以下是修改后的代码：</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>retry<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Backoff</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>retry<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Retryable</span><span class="token punctuation">;</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FeatureOperate</span> <span class="token punctuation">{</span>    <span class="token annotation punctuation">@Retryable</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token class-name">JSONException</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">}</span><span class="token punctuation">,</span> maxAttempts <span class="token operator">=</span> <span class="token number">2</span><span class="token punctuation">,</span> backoff <span class="token operator">=</span> <span class="token annotation punctuation">@Backoff</span><span class="token punctuation">(</span>delay <span class="token operator">=</span> <span class="token number">120000</span><span class="token punctuation">)</span><span class="token punctuation">)</span>    <span class="token keyword">private</span> <span class="token keyword">boolean</span> <span class="token function">insert</span><span class="token punctuation">(</span>params……<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token class-name">String</span> res <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>        <span class="token keyword">try</span> <span class="token punctuation">{</span>            res <span class="token operator">=</span> <span class="token class-name">HttpClient4Utils</span><span class="token punctuation">.</span><span class="token function">httpPost</span><span class="token punctuation">(</span>operateUrl<span class="token punctuation">,</span> headerMap<span class="token punctuation">,</span> paramJson<span class="token punctuation">.</span><span class="token function">toJSONString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">Consts</span><span class="token punctuation">.</span>UTF_8<span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token class-name">JSONObject</span> jsonObject <span class="token operator">=</span> <span class="token class-name">JSONObject</span><span class="token punctuation">.</span><span class="token function">parseObject</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">JSONException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>            log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"[res]{} [Message]{} [paramJson]{}"</span><span class="token punctuation">,</span> res<span class="token punctuation">,</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> paramJson<span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token keyword">throw</span> e<span class="token punctuation">;</span> <span class="token comment">// 重新抛出异常，触发重试</span>        <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>            log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"[res]{} [Message]{} [paramJson]{}"</span><span class="token punctuation">,</span> res<span class="token punctuation">,</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> paramJson<span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span>        <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>主要修改如下：</p><ol><li><p>添加了 <code>@Retryable</code> 注解到方法上：</p><ul><li><code>value = {JSONException.class}</code>: 指定要重试的异常类型。</li><li><code>maxAttempts = 2</code>: 设置最大尝试次数为 2（初始尝试 + 1 次重试）。</li><li><code>backoff = @Backoff(delay = 120000)</code>: 设置重试延迟为 120000 毫秒（2 分钟）。</li></ul></li><li><p>在 catch JSONException 的块中，我们重新抛出异常，以触发重试机制。</p></li><li><p>这样，当发生 JSONException 时，方法将等待 2 分钟后重新尝试。如果第二次尝试仍然失败，则方法将返回 false。</p></li></ol><p>请注意，这种方法会增加方法的执行时间。如果这是一个对时间敏感的操作，你可能需要考虑其他的错误处理策略。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;-XX:G1HeapRegionSize=32M&lt;/p&gt;
&lt;h3 id=&quot;引入依赖&quot;&gt;&lt;a href=&quot;#引入依赖&quot; class=&quot;headerlink&quot; title=&quot;引入依赖&quot;&gt;&lt;/a&gt;引入依赖&lt;/h3&gt;&lt;p&gt;确保在你的项目中添加了 Spring Retry 依赖：&lt;/p&gt;
&lt;pre class=&quot;language-xml&quot; data-language=&quot;xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;dependency&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;groupId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;org.springframework.retry&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;groupId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;artifactId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;spring-retry&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;artifactId&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;dependency&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</summary>
    
    
    
    <category term="Java" scheme="https://jueee.github.io/categories/Java/"/>
    
    <category term="SpringBoot" scheme="https://jueee.github.io/categories/Java/SpringBoot/"/>
    
    <category term="JavaJar" scheme="https://jueee.github.io/categories/Java/JavaJar/"/>
    
    
    <category term="SpringBoot" scheme="https://jueee.github.io/tags/SpringBoot/"/>
    
  </entry>
  
  <entry>
    <title>优化 POST 参数解析，使动态解析参数</title>
    <link href="https://jueee.github.io/2025/04/2025-04-09-%E4%BC%98%E5%8C%96POST%E5%8F%82%E6%95%B0%E8%A7%A3%E6%9E%90%EF%BC%8C%E4%BD%BF%E5%8A%A8%E6%80%81%E8%A7%A3%E6%9E%90%E5%8F%82%E6%95%B0/"/>
    <id>https://jueee.github.io/2025/04/2025-04-09-%E4%BC%98%E5%8C%96POST%E5%8F%82%E6%95%B0%E8%A7%A3%E6%9E%90%EF%BC%8C%E4%BD%BF%E5%8A%A8%E6%80%81%E8%A7%A3%E6%9E%90%E5%8F%82%E6%95%B0/</id>
    <published>2025-04-09T00:00:00.000Z</published>
    <updated>2025-04-09T08:35:56.327Z</updated>
    
    <content type="html"><![CDATA[<p>当 POST 方法试图再次读取请求体，但是请求体已经被 Spring 的 @RequestBody 注解消费了。</p><p>我们需要在 @RequestBody 的同时，优化参数解析方法，使其能够动态地从请求中读取其他的额外参数，而不需要预先定义固定的字段。</p><a id="more"></a><p>以下是一个改进的方案：</p><ol><li>首先，我们创建一个自定义的注解来标记我们想要处理的请求：</li></ol><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">ElementType</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Retention</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">RetentionPolicy</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Target</span><span class="token punctuation">;</span><span class="token annotation punctuation">@Target</span><span class="token punctuation">(</span><span class="token class-name">ElementType</span><span class="token punctuation">.</span>METHOD<span class="token punctuation">)</span><span class="token annotation punctuation">@Retention</span><span class="token punctuation">(</span><span class="token class-name">RetentionPolicy</span><span class="token punctuation">.</span>RUNTIME<span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token annotation punctuation">@interface</span> <span class="token class-name">ProcessRequestParams</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></code></pre><ol start="2"><li>然后，我们创建一个 <code>RequestBodyWrapper</code> 类来包装原始的请求体：</li></ol><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">RequestBodyWrapper</span> <span class="token punctuation">{</span>    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> body<span class="token punctuation">;</span>    <span class="token keyword">public</span> <span class="token class-name">RequestBodyWrapper</span><span class="token punctuation">(</span><span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> body<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">this</span><span class="token punctuation">.</span>body <span class="token operator">=</span> body<span class="token punctuation">;</span>    <span class="token punctuation">}</span>    <span class="token keyword">public</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> <span class="token function">getBody</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">return</span> body<span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><ol start="3"><li>为了确保 ContentCachingRequestWrapper 被正确应用，你需要在你的应用中添加一个 Filter：</li></ol><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span><span class="token class-name">Ordered</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>core<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Order</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>stereotype<span class="token punctuation">.</span></span><span class="token class-name">Component</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter<span class="token punctuation">.</span></span><span class="token class-name">OncePerRequestFilter</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">ContentCachingRequestWrapper</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span></span><span class="token class-name">FilterChain</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span></span><span class="token class-name">ServletException</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span>http<span class="token punctuation">.</span></span><span class="token class-name">HttpServletRequest</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span>http<span class="token punctuation">.</span></span><span class="token class-name">HttpServletResponse</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span><span class="token class-name">IOException</span><span class="token punctuation">;</span><span class="token annotation punctuation">@Component</span><span class="token annotation punctuation">@Order</span><span class="token punctuation">(</span><span class="token class-name">Ordered</span><span class="token punctuation">.</span>HIGHEST_PRECEDENCE<span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ContentCachingFilter</span> <span class="token keyword">extends</span> <span class="token class-name">OncePerRequestFilter</span> <span class="token punctuation">{</span>    <span class="token annotation punctuation">@Override</span>    <span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">doFilterInternal</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">,</span> <span class="token class-name">FilterChain</span> filterChain<span class="token punctuation">)</span>            <span class="token keyword">throws</span> <span class="token class-name">ServletException</span><span class="token punctuation">,</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span>        <span class="token class-name">ContentCachingRequestWrapper</span> wrappedRequest <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ContentCachingRequestWrapper</span><span class="token punctuation">(</span>request<span class="token punctuation">)</span><span class="token punctuation">;</span>        filterChain<span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span>wrappedRequest<span class="token punctuation">,</span> response<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><ol start="3"><li>接下来，我们创建一个自定义的 <code>HandlerMethodArgumentResolver</code>：</li></ol><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">import</span> <span class="token namespace">com<span class="token punctuation">.</span>fasterxml<span class="token punctuation">.</span>jackson<span class="token punctuation">.</span>databind<span class="token punctuation">.</span></span><span class="token class-name">ObjectMapper</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">com<span class="token punctuation">.</span>netease<span class="token punctuation">.</span>mdas<span class="token punctuation">.</span>system<span class="token punctuation">.</span>bean<span class="token punctuation">.</span></span><span class="token class-name">RequestBodyWrapper</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span><span class="token class-name">MethodParameter</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">StreamUtils</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>bind<span class="token punctuation">.</span>support<span class="token punctuation">.</span></span><span class="token class-name">WebDataBinderFactory</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>context<span class="token punctuation">.</span>request<span class="token punctuation">.</span></span><span class="token class-name">NativeWebRequest</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>method<span class="token punctuation">.</span>support<span class="token punctuation">.</span></span><span class="token class-name">HandlerMethodArgumentResolver</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>method<span class="token punctuation">.</span>support<span class="token punctuation">.</span></span><span class="token class-name">ModelAndViewContainer</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">ContentCachingRequestWrapper</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">WebUtils</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span>http<span class="token punctuation">.</span></span><span class="token class-name">HttpServletRequest</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span><span class="token class-name">IOException</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>nio<span class="token punctuation">.</span>charset<span class="token punctuation">.</span></span><span class="token class-name">StandardCharsets</span><span class="token punctuation">;</span><span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Map</span><span class="token punctuation">;</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">RequestBodyWrapperArgumentResolver</span> <span class="token keyword">implements</span> <span class="token class-name">HandlerMethodArgumentResolver</span> <span class="token punctuation">{</span>    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">ObjectMapper</span> objectMapper<span class="token punctuation">;</span>    <span class="token keyword">public</span> <span class="token class-name">RequestBodyWrapperArgumentResolver</span><span class="token punctuation">(</span><span class="token class-name">ObjectMapper</span> objectMapper<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">this</span><span class="token punctuation">.</span>objectMapper <span class="token operator">=</span> objectMapper<span class="token punctuation">;</span>    <span class="token punctuation">}</span>    <span class="token annotation punctuation">@Override</span>    <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">supportsParameter</span><span class="token punctuation">(</span><span class="token class-name">MethodParameter</span> parameter<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">return</span> parameter<span class="token punctuation">.</span><span class="token function">getParameterType</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span><span class="token class-name">RequestBodyWrapper</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>    <span class="token annotation punctuation">@Override</span>    <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">resolveArgument</span><span class="token punctuation">(</span><span class="token class-name">MethodParameter</span> parameter<span class="token punctuation">,</span> <span class="token class-name">ModelAndViewContainer</span> mavContainer<span class="token punctuation">,</span>                                  <span class="token class-name">NativeWebRequest</span> webRequest<span class="token punctuation">,</span> <span class="token class-name">WebDataBinderFactory</span> binderFactory<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>        <span class="token class-name">HttpServletRequest</span> nativeRequest <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span><span class="token punctuation">)</span> webRequest<span class="token punctuation">.</span><span class="token function">getNativeRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token class-name">String</span> body <span class="token operator">=</span> <span class="token function">getRequestBody</span><span class="token punctuation">(</span>nativeRequest<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span>body <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>body<span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>            <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> map <span class="token operator">=</span> objectMapper<span class="token punctuation">.</span><span class="token function">readValue</span><span class="token punctuation">(</span>body<span class="token punctuation">,</span> <span class="token class-name">Map</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">RequestBodyWrapper</span><span class="token punctuation">(</span>map<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span>        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">RequestBodyWrapper</span><span class="token punctuation">(</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>    <span class="token keyword">private</span> <span class="token class-name">String</span> <span class="token function">getRequestBody</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span>        <span class="token class-name">ContentCachingRequestWrapper</span> wrapper <span class="token operator">=</span> <span class="token class-name">WebUtils</span><span class="token punctuation">.</span><span class="token function">getNativeRequest</span><span class="token punctuation">(</span>request<span class="token punctuation">,</span> <span class="token class-name">ContentCachingRequestWrapper</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span>wrapper <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>            <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> buf <span class="token operator">=</span> wrapper<span class="token punctuation">.</span><span class="token function">getContentAsByteArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token keyword">if</span> <span class="token punctuation">(</span>buf<span class="token punctuation">.</span>length <span class="token operator">&gt;</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span>buf<span class="token punctuation">,</span> <span class="token class-name">StandardCharsets</span><span class="token punctuation">.</span>UTF_8<span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token punctuation">}</span>        <span class="token punctuation">}</span>        <span class="token comment">// 如果不是 ContentCachingRequestWrapper，则直接读取输入流</span>        <span class="token keyword">return</span> <span class="token class-name">StreamUtils</span><span class="token punctuation">.</span><span class="token function">copyToString</span><span class="token punctuation">(</span>request<span class="token punctuation">.</span><span class="token function">getInputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">StandardCharsets</span><span class="token punctuation">.</span>UTF_8<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><ol start="4"><li>在 Spring 配置中注册这个 <code>ArgumentResolver</code>：</li></ol><pre class="language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Configuration</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">WebMvcConfig</span> <span class="token keyword">implements</span> <span class="token class-name">WebMvcConfigurer</span> <span class="token punctuation">{</span>    <span class="token annotation punctuation">@Autowired</span>    <span class="token keyword">private</span> <span class="token class-name">ObjectMapper</span> objectMapper<span class="token punctuation">;</span>    <span class="token annotation punctuation">@Override</span>    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">addArgumentResolvers</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">HandlerMethodArgumentResolver</span><span class="token punctuation">&gt;</span></span> resolvers<span class="token punctuation">)</span> <span class="token punctuation">{</span>        resolvers<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">RequestBodyWrapperArgumentResolver</span><span class="token punctuation">(</span>objectMapper<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><ol start="5"><li>修改 <code>SearchController</code>：</li></ol><pre class="language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@ApiOperation</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"邮件列表"</span><span class="token punctuation">,</span> notes <span class="token operator">=</span> <span class="token string">"邮件列表,根据条件名模糊查询"</span><span class="token punctuation">)</span><span class="token annotation punctuation">@PostMapping</span><span class="token punctuation">(</span><span class="token string">"/findList"</span><span class="token punctuation">)</span><span class="token annotation punctuation">@ProcessRequestParams</span><span class="token keyword">public</span> <span class="token class-name">ResponseBean</span> <span class="token function">findList</span><span class="token punctuation">(</span><span class="token annotation punctuation">@RequestHeader</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"systemproduct"</span><span class="token punctuation">)</span> <span class="token class-name">String</span> orgId<span class="token punctuation">,</span>                              <span class="token annotation punctuation">@RequestBody</span> <span class="token class-name">FeedbackSearchVO</span> dto<span class="token punctuation">,</span>                             <span class="token class-name">RequestBodyWrapper</span> wrapper<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token comment">// ... 其他代码保持不变 ...</span>    dto<span class="token punctuation">.</span><span class="token function">setOtherInfoQuery</span><span class="token punctuation">(</span><span class="token function">initOtherInfoQuery</span><span class="token punctuation">(</span>wrapper<span class="token punctuation">.</span><span class="token function">getBody</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token comment">// ... 其他代码保持不变 ...</span><span class="token punctuation">}</span></code></pre><ol start="6"><li>最后，修改 <code>initOtherInfoQuery</code> 方法：</li></ol><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">List</span><span class="token punctuation">&lt;</span><span class="token class-name">JSONObject</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> <span class="token function">initOtherInfoQuery</span><span class="token punctuation">(</span><span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> requestBody<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">List</span><span class="token punctuation">&lt;</span><span class="token class-name">JSONObject</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> otherInfoQuery <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Map</span><span class="token punctuation">.</span><span class="token class-name">Entry</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> entry <span class="token operator">:</span> requestBody<span class="token punctuation">.</span><span class="token function">entrySet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token class-name">String</span> key <span class="token operator">=</span> entry<span class="token punctuation">.</span><span class="token function">getKey</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token class-name">Object</span> value <span class="token operator">=</span> entry<span class="token punctuation">.</span><span class="token function">getValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token keyword">if</span> <span class="token punctuation">(</span>value <span class="token keyword">instanceof</span> <span class="token class-name">List</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>            <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">JSONObject</span><span class="token punctuation">&gt;</span></span> jsonList <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Object</span> item <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">)</span> value<span class="token punctuation">)</span> <span class="token punctuation">{</span>                jsonList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">JSONObject</span><span class="token punctuation">(</span>item<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            <span class="token punctuation">}</span>            otherInfoQuery<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> jsonList<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>            <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">JSONObject</span><span class="token punctuation">&gt;</span></span> jsonList <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            jsonList<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">JSONObject</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            otherInfoQuery<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> jsonList<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span>    <span class="token punctuation">}</span>    <span class="token keyword">return</span> otherInfoQuery<span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p>这种方法的优点是：</p><ol><li>它可以动态处理所有请求参数，不需要预先定义固定的字段。</li><li>它不会干扰 <code>@RequestBody</code> 的正常工作。</li><li>它允许你同时访问解析后的 DTO 和原始请求体。</li></ol><p>这个解决方案应该能够处理动态的参数，而不需要在代码中硬编码这些参数名。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;当 POST 方法试图再次读取请求体，但是请求体已经被 Spring 的 @RequestBody 注解消费了。&lt;/p&gt;
&lt;p&gt;我们需要在 @RequestBody 的同时，优化参数解析方法，使其能够动态地从请求中读取其他的额外参数，而不需要预先定义固定的字段。&lt;/p&gt;</summary>
    
    
    
    <category term="Java" scheme="https://jueee.github.io/categories/Java/"/>
    
    
    <category term="Java" scheme="https://jueee.github.io/tags/Java/"/>
    
  </entry>
  
  <entry>
    <title>Linux 查找搜索相关命令行汇总</title>
    <link href="https://jueee.github.io/2025/03/2025-03-18-Linux%E6%9F%A5%E6%89%BE%E6%90%9C%E7%B4%A2%E7%9B%B8%E5%85%B3%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%B1%87%E6%80%BB/"/>
    <id>https://jueee.github.io/2025/03/2025-03-18-Linux%E6%9F%A5%E6%89%BE%E6%90%9C%E7%B4%A2%E7%9B%B8%E5%85%B3%E5%91%BD%E4%BB%A4%E8%A1%8C%E6%B1%87%E6%80%BB/</id>
    <published>2025-03-18T00:00:00.000Z</published>
    <updated>2025-03-18T02:33:06.919Z</updated>
    
    <content type="html"><![CDATA[<h3 id="查找文件"><a href="#查找文件" class="headerlink" title="查找文件"></a>查找文件</h3><p>查找包含 "aaa" 的文件</p><pre class="language-none"><code class="language-none">grep -rl "aaa" /path/to/directory</code></pre><h3 id="汇总出现次数"><a href="#汇总出现次数" class="headerlink" title="汇总出现次数"></a>汇总出现次数</h3><p>汇总出现的字符次数：</p><pre class="language-none"><code class="language-none">grep -ro "aaa" /path/to/directory | wc -l</code></pre><p>将找到的文件名和出现次数汇总在一起：</p><pre class="language-none"><code class="language-none">for file in $(grep -rl "mail" /home/dir/test); do     count=$(grep -o "mail" "$file" | wc -l);     echo "$file: $count"; done</code></pre>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;查找文件&quot;&gt;&lt;a href=&quot;#查找文件&quot; class=&quot;headerlink&quot; title=&quot;查找文件&quot;&gt;&lt;/a&gt;查找文件&lt;/h3&gt;&lt;p&gt;查找包含 &quot;aaa&quot; 的文件&lt;/p&gt;
&lt;pre class=&quot;language-none&quot;&gt;&lt;code class=&quot;lan</summary>
      
    
    
    
    <category term="Linux" scheme="https://jueee.github.io/categories/Linux/"/>
    
    
    <category term="Linux" scheme="https://jueee.github.io/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>网易内推参与说明｜无偿、直通 HR、进度可查</title>
    <link href="https://jueee.github.io/2025/01/2025-01-01-%E7%BD%91%E6%98%93%E5%86%85%E6%8E%A8%E5%8F%82%E4%B8%8E%E8%AF%B4%E6%98%8E/"/>
    <id>https://jueee.github.io/2025/01/2025-01-01-%E7%BD%91%E6%98%93%E5%86%85%E6%8E%A8%E5%8F%82%E4%B8%8E%E8%AF%B4%E6%98%8E/</id>
    <published>2025-01-01T00:00:00.000Z</published>
    <updated>2025-10-28T03:30:11.001Z</updated>
    
    <content type="html"><![CDATA[<h3 id="内推说明"><a href="#内推说明" class="headerlink" title="内推说明"></a>内推说明</h3><p>作为在网易近十年的 “老网易”，很乐意做你的求职伙伴！</p><p>社招 / 实习均可内推，全程护航助你避开海笔筛选，直连 HR 团队效率拉满！ </p><h4 id="岗位城市"><a href="#岗位城市" class="headerlink" title="岗位城市"></a>岗位城市</h4><p><strong>北京</strong>、<strong>广州</strong>、<strong>杭州</strong>、<strong>上海</strong>、<strong>成都</strong> 等。</p><h4 id="可选部门"><a href="#可选部门" class="headerlink" title="可选部门"></a>可选部门</h4><p>网易游戏、网易云音乐、网易有道、网易邮箱、Lofter 等都可以！</p><h4 id="岗位类型"><a href="#岗位类型" class="headerlink" title="岗位类型"></a>岗位类型</h4><p>包括但不限于 技术、产品、运营、项目管理、市场渠道、销售、内容、电商、教育、职能支持、游戏策划、游戏程序、游戏艺术、游戏测试、人工智能、用户体验及设计、高管、企业服务 等等，总有一款适合你～～</p><h3 id="内推操作指南"><a href="#内推操作指南" class="headerlink" title="内推操作指南"></a>内推操作指南</h3><p>1️⃣ 登录 <span class="exturl" data-url="aHR0cHM6Ly9oci4xNjMuY29tL2pvYi1saXN0Lmh0bWw=">网易社会招聘官网<i class="fa fa-external-link-alt"></i></span> :hr.163.com，挑选心仪岗位 </p><p>2️⃣ 邮箱发我岗位信息（截图 or 链接 or 岗位名称），地址：<strong>hellojue#foxmail.com</strong>,  <strong>#替换成 @</strong></p><p>3️⃣ 我回复你独属内推邀请海报 </p><p>4️⃣ 你扫码填信息，并按邮件指引补全简历即完成内推！（简历直达 HR） </p><h3 id="内推优势"><a href="#内推优势" class="headerlink" title="内推优势"></a>内推优势</h3><p>✅ 免部分岗位海笔筛选 </p><p>✅ 直推业务团队，流程加速 </p><p>✅ 全程跟进进度，可私聊查询状态 </p><p>✅ 隐私保护（简历仅 HR 可见，零泄露风险）</p><p>如果与其他问题，可以随时沟通～～</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;内推说明&quot;&gt;&lt;a href=&quot;#内推说明&quot; class=&quot;headerlink&quot; title=&quot;内推说明&quot;&gt;&lt;/a&gt;内推说明&lt;/h3&gt;&lt;p&gt;作为在网易近十年的 “老网易”，很乐意做你的求职伙伴！&lt;/p&gt;
&lt;p&gt;社招 / 实习均可内推，全程护航助你避开海笔筛选，直连</summary>
      
    
    
    
    <category term="Blog" scheme="https://jueee.github.io/categories/Blog/"/>
    
    
    <category term="Blog" scheme="https://jueee.github.io/tags/Blog/"/>
    
  </entry>
  
  <entry>
    <title>轮询请求并动态刷新列表数据</title>
    <link href="https://jueee.github.io/2024/10/2024-10-23-%E8%BD%AE%E8%AF%A2%E8%AF%B7%E6%B1%82%E5%B9%B6%E5%8A%A8%E6%80%81%E5%88%B7%E6%96%B0%E5%88%97%E8%A1%A8%E6%95%B0%E6%8D%AE/"/>
    <id>https://jueee.github.io/2024/10/2024-10-23-%E8%BD%AE%E8%AF%A2%E8%AF%B7%E6%B1%82%E5%B9%B6%E5%8A%A8%E6%80%81%E5%88%B7%E6%96%B0%E5%88%97%E8%A1%A8%E6%95%B0%E6%8D%AE/</id>
    <published>2024-10-23T00:00:00.000Z</published>
    <updated>2025-08-06T07:01:06.992Z</updated>
    
    <content type="html"><![CDATA[<p>对于耗时比较久的操作，需要前端页面实时请求更新已处理的结果。</p><p>一个用于启动异步处理的接口，另一个用于查询处理状态和结果的接口。实现异步处理和轮询查询的功能。</p><a id="more"></a><h3 id="原始逻辑"><a href="#原始逻辑" class="headerlink" title="原始逻辑"></a>原始逻辑</h3><pre class="language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@GetMapping</span><span class="token punctuation">(</span><span class="token string">"/accountCheck"</span><span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token class-name">ResponseBean</span> <span class="token function">accountCheck</span><span class="token punctuation">(</span><span class="token annotation punctuation">@RequestHeader</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"teamId"</span><span class="token punctuation">)</span> <span class="token class-name">String</span> teamId<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Account</span><span class="token punctuation">&gt;</span></span> <span class="token class-name">AccountList</span> <span class="token operator">=</span> <span class="token class-name">AccountService</span><span class="token punctuation">.</span><span class="token function">findAll</span><span class="token punctuation">(</span>teamId<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AccountEdit</span><span class="token punctuation">&gt;</span></span> accountEdits <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">LinkedList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Account</span> account <span class="token operator">:</span> <span class="token class-name">AccountList</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token class-name">AccountEdit</span> accountEdit <span class="token operator">=</span> <span class="token class-name">AccountService</span><span class="token punctuation">.</span><span class="token function">edit</span><span class="token punctuation">(</span>account<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token class-name">ResponseBean</span> checkRes <span class="token operator">=</span> <span class="token class-name">AccountCheckUtils</span><span class="token punctuation">.</span><span class="token function">checkAccount</span><span class="token punctuation">(</span>accountEdit<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">if</span> <span class="token punctuation">(</span>checkRes<span class="token punctuation">.</span><span class="token function">isError</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>            accountEdit<span class="token punctuation">.</span><span class="token function">setAuthParams</span><span class="token punctuation">(</span>checkRes<span class="token punctuation">.</span><span class="token function">getMsg</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>            accountEdits<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>accountEdit<span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token punctuation">}</span>    <span class="token punctuation">}</span>    <span class="token class-name">String</span> info <span class="token operator">=</span> <span class="token string">"校验完成，共"</span> <span class="token operator">+</span> accountEdits<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"个账号，其中有"</span> <span class="token operator">+</span> accountEdits<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"个账号校验失败！"</span><span class="token punctuation">;</span>    <span class="token keyword">return</span> <span class="token class-name">ResponseBean</span><span class="token punctuation">.</span><span class="token function">success</span><span class="token punctuation">(</span>info<span class="token punctuation">,</span> accountEdits<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h3 id="异步轮询"><a href="#异步轮询" class="headerlink" title="异步轮询"></a>异步轮询</h3><p>我们可以将这个过程分为两个部分：一个用于启动异步处理的接口，另一个用于查询处理状态和结果的接口。这样可以实现异步处理和轮询查询的功能。以下是优化后的代码：</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Autowired</span><span class="token keyword">private</span> <span class="token class-name">AccountService</span> <span class="token class-name">AccountService</span><span class="token punctuation">;</span><span class="token annotation punctuation">@Autowired</span><span class="token annotation punctuation">@Qualifier</span><span class="token punctuation">(</span><span class="token string">"applicationTaskExecutor"</span><span class="token punctuation">)</span><span class="token keyword">private</span> <span class="token class-name">AsyncTaskExecutor</span> asyncTaskExecutor<span class="token punctuation">;</span><span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">ConcurrentMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">AccountCheckTask</span><span class="token punctuation">&gt;</span></span> taskMap <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ConcurrentHashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token annotation punctuation">@GetMapping</span><span class="token punctuation">(</span><span class="token string">"/startAccountCheck"</span><span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token class-name">ResponseBean</span> <span class="token function">startAccountCheck</span><span class="token punctuation">(</span><span class="token annotation punctuation">@RequestHeader</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"teamId"</span><span class="token punctuation">)</span> <span class="token class-name">String</span> teamId<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token class-name">String</span> taskId <span class="token operator">=</span> <span class="token class-name">ActiveInfo</span><span class="token punctuation">.</span><span class="token function">userName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">+</span>teamId<span class="token punctuation">;</span>    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Account</span><span class="token punctuation">&gt;</span></span> <span class="token class-name">AccountList</span> <span class="token operator">=</span> <span class="token class-name">AccountService</span><span class="token punctuation">.</span><span class="token function">findAll</span><span class="token punctuation">(</span>teamId<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token class-name">AccountCheckTask</span> task <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AccountCheckTask</span><span class="token punctuation">(</span><span class="token class-name">AccountList</span><span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    taskMap<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>taskId<span class="token punctuation">,</span> task<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token class-name">CompletableFuture</span><span class="token punctuation">.</span><span class="token function">runAsync</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> <span class="token function">processAccounts</span><span class="token punctuation">(</span><span class="token class-name">AccountList</span><span class="token punctuation">,</span> task<span class="token punctuation">)</span><span class="token punctuation">,</span> asyncTaskExecutor<span class="token punctuation">)</span>            <span class="token punctuation">.</span><span class="token function">thenRun</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-&gt;</span> task<span class="token punctuation">.</span><span class="token function">setCompleted</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> response <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    response<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"taskId"</span><span class="token punctuation">,</span> taskId<span class="token punctuation">)</span><span class="token punctuation">;</span>    response<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"totalAccounts"</span><span class="token punctuation">,</span> <span class="token class-name">AccountList</span><span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">return</span> <span class="token class-name">ResponseBean</span><span class="token punctuation">.</span><span class="token function">successMap</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">,</span>response<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token annotation punctuation">@GetMapping</span><span class="token punctuation">(</span><span class="token string">"/getAccountCheckResult"</span><span class="token punctuation">)</span><span class="token keyword">public</span> <span class="token class-name">ResponseBean</span> <span class="token function">getAccountCheckResult</span><span class="token punctuation">(</span><span class="token annotation punctuation">@RequestHeader</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">"teamId"</span><span class="token punctuation">)</span> <span class="token class-name">String</span> teamId<span class="token punctuation">)</span> <span class="token punctuation">{</span>    <span class="token class-name">String</span> taskId <span class="token operator">=</span> <span class="token class-name">ActiveInfo</span><span class="token punctuation">.</span><span class="token function">userName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">+</span>teamId<span class="token punctuation">;</span>    <span class="token class-name">AccountCheckTask</span> task <span class="token operator">=</span> taskMap<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>taskId<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span>task <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">return</span> <span class="token class-name">ResponseBean</span><span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"Task not found"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>    <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> result <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashMap</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    result<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"totalAccounts"</span><span class="token punctuation">,</span> task<span class="token punctuation">.</span><span class="token function">getTotalAccounts</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    result<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"processedAccounts"</span><span class="token punctuation">,</span> task<span class="token punctuation">.</span><span class="token function">getProcessedAccounts</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    result<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"remainingAccounts"</span><span class="token punctuation">,</span> task<span class="token punctuation">.</span><span class="token function">getRemainingAccounts</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    result<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"completed"</span><span class="token punctuation">,</span> task<span class="token punctuation">.</span><span class="token function">isCompleted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token class-name">String</span> statusInfo <span class="token operator">=</span> <span class="token string">"进行中"</span><span class="token punctuation">;</span>    <span class="token keyword">if</span> <span class="token punctuation">(</span>task<span class="token punctuation">.</span><span class="token function">isCompleted</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        statusInfo <span class="token operator">=</span> <span class="token string">"已完成"</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AccountEdit</span><span class="token punctuation">&gt;</span></span> failedAccounts <span class="token operator">=</span> task<span class="token punctuation">.</span><span class="token function">getFailedAccounts</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token class-name">String</span> info <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"账号校验%s（共 %d 个账号）：已检测 %d 个账号，其中有 %d 个账号校验失败！"</span><span class="token punctuation">,</span>statusInfo<span class="token punctuation">,</span>            task<span class="token punctuation">.</span><span class="token function">getTotalAccounts</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> task<span class="token punctuation">.</span><span class="token function">getProcessedAccounts</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> failedAccounts<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    result<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"info"</span><span class="token punctuation">,</span> info<span class="token punctuation">)</span><span class="token punctuation">;</span>    result<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span><span class="token string">"failedAccounts"</span><span class="token punctuation">,</span> failedAccounts<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">return</span> <span class="token class-name">ResponseBean</span><span class="token punctuation">.</span><span class="token function">successMap</span><span class="token punctuation">(</span>info<span class="token punctuation">,</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">processAccounts</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Account</span><span class="token punctuation">&gt;</span></span> accounts<span class="token punctuation">,</span> <span class="token class-name">AccountCheckTask</span> task<span class="token punctuation">)</span> <span class="token punctuation">{</span>    accounts<span class="token punctuation">.</span><span class="token function">stream</span><span class="token punctuation">(</span><span class="token punctuation">)</span>            <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>account <span class="token operator">-&gt;</span> <span class="token class-name">AccountService</span><span class="token punctuation">.</span><span class="token function">edit</span><span class="token punctuation">(</span>account<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>            <span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span>accountEdit <span class="token operator">-&gt;</span> <span class="token punctuation">{</span>                <span class="token keyword">try</span> <span class="token punctuation">{</span>                    <span class="token class-name">ResponseBean</span> checkRes <span class="token operator">=</span> <span class="token class-name">AccountCheckUtils</span><span class="token punctuation">.</span><span class="token function">checkAccount</span><span class="token punctuation">(</span>accountEdit<span class="token punctuation">)</span><span class="token punctuation">;</span>                    <span class="token keyword">if</span> <span class="token punctuation">(</span>checkRes<span class="token punctuation">.</span><span class="token function">isError</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>                        accountEdit<span class="token punctuation">.</span><span class="token function">setAuthParams</span><span class="token punctuation">(</span>checkRes<span class="token punctuation">.</span><span class="token function">getMsg</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                        task<span class="token punctuation">.</span><span class="token function">addFailedAccount</span><span class="token punctuation">(</span>accountEdit<span class="token punctuation">)</span><span class="token punctuation">;</span>                    <span class="token punctuation">}</span>                <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>                    log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">"Error checking account: "</span> <span class="token operator">+</span> accountEdit<span class="token punctuation">.</span><span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span>                    accountEdit<span class="token punctuation">.</span><span class="token function">setAuthParams</span><span class="token punctuation">(</span><span class="token string">"检查过程中发生错误: "</span> <span class="token operator">+</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                    task<span class="token punctuation">.</span><span class="token function">addFailedAccount</span><span class="token punctuation">(</span>accountEdit<span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>                    task<span class="token punctuation">.</span><span class="token function">incrementProcessedAccounts</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                <span class="token punctuation">}</span>            <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><p>其中</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Data</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AccountCheckTask</span> <span class="token punctuation">{</span>    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token keyword">int</span> totalAccounts<span class="token punctuation">;</span>    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">AtomicInteger</span> processedAccounts <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AtomicInteger</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">AccountEdit</span><span class="token punctuation">&gt;</span></span> failedAccounts <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CopyOnWriteArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">private</span> <span class="token keyword">volatile</span> <span class="token keyword">boolean</span> completed <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span>    <span class="token keyword">public</span> <span class="token class-name">AccountCheckTask</span><span class="token punctuation">(</span><span class="token keyword">int</span> totalAccounts<span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">this</span><span class="token punctuation">.</span>totalAccounts <span class="token operator">=</span> totalAccounts<span class="token punctuation">;</span>    <span class="token punctuation">}</span>    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">incrementProcessedAccounts</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        processedAccounts<span class="token punctuation">.</span><span class="token function">incrementAndGet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>    <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">getRemainingAccounts</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token keyword">return</span> totalAccounts <span class="token operator">-</span> processedAccounts<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span>    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">addFailedAccount</span><span class="token punctuation">(</span><span class="token class-name">AccountEdit</span> account<span class="token punctuation">)</span> <span class="token punctuation">{</span>        failedAccounts<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>account<span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h3 id="前端轮询"><a href="#前端轮询" class="headerlink" title="前端轮询"></a>前端轮询</h3><pre class="language-react" data-language="react"><code class="language-react">const [checkStatus, setCheckStatus] = useState(false);const [accountList, setAccountList] = useState([]);const [checkInfo, setCheckInfo] = useState('');const startAccountList = async () =&gt; {    const { data } = await axios    .get('/AccountCheck/startAccountCheck');    let intervalId = null;    const fetchData = async () =&gt; {        const { data } = await axios        .get('/AccountCheck/getAccountCheckResult');        setAccountList(data.map.failedAccounts.map(convertToListBean));        setCheckInfo(data.map.info)        if(data.map.completed){            setCheckStatus(false)            clearInterval(intervalId);        } else {            setCheckStatus(true)        }    };    fetchData();// 立即执行一次    // 然后设置定时器    intervalId = setInterval(fetchData, 5000);    return () =&gt; {        if (intervalId) {            clearInterval(intervalId);        }    };};</code></pre><h3 id="异常处理"><a href="#异常处理" class="headerlink" title="异常处理"></a>异常处理</h3><h4 id="错误说明"><a href="#错误说明" class="headerlink" title="错误说明"></a>错误说明</h4><pre class="language-none"><code class="language-none">***************************APPLICATION FAILED TO START***************************Description:Field asyncTaskExecutor in xxx...Controller required a single bean, but 2 were found:- applicationTaskExecutor: defined by method 'applicationTaskExecutor' in class path resource [org/springframework/boot/autoconfigure/task/TaskExecutionAutoConfiguration.class]- taskScheduler: defined by method 'taskScheduler' in class path resource [org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfiguration.class]</code></pre><h4 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h4><p>这个错误表明 Spring 容器中存在多个 AsyncTaskExecutor 的 bean 定义，导致注入冲突。解决这个问题有几种方法：</p><h5 id="使用-Qualifier-注解"><a href="#使用-Qualifier-注解" class="headerlink" title="使用 @Qualifier 注解"></a>使用 @Qualifier 注解</h5><p>使用 @Qualifier 注解指定要注入的具体 bean：</p><p>在你的 AccountCheckController 类中，将：</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Autowired</span><span class="token keyword">private</span> <span class="token class-name">AsyncTaskExecutor</span> asyncTaskExecutor<span class="token punctuation">;</span></code></pre><p>改为：</p><pre class="language-none"><code class="language-none">@Autowired@Qualifier("applicationTaskExecutor")private AsyncTaskExecutor asyncTaskExecutor;</code></pre><h5 id="定义AsyncTaskExecutor"><a href="#定义AsyncTaskExecutor" class="headerlink" title="定义AsyncTaskExecutor"></a>定义 AsyncTaskExecutor</h5><p>在你的配置类中明确定义一个 AsyncTaskExecutor bean：</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Configuration</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AsyncConfig</span> <span class="token punctuation">{</span>    <span class="token annotation punctuation">@Bean</span>    <span class="token keyword">public</span> <span class="token class-name">AsyncTaskExecutor</span> <span class="token function">asyncTaskExecutor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token class-name">ThreadPoolTaskExecutor</span> executor <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ThreadPoolTaskExecutor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        executor<span class="token punctuation">.</span><span class="token function">setCorePoolSize</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        executor<span class="token punctuation">.</span><span class="token function">setMaxPoolSize</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        executor<span class="token punctuation">.</span><span class="token function">setQueueCapacity</span><span class="token punctuation">(</span><span class="token number">25</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        executor<span class="token punctuation">.</span><span class="token function">setThreadNamePrefix</span><span class="token punctuation">(</span><span class="token string">"MyAsync-"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        executor<span class="token punctuation">.</span><span class="token function">initialize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>        <span class="token keyword">return</span> executor<span class="token punctuation">;</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>然后在控制器中使用 @Qualifier 注入这个 bean：</p><pre class="language-none"><code class="language-none">@Autowired@Qualifier("asyncTaskExecutor")private AsyncTaskExecutor asyncTaskExecutor;</code></pre><h5 id="禁用自动配置"><a href="#禁用自动配置" class="headerlink" title="禁用自动配置"></a>禁用自动配置</h5><p>如果你不需要自定义 AsyncTaskExecutor，可以在 application.properties 或 application.yml 中禁用自动配置：</p><pre class="language-properties" data-language="properties"><code class="language-properties"><span class="token attr-name">spring.task.execution.pool.enabled</span><span class="token punctuation">=</span><span class="token attr-value">false</span><span class="token attr-name">spring.task.scheduling.pool.enabled</span><span class="token punctuation">=</span><span class="token attr-value">false</span></code></pre><h5 id="使用-Primary-注解"><a href="#使用-Primary-注解" class="headerlink" title="使用 @Primary 注解"></a>使用 @Primary 注解</h5><p>使用 @Primary 注解标记首选的 bean：</p><p>在你的配置类中：</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Configuration</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AsyncConfig</span> <span class="token punctuation">{</span>    <span class="token annotation punctuation">@Bean</span>    <span class="token annotation punctuation">@Primary</span>    <span class="token keyword">public</span> <span class="token class-name">AsyncTaskExecutor</span> <span class="token function">asyncTaskExecutor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token comment">// ... 配置和返回 AsyncTaskExecutor</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><h5 id="使用不同的名称"><a href="#使用不同的名称" class="headerlink" title="使用不同的名称"></a>使用不同的名称</h5><p>如果你确实需要多个 AsyncTaskExecutor，可以考虑使用不同的名称：</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Configuration</span><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AsyncConfig</span> <span class="token punctuation">{</span>    <span class="token annotation punctuation">@Bean</span>    <span class="token keyword">public</span> <span class="token class-name">AsyncTaskExecutor</span> <span class="token function">myAsyncTaskExecutor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>        <span class="token comment">// ... 配置和返回 AsyncTaskExecutor</span>    <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>然后在控制器中：</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token annotation punctuation">@Autowired</span><span class="token annotation punctuation">@Qualifier</span><span class="token punctuation">(</span><span class="token string">"myAsyncTaskExecutor"</span><span class="token punctuation">)</span><span class="token keyword">private</span> <span class="token class-name">AsyncTaskExecutor</span> asyncTaskExecutor<span class="token punctuation">;</span></code></pre><p>选择最适合你的项目结构和需求的方法。</p><p>通常，使用 @Qualifier 或定义一个明确的 bean 是最直接的解决方案。</p><p>如果你的项目中确实需要多个 AsyncTaskExecutor，确保它们有不同的名称，并在注入时使用 @Qualifier 指定正确的 bean。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;对于耗时比较久的操作，需要前端页面实时请求更新已处理的结果。&lt;/p&gt;
&lt;p&gt;一个用于启动异步处理的接口，另一个用于查询处理状态和结果的接口。实现异步处理和轮询查询的功能。&lt;/p&gt;</summary>
    
    
    
    <category term="Java" scheme="https://jueee.github.io/categories/Java/"/>
    
    <category term="JavaClass" scheme="https://jueee.github.io/categories/Java/JavaClass/"/>
    
    
    <category term="Java" scheme="https://jueee.github.io/tags/Java/"/>
    
    <category term="JavaClass" scheme="https://jueee.github.io/tags/JavaClass/"/>
    
  </entry>
  
  <entry>
    <title>根据拼音提取首字母</title>
    <link href="https://jueee.github.io/2024/09/2024-09-30-%E6%A0%B9%E6%8D%AE%E6%8B%BC%E9%9F%B3%E6%8F%90%E5%8F%96%E9%A6%96%E5%AD%97%E6%AF%8D/"/>
    <id>https://jueee.github.io/2024/09/2024-09-30-%E6%A0%B9%E6%8D%AE%E6%8B%BC%E9%9F%B3%E6%8F%90%E5%8F%96%E9%A6%96%E5%AD%97%E6%AF%8D/</id>
    <published>2024-09-30T00:00:00.000Z</published>
    <updated>2024-09-30T09:18:59.898Z</updated>
    
    <content type="html"><![CDATA[<p>根据拼音提取首字母，例如将连续的拼音字符串（如 "zhongguorenmin"）分解为单独的拼音（如 ["zhong", "guo", "ren", "min"]），并能提取出拼音的首字母缩写（如 "zgrm"）。</p><a id="more"></a><h3 id="实现代码"><a href="#实现代码" class="headerlink" title="实现代码"></a>实现代码</h3><p>这段代码实现了一个拼音分词和缩写提取的功能。</p><p>代码主要部分：</p><ol><li>TrieNode 类： 实现了一个字典树（Trie）的节点，用于存储拼音。</li><li>insert 函数： 将拼音插入到 Trie 中。</li><li>search_longest 函数： 在 Trie 中搜索最长匹配的拼音。</li><li>extract_initials_and_full 函数： 将输入的文本分解为拼音，返回完整拼音列表。</li><li>get_initials 函数： 从完整拼音列表中提取首字母，生成缩写。</li><li>拼音数据： 定义了声母（initials）和韵母（finals）列表。</li><li>生成有效拼音： 通过组合声母和韵母，生成有效的拼音列表。</li><li>特殊情况处理： 添加了一些特殊的拼音情况。</li><li>构建 Trie： 使用有效拼音列表构建 Trie。</li><li>测试用例： 使用一系列测试用例来演示代码的功能。</li></ol><p>它使用 Trie 结构来高效地匹配最长的有效拼音，从而实现准确的拼音分词。</p><pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">class</span> <span class="token class-name">TrieNode</span><span class="token punctuation">:</span>    <span class="token keyword">def</span> <span class="token function">__init__</span><span class="token punctuation">(</span>self<span class="token punctuation">)</span><span class="token punctuation">:</span>        self<span class="token punctuation">.</span>children <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>        self<span class="token punctuation">.</span>is_end <span class="token operator">=</span> <span class="token boolean">False</span>        self<span class="token punctuation">.</span>full <span class="token operator">=</span> <span class="token string">''</span><span class="token keyword">def</span> <span class="token function">insert</span><span class="token punctuation">(</span>root<span class="token punctuation">,</span> word<span class="token punctuation">,</span> full<span class="token punctuation">)</span><span class="token punctuation">:</span>    node <span class="token operator">=</span> root    <span class="token keyword">for</span> char <span class="token keyword">in</span> word<span class="token punctuation">:</span>        <span class="token keyword">if</span> char <span class="token keyword">not</span> <span class="token keyword">in</span> node<span class="token punctuation">.</span>children<span class="token punctuation">:</span>            node<span class="token punctuation">.</span>children<span class="token punctuation">[</span>char<span class="token punctuation">]</span> <span class="token operator">=</span> TrieNode<span class="token punctuation">(</span><span class="token punctuation">)</span>        node <span class="token operator">=</span> node<span class="token punctuation">.</span>children<span class="token punctuation">[</span>char<span class="token punctuation">]</span>    node<span class="token punctuation">.</span>is_end <span class="token operator">=</span> <span class="token boolean">True</span>    node<span class="token punctuation">.</span>full <span class="token operator">=</span> full<span class="token keyword">def</span> <span class="token function">search_longest</span><span class="token punctuation">(</span>root<span class="token punctuation">,</span> word<span class="token punctuation">)</span><span class="token punctuation">:</span>    node <span class="token operator">=</span> root    last_match <span class="token operator">=</span> <span class="token boolean">None</span>    <span class="token keyword">for</span> i<span class="token punctuation">,</span> char <span class="token keyword">in</span> <span class="token builtin">enumerate</span><span class="token punctuation">(</span>word<span class="token punctuation">)</span><span class="token punctuation">:</span>        <span class="token keyword">if</span> char <span class="token keyword">not</span> <span class="token keyword">in</span> node<span class="token punctuation">.</span>children<span class="token punctuation">:</span>            <span class="token keyword">break</span>        node <span class="token operator">=</span> node<span class="token punctuation">.</span>children<span class="token punctuation">[</span>char<span class="token punctuation">]</span>        <span class="token keyword">if</span> node<span class="token punctuation">.</span>is_end<span class="token punctuation">:</span>            last_match <span class="token operator">=</span> <span class="token punctuation">(</span>i<span class="token punctuation">,</span> node<span class="token punctuation">.</span>full<span class="token punctuation">)</span>    <span class="token keyword">return</span> last_match<span class="token keyword">def</span> <span class="token function">extract_initials_and_full</span><span class="token punctuation">(</span>text<span class="token punctuation">,</span> trie<span class="token punctuation">)</span><span class="token punctuation">:</span>    result <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span>    i <span class="token operator">=</span> <span class="token number">0</span>    <span class="token keyword">while</span> i <span class="token operator">&lt;</span> <span class="token builtin">len</span><span class="token punctuation">(</span>text<span class="token punctuation">)</span><span class="token punctuation">:</span>        match <span class="token operator">=</span> search_longest<span class="token punctuation">(</span>trie<span class="token punctuation">,</span> text<span class="token punctuation">[</span>i<span class="token punctuation">:</span><span class="token punctuation">]</span><span class="token punctuation">)</span>        <span class="token keyword">if</span> match<span class="token punctuation">:</span>            end<span class="token punctuation">,</span> full <span class="token operator">=</span> match            result<span class="token punctuation">.</span>append<span class="token punctuation">(</span>full<span class="token punctuation">)</span>            i <span class="token operator">+=</span> end <span class="token operator">+</span> <span class="token number">1</span>        <span class="token keyword">else</span><span class="token punctuation">:</span>            result<span class="token punctuation">.</span>append<span class="token punctuation">(</span>text<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">)</span>            i <span class="token operator">+=</span> <span class="token number">1</span>    <span class="token keyword">return</span> result<span class="token keyword">def</span> <span class="token function">get_initials</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">:</span>    <span class="token keyword">return</span> <span class="token string">''</span><span class="token punctuation">.</span>join<span class="token punctuation">(</span>item<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span> <span class="token keyword">for</span> item <span class="token keyword">in</span> result<span class="token punctuation">)</span>initials <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'b'</span><span class="token punctuation">,</span> <span class="token string">'p'</span><span class="token punctuation">,</span> <span class="token string">'m'</span><span class="token punctuation">,</span> <span class="token string">'f'</span><span class="token punctuation">,</span> <span class="token string">'d'</span><span class="token punctuation">,</span> <span class="token string">'t'</span><span class="token punctuation">,</span> <span class="token string">'n'</span><span class="token punctuation">,</span> <span class="token string">'l'</span><span class="token punctuation">,</span> <span class="token string">'g'</span><span class="token punctuation">,</span> <span class="token string">'k'</span><span class="token punctuation">,</span> <span class="token string">'h'</span><span class="token punctuation">,</span> <span class="token string">'j'</span><span class="token punctuation">,</span> <span class="token string">'q'</span><span class="token punctuation">,</span> <span class="token string">'x'</span><span class="token punctuation">,</span> <span class="token string">'zh'</span><span class="token punctuation">,</span> <span class="token string">'ch'</span><span class="token punctuation">,</span> <span class="token string">'sh'</span><span class="token punctuation">,</span> <span class="token string">'r'</span><span class="token punctuation">,</span> <span class="token string">'z'</span><span class="token punctuation">,</span> <span class="token string">'c'</span><span class="token punctuation">,</span> <span class="token string">'s'</span><span class="token punctuation">,</span> <span class="token string">'y'</span><span class="token punctuation">,</span> <span class="token string">'w'</span><span class="token punctuation">]</span>finals <span class="token operator">=</span> <span class="token punctuation">[</span>    <span class="token string">''</span><span class="token punctuation">,</span> <span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token string">'o'</span><span class="token punctuation">,</span> <span class="token string">'e'</span><span class="token punctuation">,</span> <span class="token string">'i'</span><span class="token punctuation">,</span> <span class="token string">'u'</span><span class="token punctuation">,</span> <span class="token string">'v'</span><span class="token punctuation">,</span>     <span class="token string">'ai'</span><span class="token punctuation">,</span> <span class="token string">'ei'</span><span class="token punctuation">,</span> <span class="token string">'ui'</span><span class="token punctuation">,</span> <span class="token string">'ao'</span><span class="token punctuation">,</span> <span class="token string">'ou'</span><span class="token punctuation">,</span> <span class="token string">'iu'</span><span class="token punctuation">,</span> <span class="token string">'ie'</span><span class="token punctuation">,</span> <span class="token string">'ve'</span><span class="token punctuation">,</span> <span class="token string">'er'</span><span class="token punctuation">,</span>     <span class="token string">'an'</span><span class="token punctuation">,</span> <span class="token string">'en'</span><span class="token punctuation">,</span> <span class="token string">'in'</span><span class="token punctuation">,</span> <span class="token string">'un'</span><span class="token punctuation">,</span> <span class="token string">'vn'</span><span class="token punctuation">,</span>     <span class="token string">'ang'</span><span class="token punctuation">,</span> <span class="token string">'eng'</span><span class="token punctuation">,</span> <span class="token string">'ing'</span><span class="token punctuation">,</span> <span class="token string">'ong'</span><span class="token punctuation">,</span>     <span class="token string">'ia'</span><span class="token punctuation">,</span> <span class="token string">'iao'</span><span class="token punctuation">,</span> <span class="token string">'ian'</span><span class="token punctuation">,</span> <span class="token string">'iang'</span><span class="token punctuation">,</span>    <span class="token string">'iong'</span><span class="token punctuation">,</span> <span class="token string">'ua'</span><span class="token punctuation">,</span> <span class="token string">'uo'</span><span class="token punctuation">,</span> <span class="token string">'uai'</span><span class="token punctuation">,</span> <span class="token string">'uan'</span><span class="token punctuation">,</span> <span class="token string">'uang'</span><span class="token punctuation">,</span>    <span class="token string">'ue'</span><span class="token punctuation">,</span> <span class="token string">'van'</span><span class="token punctuation">,</span> <span class="token string">'ve'</span><span class="token punctuation">,</span> <span class="token string">'ueng'</span><span class="token punctuation">,</span>    <span class="token string">'ong'</span><span class="token punctuation">,</span> <span class="token string">'iong'</span><span class="token punctuation">]</span>valid_pinyin <span class="token operator">=</span> <span class="token punctuation">[</span>    <span class="token punctuation">(</span>initial <span class="token operator">+</span> final<span class="token punctuation">,</span> initial<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> initial <span class="token operator">+</span> final<span class="token punctuation">)</span>    <span class="token keyword">for</span> initial <span class="token keyword">in</span> initials    <span class="token keyword">for</span> final <span class="token keyword">in</span> finals<span class="token punctuation">]</span>special_cases <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'a'</span><span class="token punctuation">,</span> <span class="token string">'o'</span><span class="token punctuation">,</span> <span class="token string">'e'</span><span class="token punctuation">,</span> <span class="token string">'i'</span><span class="token punctuation">,</span> <span class="token string">'u'</span><span class="token punctuation">,</span> <span class="token string">'v'</span><span class="token punctuation">,</span> <span class="token string">'ai'</span><span class="token punctuation">,</span> <span class="token string">'ei'</span><span class="token punctuation">,</span> <span class="token string">'ui'</span><span class="token punctuation">,</span> <span class="token string">'ao'</span><span class="token punctuation">,</span> <span class="token string">'ou'</span><span class="token punctuation">,</span> <span class="token string">'an'</span><span class="token punctuation">,</span> <span class="token string">'en'</span><span class="token punctuation">,</span> <span class="token string">'er'</span><span class="token punctuation">,</span> <span class="token string">'ang'</span><span class="token punctuation">,</span> <span class="token string">'eng'</span><span class="token punctuation">]</span>valid_pinyin<span class="token punctuation">.</span>extend<span class="token punctuation">(</span><span class="token punctuation">(</span>case<span class="token punctuation">,</span> case<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">,</span> case<span class="token punctuation">)</span> <span class="token keyword">for</span> case <span class="token keyword">in</span> special_cases<span class="token punctuation">)</span>pinyin_trie <span class="token operator">=</span> TrieNode<span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token keyword">for</span> pinyin<span class="token punctuation">,</span> initial<span class="token punctuation">,</span> full <span class="token keyword">in</span> valid_pinyin<span class="token punctuation">:</span>    insert<span class="token punctuation">(</span>pinyin_trie<span class="token punctuation">,</span> pinyin<span class="token punctuation">,</span> full<span class="token punctuation">)</span>test_cases <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">"zhongguorenmin"</span><span class="token punctuation">,</span> <span class="token string">"beijingdaxue"</span><span class="token punctuation">,</span> <span class="token string">"aiwozhonghua"</span><span class="token punctuation">,</span> <span class="token string">"qiaoersi"</span><span class="token punctuation">,</span> <span class="token string">"changsha"</span><span class="token punctuation">,</span> <span class="token string">"liangjiang"</span><span class="token punctuation">,</span> <span class="token string">"fangyt"</span><span class="token punctuation">]</span><span class="token keyword">for</span> case <span class="token keyword">in</span> test_cases<span class="token punctuation">:</span>    result <span class="token operator">=</span> extract_initials_and_full<span class="token punctuation">(</span>case<span class="token punctuation">,</span> pinyin_trie<span class="token punctuation">)</span>    initials <span class="token operator">=</span> get_initials<span class="token punctuation">(</span>result<span class="token punctuation">)</span>    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Input: </span><span class="token interpolation"><span class="token punctuation">{</span>case<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Full result: </span><span class="token interpolation"><span class="token punctuation">{</span>result<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token string-interpolation"><span class="token string">f"Initials: </span><span class="token interpolation"><span class="token punctuation">{</span>initials<span class="token punctuation">}</span></span><span class="token string">"</span></span><span class="token punctuation">)</span>    <span class="token keyword">print</span><span class="token punctuation">(</span><span class="token punctuation">)</span></code></pre><h4 id="输出"><a href="#输出" class="headerlink" title="输出"></a>输出</h4><pre class="language-none"><code class="language-none">Input: zhongguorenminFull result: ['zhong', 'guo', 'ren', 'min']Initials: zgrmInput: beijingdaxueFull result: ['bei', 'jing', 'da', 'xue']Initials: bjdxInput: aiwozhonghuaFull result: ['ai', 'wo', 'zhong', 'hua']Initials: awzhInput: qiaoersiFull result: ['qiao', 'er', 'si']Initials: qesInput: changshaFull result: ['chang', 'sha']Initials: csInput: liangjiangFull result: ['liang', 'jiang']Initials: ljInput: fangytFull result: ['fang', 'y', 't']Initials: fyt</code></pre>]]></content>
    
    
    <summary type="html">&lt;p&gt;根据拼音提取首字母，例如将连续的拼音字符串（如 &quot;zhongguorenmin&quot;）分解为单独的拼音（如 [&quot;zhong&quot;, &quot;guo&quot;, &quot;ren&quot;, &quot;min&quot;]），并能提取出拼音的首字母缩写（如 &quot;zgrm&quot;）。&lt;/p&gt;</summary>
    
    
    
    <category term="Python" scheme="https://jueee.github.io/categories/Python/"/>
    
    
    <category term="Python" scheme="https://jueee.github.io/tags/Python/"/>
    
  </entry>
  
  <entry>
    <title>根据二叉树的前序中序遍历结果，求后序遍历结果</title>
    <link href="https://jueee.github.io/2024/09/2024-09-09-%E6%A0%B9%E6%8D%AE%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%89%8D%E5%BA%8F%E4%B8%AD%E5%BA%8F%E9%81%8D%E5%8E%86%E7%BB%93%E6%9E%9C%EF%BC%8C%E6%B1%82%E5%90%8E%E5%BA%8F%E9%81%8D%E5%8E%86%E7%BB%93%E6%9E%9C/"/>
    <id>https://jueee.github.io/2024/09/2024-09-09-%E6%A0%B9%E6%8D%AE%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%89%8D%E5%BA%8F%E4%B8%AD%E5%BA%8F%E9%81%8D%E5%8E%86%E7%BB%93%E6%9E%9C%EF%BC%8C%E6%B1%82%E5%90%8E%E5%BA%8F%E9%81%8D%E5%8E%86%E7%BB%93%E6%9E%9C/</id>
    <published>2024-09-09T00:00:00.000Z</published>
    <updated>2024-09-09T01:51:45.773Z</updated>
    
    <content type="html"><![CDATA[<h3 id="根据二叉树的前序中序遍历结果，求后序遍历结果"><a href="#根据二叉树的前序中序遍历结果，求后序遍历结果" class="headerlink" title="根据二叉树的前序中序遍历结果，求后序遍历结果"></a>根据二叉树的前序中序遍历结果，求后序遍历结果</h3><p>当一棵二叉树的前序序列和中序序列分别是 ABCDEF 和 BADCEF 时，其后序序列必是？</p><ul><li>前序序列：ABCDEF，依次在表格左侧顺序写入列</li><li>中序序列：BADCEF，依次在表格下侧顺序写入行</li><li>交叉的节点，即为二叉树的节点</li></ul><table><thead><tr><th> A</th><th></th><th>A</th><th></th><th></th><th></th><th></th></tr></thead><tbody><tr><td>B</td><td>B</td><td></td><td></td><td></td><td></td><td></td></tr><tr><td>C</td><td></td><td></td><td></td><td>C</td><td></td><td></td></tr><tr><td>D</td><td></td><td></td><td>D</td><td></td><td></td><td></td></tr><tr><td>E</td><td></td><td></td><td></td><td></td><td>E</td><td></td></tr><tr><td>F</td><td></td><td></td><td></td><td></td><td></td><td>F</td></tr><tr><td></td><td>B</td><td>A</td><td>D</td><td>C</td><td>E</td><td>F</td></tr></tbody></table><p>二叉树的结果为：</p><p><img src="assets/image-20240909093817574.png" alt="image-20240909093817574" loading="lazy"></p><p>在每个节点的后侧画个节点，依次遍历二叉树，即可得到其后序遍历结果：</p><p><img src="assets/image-20240909093817575.png" alt="image-20240909093817574" loading="lazy"></p><p>则其后续遍历是：BDFECA</p><p>二叉树：[A,B,C,null,null,D,E,null,null,null,F]</p><p>绘制树：<span class="exturl" data-url="aHR0cHM6Ly9ibG9nLnNjaHdhcnplbmkuY29tL3dvcmtzL2xlZXRjb2RlLWJpbmFyeXRyZWUtZWRpdC8=">https://blog.schwarzeni.com/works/leetcode-binarytree-edit/<i class="fa fa-external-link-alt"></i></span></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;根据二叉树的前序中序遍历结果，求后序遍历结果&quot;&gt;&lt;a href=&quot;#根据二叉树的前序中序遍历结果，求后序遍历结果&quot; class=&quot;headerlink&quot; title=&quot;根据二叉树的前序中序遍历结果，求后序遍历结果&quot;&gt;&lt;/a&gt;根据二叉树的前序中序遍历结果，求后序遍历</summary>
      
    
    
    
    <category term="Blog" scheme="https://jueee.github.io/categories/Blog/"/>
    
    
    <category term="Blog" scheme="https://jueee.github.io/tags/Blog/"/>
    
  </entry>
  
  <entry>
    <title>Axios 包含数组类型的变量 HTTP 请求处理</title>
    <link href="https://jueee.github.io/2024/09/2024-09-03-Axios%E5%8C%85%E5%90%AB%E6%95%B0%E7%BB%84%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8F%98%E9%87%8FHTTP%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86/"/>
    <id>https://jueee.github.io/2024/09/2024-09-03-Axios%E5%8C%85%E5%90%AB%E6%95%B0%E7%BB%84%E7%B1%BB%E5%9E%8B%E7%9A%84%E5%8F%98%E9%87%8FHTTP%E8%AF%B7%E6%B1%82%E5%A4%84%E7%90%86/</id>
    <published>2024-09-03T00:00:00.000Z</published>
    <updated>2024-09-03T10:05:10.342Z</updated>
    
    <content type="html"><![CDATA[<h3 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h3><pre class="language-js" data-language="js"><code class="language-js">axios<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">{</span>    url<span class="token operator">:</span> url<span class="token punctuation">,</span>    method<span class="token operator">:</span> <span class="token string">"post"</span><span class="token punctuation">,</span>    responseType<span class="token operator">:</span> <span class="token string">"blob"</span><span class="token punctuation">,</span>    params<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>queryMap<span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre><p>在使用 Axios 进行 HTTP 请求时，如果 <code>params</code> 包含数组类型的变量，默认情况下，Axios 会将数组参数转换成类似 <code>param[]=value1&amp;param[]=value2</code> 的形式。</p><p>然而，这种默认行为可能与服务器的预期格式不匹配，导致异常。</p><p>如果你希望数组参数以其他格式传递，可以使用 <code>paramsSerializer</code> 来自定义序列化过程。</p><a id="more"></a><p>下面是一个示例，展示如何使用 <code>qs</code> 库将数组参数序列化为所需的格式。</p><h3 id="使用-qs-库进行自定义序列化"><a href="#使用-qs-库进行自定义序列化" class="headerlink" title="使用 qs 库进行自定义序列化"></a>使用 <code>qs</code> 库进行自定义序列化</h3><p>首先，确保你已经安装了 <code>qs</code> 库：</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> qs</code></pre><p>然后，你可以在 Axios 请求中使用 <code>qs.stringify</code> 方法来自定义参数序列化：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">import</span> axios <span class="token keyword">from</span> <span class="token string">'axios'</span><span class="token punctuation">;</span><span class="token keyword">import</span> qs <span class="token keyword">from</span> <span class="token string">'qs'</span><span class="token punctuation">;</span>axios<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">{</span>  url<span class="token operator">:</span> url<span class="token punctuation">,</span>  method<span class="token operator">:</span> <span class="token string">'post'</span><span class="token punctuation">,</span>  responseType<span class="token operator">:</span> <span class="token string">'blob'</span><span class="token punctuation">,</span>  params<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>queryMap<span class="token punctuation">,</span>  <span class="token function-variable function">paramsSerializer</span><span class="token operator">:</span> <span class="token parameter">params</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>​    <span class="token keyword">return</span> qs<span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>params<span class="token punctuation">,</span> <span class="token punctuation">{</span> arrayFormat<span class="token operator">:</span> <span class="token string">'repeat'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>在 <code>qs.stringify</code> 方法中，<code>arrayFormat</code> 有多种选项，你可以根据需要选择适合你的选项：</p><p>- <code>'indices'</code> (默认): <code>param[0]=value0&amp;param[1]=value1</code></p><p>- <code>'brackets'</code>: <code>param[]=value0&amp;param[]=value1</code></p><p>- <code>'repeat'</code>: <code>param=value0&amp;param=value1</code></p><p>- <code>'comma'</code>: <code>param=value0,value1</code></p><p>例如：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token function-variable function">paramsSerializer</span><span class="token operator">:</span> <span class="token parameter">params</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>  <span class="token keyword">return</span> qs<span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>params<span class="token punctuation">,</span> <span class="token punctuation">{</span> arrayFormat<span class="token operator">:</span> <span class="token string">'brackets'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre><h3 id="另一种方式：手动序列化"><a href="#另一种方式：手动序列化" class="headerlink" title="另一种方式：手动序列化"></a>另一种方式：手动序列化</h3><p>如果你不想引入额外的库，可以手动实现参数序列化：</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">customParamsSerializer</span><span class="token punctuation">(</span><span class="token parameter">params</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>  <span class="token keyword">const</span> queryString <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>params<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">key</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>​    <span class="token keyword">const</span> value <span class="token operator">=</span> params<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">;</span>​    <span class="token keyword">if</span> <span class="token punctuation">(</span>Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>​      <span class="token keyword">return</span> value<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">val</span> <span class="token operator">=&gt;</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span>val<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'&amp;'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>​    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>​      <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>​    <span class="token punctuation">}</span>  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'&amp;'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">return</span> queryString<span class="token punctuation">;</span><span class="token punctuation">}</span>axios<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">{</span>  url<span class="token operator">:</span> url<span class="token punctuation">,</span>  method<span class="token operator">:</span> <span class="token string">'post'</span><span class="token punctuation">,</span>  responseType<span class="token operator">:</span> <span class="token string">'blob'</span><span class="token punctuation">,</span>  params<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>queryMap<span class="token punctuation">,</span>  paramsSerializer<span class="token operator">:</span> customParamsSerializer<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><h4 id="完整示例"><a href="#完整示例" class="headerlink" title="完整示例"></a>完整示例</h4><h5 id="使用-qs-库"><a href="#使用-qs-库" class="headerlink" title="使用 qs 库"></a>使用 <code>qs</code> 库</h5><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">import</span> axios <span class="token keyword">from</span> <span class="token string">'axios'</span><span class="token punctuation">;</span><span class="token keyword">import</span> qs <span class="token keyword">from</span> <span class="token string">'qs'</span><span class="token punctuation">;</span>axios<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">{</span>  url<span class="token operator">:</span> url<span class="token punctuation">,</span>  method<span class="token operator">:</span> <span class="token string">'post'</span><span class="token punctuation">,</span>  responseType<span class="token operator">:</span> <span class="token string">'blob'</span><span class="token punctuation">,</span>  params<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>queryMap<span class="token punctuation">,</span>  <span class="token function-variable function">paramsSerializer</span><span class="token operator">:</span> <span class="token parameter">params</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>​    <span class="token keyword">return</span> qs<span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>params<span class="token punctuation">,</span> <span class="token punctuation">{</span> arrayFormat<span class="token operator">:</span> <span class="token string">'repeat'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>  <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><h5 id="手动序列化"><a href="#手动序列化" class="headerlink" title="手动序列化"></a>手动序列化</h5><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">function</span> <span class="token function">customParamsSerializer</span><span class="token punctuation">(</span><span class="token parameter">params</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>  <span class="token keyword">const</span> queryString <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>params<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">key</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>​    <span class="token keyword">const</span> value <span class="token operator">=</span> params<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">;</span>​    <span class="token keyword">if</span> <span class="token punctuation">(</span>Array<span class="token punctuation">.</span><span class="token function">isArray</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>​      <span class="token keyword">return</span> value<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">val</span> <span class="token operator">=&gt;</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span>val<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'&amp;'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>​    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>​      <span class="token keyword">return</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">encodeURIComponent</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">;</span>​    <span class="token punctuation">}</span>  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">'&amp;'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>    <span class="token keyword">return</span> queryString<span class="token punctuation">;</span><span class="token punctuation">}</span>axios<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span><span class="token punctuation">{</span>  url<span class="token operator">:</span> url<span class="token punctuation">,</span>  method<span class="token operator">:</span> <span class="token string">'post'</span><span class="token punctuation">,</span>  responseType<span class="token operator">:</span> <span class="token string">'blob'</span><span class="token punctuation">,</span>  params<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>queryMap<span class="token punctuation">,</span>  paramsSerializer<span class="token operator">:</span> customParamsSerializer<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>通过自定义 <code>paramsSerializer</code>，你可以确保数组类型的请求变量以正确的格式发送，从而避免出现异常。</p>]]></content>
    
    
    <summary type="html">&lt;h3 id=&quot;问题描述&quot;&gt;&lt;a href=&quot;#问题描述&quot; class=&quot;headerlink&quot; title=&quot;问题描述&quot;&gt;&lt;/a&gt;问题描述&lt;/h3&gt;&lt;pre class=&quot;language-js&quot; data-language=&quot;js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;axios&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    url&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    method&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;post&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    responseType&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;blob&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    params&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;queryMap
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;在使用 Axios 进行 HTTP 请求时，如果 &lt;code&gt;params&lt;/code&gt; 包含数组类型的变量，默认情况下，Axios 会将数组参数转换成类似 &lt;code&gt;param[]=value1&amp;amp;param[]=value2&lt;/code&gt; 的形式。&lt;/p&gt;
&lt;p&gt;然而，这种默认行为可能与服务器的预期格式不匹配，导致异常。&lt;/p&gt;
&lt;p&gt;如果你希望数组参数以其他格式传递，可以使用 &lt;code&gt;paramsSerializer&lt;/code&gt; 来自定义序列化过程。&lt;/p&gt;</summary>
    
    
    
    <category term="Vue" scheme="https://jueee.github.io/categories/Vue/"/>
    
    
    <category term="Vue" scheme="https://jueee.github.io/tags/Vue/"/>
    
    <category term="axios" scheme="https://jueee.github.io/tags/axios/"/>
    
  </entry>
  
  <entry>
    <title>MySQL 获取时间最大的查询记录</title>
    <link href="https://jueee.github.io/2024/08/2024-08-23-MySQL%E8%8E%B7%E5%8F%96%E6%97%B6%E9%97%B4%E6%9C%80%E5%A4%A7%E7%9A%84%E6%9F%A5%E8%AF%A2%E8%AE%B0%E5%BD%95/"/>
    <id>https://jueee.github.io/2024/08/2024-08-23-MySQL%E8%8E%B7%E5%8F%96%E6%97%B6%E9%97%B4%E6%9C%80%E5%A4%A7%E7%9A%84%E6%9F%A5%E8%AF%A2%E8%AE%B0%E5%BD%95/</id>
    <published>2024-08-23T00:00:00.000Z</published>
    <updated>2024-08-23T05:58:40.668Z</updated>
    
    <content type="html"><![CDATA[<p>MySQL 获取时间最大的查询记录</p><a id="more"></a><h3 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h3><p>MySQL 根据账号汇总创建时间最大的的记录：</p><pre class="language-sql" data-language="sql"><code class="language-sql"><span class="token keyword">SELECT</span>ws<span class="token punctuation">.</span><span class="token operator">*</span><span class="token keyword">FROM</span>account_state ws<span class="token keyword">INNER</span> <span class="token keyword">JOIN</span> <span class="token punctuation">(</span><span class="token keyword">SELECT</span>account_id<span class="token punctuation">,</span><span class="token function">MAX</span><span class="token punctuation">(</span>create_time<span class="token punctuation">)</span> <span class="token keyword">AS</span> max_create_time<span class="token keyword">FROM</span>account_state<span class="token keyword">GROUP</span> <span class="token keyword">BY</span>account_id<span class="token punctuation">)</span> max_ws <span class="token keyword">ON</span> ws<span class="token punctuation">.</span>account_id <span class="token operator">=</span> max_ws<span class="token punctuation">.</span>account_id <span class="token operator">AND</span> ws<span class="token punctuation">.</span>create_time <span class="token operator">=</span> max_ws<span class="token punctuation">.</span>max_create_time</code></pre>]]></content>
    
    
    <summary type="html">&lt;p&gt;MySQL 获取时间最大的查询记录&lt;/p&gt;</summary>
    
    
    
    <category term="Database" scheme="https://jueee.github.io/categories/Database/"/>
    
    <category term="MySQL" scheme="https://jueee.github.io/categories/Database/MySQL/"/>
    
    
    <category term="Database" scheme="https://jueee.github.io/tags/Database/"/>
    
    <category term="MySQL" scheme="https://jueee.github.io/tags/MySQL/"/>
    
  </entry>
  
</feed>
