文章列表

一款刚刚开源的TTS语音模型!25ms超低延迟支持实时对话,4种规格适配全场景!

作者:微信小助手

<p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 0px;color: rgb(10, 10, 10);font-family: ui-sans-serif, system-ui, sans-serif, " apple color emoji, segoe ui symbol, noto emoji;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 0px;line-height: 0; data-pm-slice="0 0 []"><span leaf="">&nbsp;</span></p> <section style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(10, 10, 10);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 0px 8px 1.5em;text-align: justify;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">在 TTS 领域,情感表达的自然度和实时性一直是两大挑战。传统模型往往在延迟和语音质量间难以平衡。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">近两年 TTS 模型也发展的越来越好,也有越来越多的功能全面的 TTS 模型面世。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><strong style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-weight: bold;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: inherit;color: rgb(66, 166, 100);><span leaf="">Orpheus TTS</span></strong><span leaf="">&nbsp;是一款刚刚发布的开源 TTS 模型,它以其接近人类的自然情感表达、超低延迟的实时输出以及强大的零样本语音克隆能力,迅速成为开源社区关注的焦点。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">不仅能生成流畅自然、充满情感的声音,还将延迟压缩到令人惊叹的 25-50 毫秒,完美适配实时对话场景。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">并且提供了从 150M 到 3B 参数的四种型号,满足不同场景的需求。支持零样本语音克隆和灵活的情感控制,可让每个人都能轻松定制专属音色。</span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100018050" data-s="300,640" src="/upload/d129f3d00d240c4999e156931fcc5191.png" data-type="png" type="block"> </section> <h4 style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 15px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(66, 166, 100);><span leaf="">核心亮点</span></h4> <ul style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: circle;margin: 0px;padding: 0px 0px 0px 1em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;color: rgb(63, 63, 63); class="list-paddingleft-1"> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">•&nbsp;</span><strong style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-weight: bold;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: inherit;color: rgb(66, 166, 100);><span leaf="">超低延迟</span></strong><span leaf="">:支持实时流式推理,延迟低至约200毫秒,通过压缩最低可至 25-50 毫秒</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">•&nbsp;</span><strong style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-weight: bold;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: inherit;color: rgb(66, 166, 100);><span leaf="">自然情感表达</span></strong><span leaf="">:支持丰富的情感和语调控制,支持高兴、悲伤、生气、困倦等多种情绪</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">•&nbsp;</span><strong style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-weight: bold;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: inherit;color: rgb(66, 166, 100);><span leaf="">零样本语音克隆</span></strong><span leaf="">:无需预训练,仅需提供参考音频即可克隆目标音色</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">•&nbsp;</span><strong style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-weight: bold;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: inherit;color: rgb(66, 166, 100);><span leaf="">提供 4 种模型规模</span></strong><span leaf="">:Medium (3B)、Small (1B)、Tiny (400M)、Nano (150M)</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">•&nbsp;</span><strong style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-weight: bold;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: inherit;color: rgb(66, 166, 100);><span leaf="">端到端语音生成</span></strong><span leaf="">:还未上线,上线即可提升语音自然度、可控性及生成速度</span> </section></li> </ul> <h4 style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 15px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(66, 166, 100);><span leaf="">快速使用</span></h4> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">Orpheus TTS 的安装和使用过程简单,支持本地部署。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">如果想要直接体验该TTS工具,HF平台上也有在线Demo可体验(需魔法)。</span></p> <section style="text-align: center;" nodeleaf=""> <img class="rich_pages wxw-img" data-imgfileid="100018051" data-s="300,640" src="/upload/0ed8000f8692d50a00b69bda21675abb.png" data-type="png" type="block"> </section> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">在线Demo:</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;color: rgb(87, 107, 149);><span leaf=""><br></span></span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;color: rgb(87, 107, 149);><span leaf="">https://huggingface.co/spaces/MohamedRashad/Orpheus-TTS</span></span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">本地部署步骤:</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">① 克隆项目</span></p> <pre style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;margin: 10px 8px;background: rgb(0, 0, 0);color: rgb(234, 234, 234);text-align: left;line-height: 1.5;overflow-x: auto;border-radius: 8px;padding: 0px !important;><span hidden style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));display: flex;padding: 10px 14px 0px;"> <svg viewbox="0 0 450 130" height="13px" width="45px" y="0px" x="0px" version="1.1" xmlns="http://www.w3.org/2000/svg"> <ellipse fill="rgb(237,108,96)" stroke-width="2" stroke="rgb(220,60,54)" ry="52" rx="50" cy="65" cx="50"></ellipse><ellipse fill="rgb(247,193,81)" stroke-width="2" stroke="rgb(218,151,33)" ry="52" rx="50" cy="65" cx="225"></ellipse><ellipse fill="rgb(100,200,86)" stroke-width="2" stroke="rgb(27,161,37)" ry="52" rx="50" cy="65" cx="400"></ellipse> </svg></span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: Menlo, " operator mono, consolas, monaco, monospace;font-feature-settings: normal;font-variation-settings: normal;font-size: 15px;display: -webkit-box;padding: 0.5em 1em 1em;overflow-x: auto;text-indent: 0px;text-align: left;line-height: 1.75;margin: 0px;white-space: nowrap;><span leaf="">git&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(231, 140, 69);"><span leaf="">clone</span></span><span leaf="">&nbsp;https://github.com/canopyai/Orpheus-TTS.git</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(231, 140, 69);"><span leaf="">cd</span></span><span leaf="">&nbsp;Orpheus-TTS</span></code></pre> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">② 安装依赖</span></p> <pre style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;margin: 10px 8px;background: rgb(0, 0, 0);color: rgb(234, 234, 234);text-align: left;line-height: 1.5;overflow-x: auto;border-radius: 8px;padding: 0px !important;><span hidden style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));display: flex;padding: 10px 14px 0px;"> <svg viewbox="0 0 450 130" height="13px" width="45px" y="0px" x="0px" version="1.1" xmlns="http://www.w3.org/2000/svg"> <ellipse fill="rgb(237,108,96)" stroke-width="2" stroke="rgb(220,60,54)" ry="52" rx="50" cy="65" cx="50"></ellipse><ellipse fill="rgb(247,193,81)" stroke-width="2" stroke="rgb(218,151,33)" ry="52" rx="50" cy="65" cx="225"></ellipse><ellipse fill="rgb(100,200,86)" stroke-width="2" stroke="rgb(27,161,37)" ry="52" rx="50" cy="65" cx="400"></ellipse> </svg></span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: Menlo, " operator mono, consolas, monaco, monospace;font-feature-settings: normal;font-variation-settings: normal;font-size: 15px;display: -webkit-box;padding: 0.5em 1em 1em;overflow-x: auto;text-indent: 0px;text-align: left;line-height: 1.75;margin: 0px;white-space: nowrap;><span leaf="">pip install orpheus-speech</span></code></pre> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">③ Python调用示例</span></p> <pre style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;margin: 10px 8px;background: rgb(0, 0, 0);color: rgb(234, 234, 234);text-align: left;line-height: 1.5;overflow-x: auto;border-radius: 8px;padding: 0px !important;><span hidden style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));display: flex;padding: 10px 14px 0px;"> <svg viewbox="0 0 450 130" height="13px" width="45px" y="0px" x="0px" version="1.1" xmlns="http://www.w3.org/2000/svg"> <ellipse fill="rgb(237,108,96)" stroke-width="2" stroke="rgb(220,60,54)" ry="52" rx="50" cy="65" cx="50"></ellipse><ellipse fill="rgb(247,193,81)" stroke-width="2" stroke="rgb(218,151,33)" ry="52" rx="50" cy="65" cx="225"></ellipse><ellipse fill="rgb(100,200,86)" stroke-width="2" stroke="rgb(27,161,37)" ry="52" rx="50" cy="65" cx="400"></ellipse> </svg></span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: Menlo, " operator mono, consolas, monaco, monospace;font-feature-settings: normal;font-variation-settings: normal;font-size: 15px;display: -webkit-box;padding: 0.5em 1em 1em;overflow-x: auto;text-indent: 0px;text-align: left;line-height: 1.75;margin: 0px;white-space: nowrap;><span leaf="">from orpheus_tts import OrpheusModel</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">import wave</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">import&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(195, 151, 216);"><span leaf="">time</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">model = OrpheusModel(model_name =</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(185, 202, 74);"><span leaf="">"canopylabs/orpheus-tts-0.1-finetune-prod"</span></span><span leaf="">)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">prompt =&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(185, 202, 74);"><span leaf="">''</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(185, 202, 74);"><span leaf="">'Man, the way social media has, um, completely changed how we interact is just wild, right? Like, we'</span></span><span leaf="">re all connected 24/7 but somehow people feel more alone than ever. And don</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(185, 202, 74);"><span leaf="">'t even get me started on how it'</span></span><span leaf="">s messing with kids</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(185, 202, 74);"><span leaf="">' self-esteem and mental health and whatnot.'</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(185, 202, 74);"><span leaf="">''</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">start_time = time.monotonic()</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">syn_tokens = model.generate_speech(</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;prompt=prompt,</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;voice=</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(185, 202, 74);"><span leaf="">"tara"</span></span><span leaf="">,</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">with wave.open(</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(185, 202, 74);"><span leaf="">"output.wav"</span></span><span leaf="">,&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(185, 202, 74);"><span leaf="">"wb"</span></span><span leaf="">) as wf:</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;wf.setnchannels(1)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;wf.setsampwidth(2)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;wf.setframerate(24000)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;total_frames = 0</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;chunk_counter = 0</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(195, 151, 216);"><span leaf="">for</span></span><span leaf="">&nbsp;audio_chunk&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(195, 151, 216);"><span leaf="">in</span></span><span leaf="">&nbsp;syn_tokens:&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(150, 152, 150);"><span leaf=""># output streaming</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; &nbsp; chunk_counter += 1</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; &nbsp; frame_count = len(audio_chunk) // (wf.getsampwidth() * wf.getnchannels())</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; &nbsp; total_frames += frame_count</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; &nbsp; wf.writeframes(audio_chunk)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;duration = total_frames / wf.getframerate()</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;end_time = time.monotonic()</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(231, 140, 69);"><span leaf="">print</span></span><span leaf="">(f</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(185, 202, 74);"><span leaf="">"It took {end_time - start_time} seconds to generate {duration:.2f} seconds of audio"</span></span><span leaf="">)</span></code></pre> <h4 style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 15px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(66, 166, 100);><span leaf="">写在最后</span></h4> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">传统语音合成(TTS)系统面临三大核心挑战:情感表达生硬、推理延迟过高(普遍&gt;500ms)、克隆音色需大量数据。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">Orpheus TTS通过混合专家架构(MoE)与KV缓存优化,在150M到3B参数范围内实现:MOS评分达4.6、端到端延迟压至25ms、零样本语音克隆、超强情感控制。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">适用于 AI 语音助手、游戏配音、有声读物、虚拟客服、智能语音交互等 多种应用,兼顾 高质量语音合成 &amp; 实时交互体验,是当前最具潜力的开源 TTS 方案之一!</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: justify;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">GitHub 项目地址:</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;color: rgb(87, 107, 149);><span leaf="">https://github.com/canopyai/Orpheus-TTS</span></span></p> </section>

Coze案例 | 饮食助手:如何在Coze进行知识库调优

作者:微信小助手

<section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;color: rgb(62, 62, 62);"> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">Coze确实是练习搭建Agent的一个比较好的平台,理论也要结合实践,所以最近再练习搭建智能体和智能应用。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">头几天自己尝试搭建一个饮食管理应用的时候,屡屡碰壁,数据库和工作流总是有bug,而且感觉工作流有些节点的逻辑跟我的直觉不一样,所以还是按部就班一点点实践吧。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">首先是搭建一个最简单的知识库LLM,创建一个知识库,让智能体可以自己检索知识库里的信息去回答用户的问题,也就是RAG。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">以及进一步</span><span style="color: rgb(95, 156, 239);box-sizing: border-box;"><strong style="box-sizing: border-box;"><span leaf="">如何调整LLM的输出准确性。</span></strong></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> <section style="text-align: left;margin: 10px 0%;box-sizing: border-box;"> <section style="display: inline-block;min-width: 10%;max-width: 100%;vertical-align: top;padding: 0px 0px 0px 30px;box-sizing: border-box;"> <section style="transform: translate3d(-30px, 0px, 0px);-webkit-transform: translate3d(-30px, 0px, 0px);-moz-transform: translate3d(-30px, 0px, 0px);-o-transform: translate3d(-30px, 0px, 0px);margin: 0px 0% -30px;box-sizing: border-box;"> <section style="display: inline-block;width: 30px;height: 30px;vertical-align: top;overflow: hidden;border-width: 0px;border-radius: 100%;border-style: none;border-color: rgba(118, 178, 124, 0);background-color: rgba(1, 169, 216, 0.3);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> </section> <section style="transform: translate3d(-15px, 0px, 0px);-webkit-transform: translate3d(-15px, 0px, 0px);-moz-transform: translate3d(-15px, 0px, 0px);-o-transform: translate3d(-15px, 0px, 0px);box-sizing: border-box;"> <section style="display: inline-block;min-width: 10%;max-width: 100%;vertical-align: top;padding: 3px 0px;box-sizing: border-box;"> <section style="color: rgb(55, 80, 114);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><strong style="box-sizing: border-box;"><span leaf="">创建知识库,合理分段</span></strong></p> </section> </section> </section> </section> </section> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">比较常见的需要用到知识库的Agent场景是协助客服,知识库的内容也就是过去记录的常见Q&amp;A。我这里去网上随便找了一段关于饮食的资料,作为知识库的素材。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> <section style="line-height: 0;box-sizing: border-box;"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;box-sizing: border-box;" nodeleaf=""> <img src="/upload/13dfaa6c943b0866997daed3d00d1025.png" class="rich_pages wxw-img" data-ratio="0.4935185185185185" data-s="300,640" data-w="1080" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;"> </section> </section> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">在Coze创建一个知识库,首先会让你上传知识库资料,如果保持默认选项来到“分段预览”这里,会发现分出来的都是一大段的内容。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">这里的操作步骤作用不仅仅是提取文字、数据预处理,分段也会影响后续LLM的性能。参考之前</span><a href="https://mp.weixin.qq.com/s?__biz=MzkzMzY1MTQ5Nw==&amp;mid=2247484548&amp;idx=1&amp;sn=05904f3531a13323cecdf04370004f57&amp;scene=21#wechat_redirect" target="_blank" style="box-sizing: border-box;"><span leaf="">《10分钟快速了解RAG是什么》</span></a><span leaf="">的RAG基础原理文章可以知道,</span><span style="color: rgb(95, 156, 239);box-sizing: border-box;"><strong style="box-sizing: border-box;"><span leaf="">数据分的段落就是后续知识库根据问题返给LLM的资料片段。</span></strong></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">也就是说,你在这里分的段落越大,后续哪怕只有一句话跟用户问题相关,</span><span style="color: rgb(95, 156, 239);box-sizing: border-box;"><strong style="box-sizing: border-box;"><span leaf="">知识库也会把整个段落都发给LLM</span></strong></span><span leaf="">,这样不仅降低精度,也可能影响性能。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> <section style="line-height: 0;box-sizing: border-box;"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;box-sizing: border-box;" nodeleaf=""> <img src="/upload/756e3c00ed30b90e1ad7620a4c0ee4fb.png" class="rich_pages wxw-img" data-ratio="0.5787037037037037" data-s="300,640" data-w="1080" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;"> </section> </section> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">所以优化的第一个机会就是,在第2步里的“分段策略”,选择自定义策略,可以根据各种分段标识符来分段。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">比如我这里本地doc文档里,段落间会有换行,知识库就可以根据换行来进行分段。也可以选择一些特殊符号,比如 {}、| 等标识。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> <section style="line-height: 0;box-sizing: border-box;"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;box-sizing: border-box;" nodeleaf=""> <img src="/upload/9cea5eaec6cafb1e42aac3283f738064.png" class="rich_pages wxw-img" data-ratio="0.6888888888888889" data-s="300,640" data-w="1080" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;"> </section> </section> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">这样的分段就更加细致了,有利于后续知识库的检索。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> <section style="text-align: left;margin: 10px 0%;box-sizing: border-box;"> <section style="display: inline-block;min-width: 10%;max-width: 100%;vertical-align: top;padding: 0px 0px 0px 30px;box-sizing: border-box;"> <section style="transform: translate3d(-30px, 0px, 0px);-webkit-transform: translate3d(-30px, 0px, 0px);-moz-transform: translate3d(-30px, 0px, 0px);-o-transform: translate3d(-30px, 0px, 0px);margin: 0px 0% -30px;box-sizing: border-box;"> <section style="display: inline-block;width: 30px;height: 30px;vertical-align: top;overflow: hidden;border-width: 0px;border-radius: 100%;border-style: none;border-color: rgba(118, 178, 124, 0);background-color: rgba(1, 169, 216, 0.3);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> </section> <section style="transform: translate3d(-15px, 0px, 0px);-webkit-transform: translate3d(-15px, 0px, 0px);-moz-transform: translate3d(-15px, 0px, 0px);-o-transform: translate3d(-15px, 0px, 0px);box-sizing: border-box;"> <section style="display: inline-block;min-width: 10%;max-width: 100%;vertical-align: top;padding: 3px 0px;box-sizing: border-box;"> <section style="color: rgb(55, 80, 114);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><b style="box-sizing: border-box;"><span leaf="">工作流:知识库检索节点</span></b></p> </section> </section> </section> </section> </section> <section style="line-height: 0;box-sizing: border-box;"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;box-sizing: border-box;" nodeleaf=""> <img src="/upload/943c8f63a4335c65b9502312d26f6f02.png" class="rich_pages wxw-img" data-ratio="0.7805555555555556" data-s="300,640" data-w="1080" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;"> </section> </section> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">创建完知识库后,我们创建一个工作流,里面插入“知识库检索”节点,看到右边三个变量。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">搜索策略里,</span><span style="color: rgb(95, 156, 239);box-sizing: border-box;"><strong style="box-sizing: border-box;"><span leaf="">语义搜索:理解关键词真正含义</span></strong></span><span leaf="">(适用于模糊提问)</span><span style="color: rgb(95, 156, 239);box-sizing: border-box;"><strong style="box-sizing: border-box;"><span leaf="">全文搜索:搜索关键词</span></strong></span><span leaf="">(适用于特定术语等精确信息查询)</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span style="color: rgb(95, 156, 239);box-sizing: border-box;"><strong style="box-sizing: border-box;"><span leaf="">最大召回数量</span></strong></span><span leaf="">即用户提问后,返回的知识库检索段落数量。</span><span style="color: rgb(95, 156, 239);box-sizing: border-box;"><strong style="box-sizing: border-box;"><span leaf="">最小匹配度</span></strong></span><span leaf="">即返回资料的相关性门槛。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><strong style="box-sizing: border-box;"></strong></p> </section> <section style="line-height: 0;text-align: center;box-sizing: border-box;"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;width: 58%;height: auto;box-sizing: border-box;" nodeleaf=""> <img src="/upload/d9b5cadffbd4963de0b8718be6105368.png" class="rich_pages wxw-img" data-ratio="1.3406593406593406" data-s="300,640" data-w="728" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;"> </section> </section> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">我们引用刚才创建的知识库后,试运行该节点,点开运行结果可以发现,返回的知识片段还是比较精确的。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> <section style="text-align: left;margin: 10px 0%;box-sizing: border-box;"> <section style="display: inline-block;min-width: 10%;max-width: 100%;vertical-align: top;padding: 0px 0px 0px 30px;box-sizing: border-box;"> <section style="transform: translate3d(-30px, 0px, 0px);-webkit-transform: translate3d(-30px, 0px, 0px);-moz-transform: translate3d(-30px, 0px, 0px);-o-transform: translate3d(-30px, 0px, 0px);margin: 0px 0% -30px;box-sizing: border-box;"> <section style="display: inline-block;width: 30px;height: 30px;vertical-align: top;overflow: hidden;border-width: 0px;border-radius: 100%;border-style: none;border-color: rgba(118, 178, 124, 0);background-color: rgba(1, 169, 216, 0.3);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> </section> <section style="transform: translate3d(-15px, 0px, 0px);-webkit-transform: translate3d(-15px, 0px, 0px);-moz-transform: translate3d(-15px, 0px, 0px);-o-transform: translate3d(-15px, 0px, 0px);box-sizing: border-box;"> <section style="display: inline-block;min-width: 10%;max-width: 100%;vertical-align: top;padding: 3px 0px;box-sizing: border-box;"> <section style="color: rgb(55, 80, 114);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><strong style="box-sizing: border-box;"><span leaf="">人设Prompt</span></strong></p> </section> </section> </section> </section> </section> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">因为这个案例比较简单,所以只提一些细小的可能会出bug的点。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> <section style="line-height: 0;box-sizing: border-box;"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;box-sizing: border-box;" nodeleaf=""> <img src="/upload/16288f6b59a896a233eb1226b2fafe5c.png" class="rich_pages wxw-img" data-ratio="0.8441247002398081" data-s="300,640" data-w="834" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;"> </section> </section> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">首先是人设逻辑这里,注意最左侧Prompt栏里,</span><span style="color: rgb(95, 156, 239);box-sizing: border-box;"><strong style="box-sizing: border-box;"><span leaf="">如果要在prompt里引用工作流,需要输入{{}}</span></strong></span><span leaf="">,就会跳出可引用的工作流选项。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">但此外,如果只是引用变量或插件的话,可以随意一些。在prompt里点名什么时候用什么变量、什么插件,也可以让LLM的输出更精确。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> <section style="text-align: left;margin: 10px 0%;box-sizing: border-box;"> <section style="display: inline-block;min-width: 10%;max-width: 100%;vertical-align: top;padding: 0px 0px 0px 30px;box-sizing: border-box;"> <section style="transform: translate3d(-30px, 0px, 0px);-webkit-transform: translate3d(-30px, 0px, 0px);-moz-transform: translate3d(-30px, 0px, 0px);-o-transform: translate3d(-30px, 0px, 0px);margin: 0px 0% -30px;box-sizing: border-box;"> <section style="display: inline-block;width: 30px;height: 30px;vertical-align: top;overflow: hidden;border-width: 0px;border-radius: 100%;border-style: none;border-color: rgba(118, 178, 124, 0);background-color: rgba(1, 169, 216, 0.3);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> </section> <section style="transform: translate3d(-15px, 0px, 0px);-webkit-transform: translate3d(-15px, 0px, 0px);-moz-transform: translate3d(-15px, 0px, 0px);-o-transform: translate3d(-15px, 0px, 0px);box-sizing: border-box;"> <section style="display: inline-block;min-width: 10%;max-width: 100%;vertical-align: top;padding: 3px 0px;box-sizing: border-box;"> <section style="color: rgb(55, 80, 114);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><strong style="box-sizing: border-box;"><span leaf="">工作流 vs 对话流</span></strong></p> </section> </section> </section> </section> </section> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">前面我们创建的是工作流,还有一种叫对话流。二者比较明显的区别是</span><span style="color: rgb(95, 156, 239);box-sizing: border-box;"><strong style="box-sizing: border-box;"><span leaf="">工作流无记忆功能,而对话流有记忆功能。</span></strong></span><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span style="color: rgb(95, 156, 239);box-sizing: border-box;"><strong style="box-sizing: border-box;"><span leaf="">工作流适用的场景是处理独立的功能性任务,</span></strong></span><span leaf="">比如批量生成内容、自动化数据处理等。比如只要给定一个主题,就自动生成文章,这种不需要交代前后对话历史的任务。</span><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">而这里搭建的智能体偏向于和用户聊天,所以需要改为“对话流”模式。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> <section style="line-height: 0;box-sizing: border-box;"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;box-sizing: border-box;" nodeleaf=""> <img src="/upload/6b960d2c4749372da0e8a595b06457b0.png" class="rich_pages wxw-img" data-ratio="0.1527777777777778" data-s="300,640" data-w="1080" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;"> </section> </section> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">我们在资源库里找到创建的工作流,可以快捷切换成对话流。切换后,点进工作流里的大模型节点,就会发现</span><span style="color: rgb(95, 156, 239);box-sizing: border-box;"><strong style="box-sizing: border-box;"><span leaf="">右边配置的“输入”部分,多了勾选对话历史的选项。</span></strong></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> <section style="text-align: left;margin: 10px 0%;box-sizing: border-box;"> <section style="display: inline-block;min-width: 10%;max-width: 100%;vertical-align: top;padding: 0px 0px 0px 30px;box-sizing: border-box;"> <section style="transform: translate3d(-30px, 0px, 0px);-webkit-transform: translate3d(-30px, 0px, 0px);-moz-transform: translate3d(-30px, 0px, 0px);-o-transform: translate3d(-30px, 0px, 0px);margin: 0px 0% -30px;box-sizing: border-box;"> <section style="display: inline-block;width: 30px;height: 30px;vertical-align: top;overflow: hidden;border-width: 0px;border-radius: 100%;border-style: none;border-color: rgba(118, 178, 124, 0);background-color: rgba(1, 169, 216, 0.3);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> </section> <section style="transform: translate3d(-15px, 0px, 0px);-webkit-transform: translate3d(-15px, 0px, 0px);-moz-transform: translate3d(-15px, 0px, 0px);-o-transform: translate3d(-15px, 0px, 0px);box-sizing: border-box;"> <section style="display: inline-block;min-width: 10%;max-width: 100%;vertical-align: top;padding: 3px 0px;box-sizing: border-box;"> <section style="color: rgb(55, 80, 114);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><b style="box-sizing: border-box;"><span leaf="">知识库RAG优化策略</span></b></p> </section> </section> </section> </section> </section> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">根据用户提问,去检索知识库的信息,然后交给LLM生成回答,这个过程看似很简单,但还有一些可优化的步骤。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">首先是用户提问。用户提问可能会存在模糊不清、指代不明的情况。上一步记录对话历史能够优化一部分,也可以通过对话流里的“意图识别”节点进行细分。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> <section style="line-height: 0;box-sizing: border-box;"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;box-sizing: border-box;" nodeleaf=""> <img src="/upload/c16b44a21ad09547cd01a3060b4233c4.png" class="rich_pages wxw-img" data-ratio="0.5453703703703704" data-s="300,640" data-w="1080" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;"> </section> </section> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">增加“意图识别”的节点后,可以识别用户输入,这里举例分为碳水、蛋白质和膳食纤维这常见的营养成分类别,当然相应的知识库也有进行细分。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">通常在“意图识别”的节点后,可以再加一个“变量聚合”,把三种可能的输出给整合到一个变量进行输出,这样如果工作流后续还要进行处理的话,也更方便管理。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span style="color: rgb(95, 156, 239);box-sizing: border-box;"><strong style="box-sizing: border-box;"><span leaf="">变量聚合的规则是“返回每个分组中第一个非空的值”</span></strong></span><span leaf="">,因此这里在变量的排序上也存在影响。一个意图识别的节点肯定是只会输出一个变量,但是如果复杂情况下涉及多个意图识别、多种输入,就需要把你更像输出的变量排在前面了。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> <section style="line-height: 0;box-sizing: border-box;"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;box-sizing: border-box;" nodeleaf=""> <img src="/upload/2b36ed135d0222caa9fde762c5b66daf.png" class="rich_pages wxw-img" data-ratio="0.41388888888888886" data-s="300,640" data-w="1080" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;"> </section> </section> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">如果用户的提问是不相关的问题,可以增加一个问答节点,询问用户到底想问什么,再引入刚才的三个分类。如果还是不符合用户的预期,再通过“文本处理”节点,对用户说明原因即可。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> <section style="text-align: left;margin: 10px 0%;box-sizing: border-box;"> <section style="display: inline-block;min-width: 10%;max-width: 100%;vertical-align: top;padding: 0px 0px 0px 30px;box-sizing: border-box;"> <section style="transform: translate3d(-30px, 0px, 0px);-webkit-transform: translate3d(-30px, 0px, 0px);-moz-transform: translate3d(-30px, 0px, 0px);-o-transform: translate3d(-30px, 0px, 0px);margin: 0px 0% -30px;box-sizing: border-box;"> <section style="display: inline-block;width: 30px;height: 30px;vertical-align: top;overflow: hidden;border-width: 0px;border-radius: 100%;border-style: none;border-color: rgba(118, 178, 124, 0);background-color: rgba(1, 169, 216, 0.3);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> </section> <section style="transform: translate3d(-15px, 0px, 0px);-webkit-transform: translate3d(-15px, 0px, 0px);-moz-transform: translate3d(-15px, 0px, 0px);-o-transform: translate3d(-15px, 0px, 0px);box-sizing: border-box;"> <section style="display: inline-block;min-width: 10%;max-width: 100%;vertical-align: top;padding: 3px 0px;box-sizing: border-box;"> <section style="color: rgb(55, 80, 114);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><strong style="box-sizing: border-box;"><span leaf="">可能出现的bug</span></strong></p> </section> </section> </section> </section> </section> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">有时候我们需要添加用户变量,例如需要根据用户自己的口味偏好来推荐饮食。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> <section style="line-height: 0;box-sizing: border-box;"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;box-sizing: border-box;" nodeleaf=""> <img src="/upload/2c28b87bfecb4d6b77beca2bef9d74d1.png" class="rich_pages wxw-img" data-ratio="0.8796296296296297" data-s="300,640" data-w="1080" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;"> </section> </section> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">但是在工作流里的大模型节点,会出现无法引用“用户变量”的问题。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> <section style="line-height: 0;box-sizing: border-box;"> <section style="max-width: 100%;vertical-align: middle;display: inline-block;line-height: 0;box-sizing: border-box;" nodeleaf=""> <img src="/upload/2b8a3ceee3e2ca90325075caedb023dd.png" class="rich_pages wxw-img" data-ratio="0.7109704641350211" data-s="300,640" data-w="948" style="vertical-align: middle;max-width: 100%;width: 100%;box-sizing: border-box;"> </section> </section> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">这时候需要点击大模型节点的“试运行”,然后选择关联我们当前的智能体,这样才能读取该智能体的“用户变量”。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">我理解的逻辑是,虽然你是在创建该智能体的界面里创建的工作流,但是逻辑还是被统一设定为,工作流是外部的流程,除非你自己设置,否则默认不属于任何一个智能体,自然也读不到智能体里面的用户变量了。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">只要关联智能体后,再点击大模型节点的配置项,就可以引用绑定用户变量了。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> <section style="text-align: left;justify-content: flex-start;display: flex;flex-flow: row;margin: 10px 0px;box-sizing: border-box;"> <section style="display: inline-block;vertical-align: top;width: auto;flex: 100 100 0%;height: auto;box-sizing: border-box;"> <section style="margin: 5px 0px;box-sizing: border-box;"> <section style="background-color: rgb(157, 202, 203);height: 1px;box-sizing: border-box;"> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> <section style="display: inline-block;vertical-align: middle;width: auto;align-self: center;flex: 0 0 0%;height: auto;z-index: auto;line-height: 0;padding: 0px 7px;box-sizing: border-box;"> <section style="text-align: center;margin: 0px;box-sizing: border-box;"> <section style="display: inline-block;width: 8px;height: 8px;vertical-align: top;overflow: hidden;border-radius: 100%;background-color: rgba(255, 255, 255, 0);border-width: 1px;border-style: solid;border-color: rgb(157, 202, 203);box-sizing: border-box;"> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> <section style="display: inline-block;vertical-align: middle;width: auto;align-self: center;flex: 0 0 0%;height: auto;z-index: auto;line-height: 0;padding: 0px;box-sizing: border-box;"> <section style="text-align: center;margin: 0px;box-sizing: border-box;"> <section style="display: inline-block;width: 8px;height: 8px;vertical-align: top;overflow: hidden;border-radius: 100%;background-color: rgba(255, 255, 255, 0);border-width: 1px;border-style: solid;border-color: rgb(157, 202, 203);box-sizing: border-box;"> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> </section> <section style="line-height: 2;box-sizing: border-box;"> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf="">一个简单的案例介绍,会持续深入的更新Coze搭建Agent的分享。</span></p> <p style="white-space: normal;margin: 0px;padding: 0px;box-sizing: border-box;"><span leaf=""><br></span></p> </section> </section> <p style="display: none;"> <mp-style-type data-value="10000"></mp-style-type></p>

爬虫+动态代理助力 AI 训练数据采集

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 10px;padding-right: 10px;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: linear-gradient(90deg, rgba(50, 0, 0, 0.03) 0%, rgba(255, 255, 255, 0) 11.49%), linear-gradient(360deg, rgba(50, 0, 0, 0.04) 0%, rgba(255, 255, 255, 0) 12.16%);background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat-x: repeat, repeat;background-repeat-y: repeat, repeat;background-size: 20px 20px, 20px 20px;width: auto;font-family: Optima, PingFangSC-light, serif;font-size: 16px;color: rgb(0, 0, 0);line-height: 1.5em;word-spacing: 0em;letter-spacing: 0em;word-break: break-word;overflow-wrap: break-word;text-align: left;"> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf=""><br></span></p> <h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;"><span style="display: none;"></span><span style="font-size: 24px;color: rgb(64, 184, 250);line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">引言</span></span><span style="display: none;"></span></h1> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">近年来,AI 技术飞速发展,很多朋友都投身于 AI 模型的训练。然而,相较于模型的获取,高质量的数据往往更加难以收集。一方面,互联网每天都在源源不断地产生新数据,另一方面,各大网站普遍设有反爬机制,阻止自动化程序抓取信息。在这种情况下,动态代理服务成为破解难题的关键工具。通过动态代理,我们的爬虫程序可以模拟不同的用户身份,在访问网站时伪装 IP 地址,从而有效降低被封禁的风险。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">作为行业的先行者,亮数据是最早开展代理 IP 服务的企业之一,经过多年积累,已构建起庞大且稳定的代理 IP 资源。借助其代理服务,我们可以显著提高爬虫程序的访问成功率,从而更高效地获取数据,助力 AI 模型的训练。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">维基百科是 AI 领域的重要数据来源,广泛用于训练 RoBERTa、XLNet 和 LLaMA 等大模型。本次,我们将以采集维基百科数据为例,分别面向零经验的初学者和熟练开发者介绍如何结合爬虫技术与动态代理,高效获取训练数据。</span></p> <h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;"><span style="display: none;"></span><span style="font-size: 24px;color: rgb(64, 184, 250);line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">新手之选:网页抓取API</span></span><span style="display: none;"></span></h1> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">如果你是第一次接触爬虫技术,可能会感到有些无从下手,不知道该从哪里开始。别担心,其实并没有那么复杂!你可以尝试使用 亮数据的网页抓取API (https://www.bright.cn/?utm_source=brand&amp;utm_campaign=brnd-mkt_cn_csdn_man202503&amp;promo=APIS25),它已经为100多个网站量身打造了不同的爬虫方案,覆盖了各种应用场景。而且,你无需编写复杂的代码,只需通过可视化界面进行简单配置,就能轻松获取所需的数据。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/af04c37c2bfad8869f940ffc8914273d.png" class="rich_pages wxw-img" data-ratio="0.47377938517179025" data-type="png" data-w="553" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100000850"></span> </figure> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">登录以后进入控制台,点击网页抓取API,选择进入到Web爬虫库。Web爬虫库中有各种网站的丰富爬虫应用可以直接使用。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/002d8ebf2507e8ccb477cdd4b96623b4.png" class="rich_pages wxw-img" data-ratio="0.48282097649186256" data-type="png" data-w="553" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100000849"></span> </figure> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">在其中定位到Wikipedia网站,可以看到有一项抓取Wikipedia文章的应用,这就是我们的目标了。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/2340f3106f8f2cdc744515f9a2f824a1.png" class="rich_pages wxw-img" data-ratio="0.484629294755877" data-type="png" data-w="553" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100000852"></span> </figure> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">点击以后选择爬虫API,它相比无代码抓取器有更多的定制空间。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/cc499ef7ea22e2f98b83733961448ec4.png" class="rich_pages wxw-img" data-ratio="0.4701627486437613" data-type="png" data-w="553" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100000851"></span> </figure> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">在爬虫的设置界面中,进入API请求构建器,在这里配置一下令牌,还可以在网址的部分配置采集的页面。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/31d97ae811c2003c1de506d724c2494c.png" class="rich_pages wxw-img" data-ratio="0.47377938517179025" data-type="png" data-w="553" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100000853"></span> </figure> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">而在词典中可以管理要采集的字段,如果没有你需要的字段,也可以提交工单等待工作人员优化。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/03fda40d654e43c7572c942db20552b2.png" class="rich_pages wxw-img" data-ratio="0.5497287522603979" data-type="png" data-w="553" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100000857"></span> </figure> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">配置完成后点击右上角开始运行。稍等片刻,就可以在日志中下载结果。是不是很简单呢?</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/254b221789ed575c8082c273f3852499.png" class="rich_pages wxw-img" data-ratio="0.379746835443038" data-type="png" data-w="553" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100000854"></span> </figure> <h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;"><span style="display: none;"></span><span style="font-size: 24px;color: rgb(64, 184, 250);line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">可靠之选:动态住宅代理</span></span><span style="display: none;"></span></h1> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">如果你已经对爬虫技术比较熟悉,并且有定制化采集需求,或者想要将数据抓取功能集成到自己的应用中,那么网页抓取 API 可能会有些局限。这时候,不妨试试 动态住宅代理(https://www.bright.cn/?utm_source=brand&amp;utm_campaign=brnd-mkt_cn_csdn_man202503&amp;promo=RESIYERA50),搭配自己编写的爬虫程序,自由度更高,也更灵活。亮数据的动态住宅代理服务拥有超过 7200 万个住宅 IP,覆盖全球多个国家和地区,IP 质量稳定,成功率高,而且价格公道,性价比极佳。对于需要长期、大规模数据采集的开发者来说,这是一个非常可靠的选择。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/922af95183093923b4380b4d09cd08a1.png" class="rich_pages wxw-img" data-ratio="0.5316455696202531" data-type="png" data-w="553" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100000858"></span> </figure> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">登录之后,在控制面板的代理&amp;抓取基础设施中选择动态住宅IP。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/b2f76c2c2dd5c2c60c5c01de31dcb57b.png" class="rich_pages wxw-img" data-ratio="0.7667269439421338" data-type="png" data-w="553" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100000856"></span> </figure> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">之后在代理设置界面填写名称,选择要选购IP的地点,之后就可以开始使用。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/21e59639d7ada936a496b9f56b10eb3d.png" class="rich_pages wxw-img" data-ratio="0.5370705244122965" data-type="png" data-w="553" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100000855"></span> </figure> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">确认之后就可以看到代理服务的主机名、用户名和密码。将它们复制下来,之后会用到。同时将本地IP添加到白名单中。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/825c5a1b5a6ce60dca98f2450ec8a533.png" class="rich_pages wxw-img" data-ratio="0.4810126582278481" data-type="png" data-w="553" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100000862"></span> </figure> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">之后我们开始编写爬虫。我们这次爬取Wikipedia的最近体育新闻板块,这个功能在网页抓取API中没有提供,所以需要我们自行开发。注意到这一个板块可以使用title="2025 in sports"定位标题,然后向上选取四层定位到整个栏目。然后向下选取到第二个div中的ul和dl即为所需。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/587904ec1b484a2fe8488cd85ed4b7ce.png" class="rich_pages wxw-img" data-ratio="0.7685352622061483" data-type="png" data-w="553" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100000863"></span> </figure> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">首先,我们将代理服务器、请求头和url定义为一些常量便于管理。接下来,我们创建一个带有代理的opener对象,和一个包含目标URL和请求头的请求对象。随后,发送HTTP请求,获取页面的HTML内容,并使用lxml库将HTML解析为可操作的XML树结构。</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ouicwjdjoz3h9mwaul5x1nvw05uzlvpt2aviaevg0vnmicayx2sw2iuwzmiaupspeic3sakw6mzsm38ahgkstfyv7umaibdr0ib8wnk 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">proxy = {</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'http'</span></span><span leaf="">:&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'http://brd-customer-hl_a0a48734-zone-residential_proxy3:7sl48y9j3jfm@brd.superproxy.io:33335'</span></span><span leaf="">}proxy.io:33335</span><span style="color: #98c379;line-height: 26px;"><span leaf="">',</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;'</span></span><span leaf="">https</span><span style="color: #98c379;line-height: 26px;"><span leaf="">': '</span></span><span leaf="">http://brd-customer-hl_a0a48734-zone-residential_proxy3:7sl48y9j3jfm@brd.superproxy.io:33335</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'}</span><span leaf=""><br></span><span leaf="">headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0"}</span><span leaf=""><br></span><span leaf="">url = "https://en.wikipedia.org/wiki/Portal:Current_events"</span><span leaf=""><br></span><span leaf="">opener = request.build_opener(request.ProxyHandler(proxy))</span><span leaf=""><br></span><span leaf="">req = request.Request(url=url, headers=headers)</span><span leaf=""><br></span><span leaf="">html = opener.open(req).read()</span><span leaf=""><br></span></span></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">接下来,首先定位到页面中 “2025 in sports” 这个链接所在的 HTML 节点,并向上回溯以找到包含完整新闻内容的 div 元素。随后,进一步解析该 div,提取其中的新闻标题和超链接,将其整理成一个字典格式的数据结构。其中,result字典用于存储爬取到的新闻内容,年份被固定设置为 2025,而新闻条目被存入 content 字段。</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ouicwjdjoz3h9mwaul5x1nvw05uzlvpt2aviaevg0vnmicayx2sw2iuwzmiaupspeic3sakw6mzsm38ahgkstfyv7umaibdr0ib8wnk 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">root = etree.HTML(html)</span><span leaf=""><br></span><span leaf="">div = root.xpath(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'.//a[@title="2025 in sports"]/../../../..'</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf="">ilist = div.xpath(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'./div[1]'</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf="">result = {</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"time"</span></span><span leaf="">: 2025,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"content"</span></span><span leaf="">: []}</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">for</span></span><span leaf="">&nbsp;item&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">in</span></span><span leaf="">&nbsp;ilist.xpath(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'./ul'</span></span><span leaf="">):</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; temp = []</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">for</span></span><span leaf="">&nbsp;lis&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">in</span></span><span leaf="">&nbsp;ilist.xpath(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'./dl/dd/ul/li'</span></span><span leaf="">):</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">for</span></span><span leaf="">&nbsp;li&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">in</span></span><span leaf="">&nbsp;lis:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; link = li.xpath(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'./a/@href'</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name = li.xpath(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'./a/@title'</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; temp.append({</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"name"</span></span><span leaf="">: name,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"link"</span></span><span leaf="">: link})</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; result[</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"content"</span></span><span leaf="">].append({i7sl48y9j3jfm@brd.superproxy.io:33335</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'}proxy.io:33335'</span></span><span leaf="">,</span><span leaf=""><br></span></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">最后,将获取到的新闻信息转换为字符串,并将其写入到本地文件中,以便后续处理或分析。</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ouicwjdjoz3h9mwaul5x1nvw05uzlvpt2aviaevg0vnmicayx2sw2iuwzmiaupspeic3sakw6mzsm38ahgkstfyv7umaibdr0ib8wnk 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">with open(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'wiki_sport.txt'</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'w'</span></span><span leaf="">) as f:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; f.write(str(result))</span><span leaf=""><br></span></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">完整代码如下:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ouicwjdjoz3h9mwaul5x1nvw05uzlvpt2aviaevg0vnmicayx2sw2iuwzmiaupspeic3sakw6mzsm38ahgkstfyv7umaibdr0ib8wnk 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">from urllib import request</span><span leaf=""><br></span><span leaf="">from lxml import etree</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">proxy = {</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'http'</span></span><span leaf="">:&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'http://brd-customer-hl_a0a48734-zone-residential_proxy3:7sl48y9j3jfm@brd.superproxy.io:33335'</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'https'</span></span><span leaf="">:&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'http://brd-customer-hl_a0a48734-zone-residential_proxy3:7sl48y9j3jfm@brd.superproxy.io:33335'</span></span><span leaf="">}</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">headers = {</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"User-Agent"</span></span><span leaf="">:&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0"</span></span><span leaf="">}</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">url =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"https://en.wikipedia.org/wiki/Portal:Current_events"</span></span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">opener = request.build_opener(request.ProxyHandler(proxy))</span><span leaf=""><br></span><span leaf="">req = request.Request(url=url, headers=headers)</span><span leaf=""><br></span><span leaf="">html = opener.open(req).</span><span style="color: #e6c07b;line-height: 26px;"><span leaf="">read</span></span><span leaf="">()</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">root = etree.HTML(html)</span><span leaf=""><br></span><span leaf="">div = root.xpath(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'.//a[@title="2025 in sports"]/../../../..'</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf="">ilist = div.xpath(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'./div[1]'</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf="">result = {</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"time"</span></span><span leaf="">: 2025,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"content"</span></span><span leaf="">: []}</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">for</span></span><span leaf="">&nbsp;item&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">in</span></span><span leaf="">&nbsp;ilist.xpath(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'./ul'</span></span><span leaf="">):</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; temp = []</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">for</span></span><span leaf="">&nbsp;lis&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">in</span></span><span leaf="">&nbsp;ilist.xpath(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'./dl/dd/ul/li'</span></span><span leaf="">):</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">for</span></span><span leaf="">&nbsp;li&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">in</span></span><span leaf="">&nbsp;lis:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; link = li.xpath(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'./a/@href'</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; name = li.xpath(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'./a/@title'</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; temp.append({</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"name"</span></span><span leaf="">: name,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"link"</span></span><span leaf="">: link})</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; result[</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"content"</span></span><span leaf="">].append({item.xpath(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'./li/a/text()'</span></span><span leaf="">): temp})</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">with open(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'wiki_sport.txt'</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'w'</span></span><span leaf="">) as f:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; f.write(str(result))</span><span leaf=""><br></span></code></pre> <h1 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;"><span style="display: none;"></span><span style="font-size: 24px;color: rgb(64, 184, 250);line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">总结</span></span><span style="display: none;"></span></h1> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">在 AI 训练的道路上,高质量的数据是不可或缺的,但获取这些数据往往面临诸多挑战。网站的反爬机制让直接抓取变得困难,而手动收集数据又过于低效。在这样的背景下,动态代理服务成为了一种高效、可靠的解决方案。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">亮数据作为行业的佼佼者,提供了强大的代理 IP 资源,无论是刚入门的数据采集爱好者,还是经验丰富的开发者,合理利用爬虫技术与代理服务,都能帮助我们在 AI 领域迈出更坚实的一步。希望本次的分享能为你的数据获取任务提供实用的思路和工具,让 AI 训练更加顺畅。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">最近亮数据也开启了一系列活动,感兴趣的朋友不妨了解一下:</span></p> <ul style="list-style-type: disc;margin-top: 8px;margin-bottom: 8px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 25px;padding-right: 0px;color: rgb(0, 0, 0);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <span leaf="">亮数据住宅代理全部套餐5折!错过等一年!所有新老客户均可使用,即可直接享受折扣:https://www.bright.cn/?utm_source=brand&amp;utm_campaign=brnd-mkt_cn_csdn_man202503&amp;promo=RESIYERA50</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <span leaf="">亮数据网页抓取API,全线75折!有效期6个月!所有新老客户均可使用,即可直接享受折扣:https://www.bright.cn/?utm_source=brand&amp;utm_campaign=brnd-mkt_cn_csdn_man202503&amp;promo=APIS25</span> </section></li> </ul> </section> <section> <span leaf=""><br></span> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>

开源语音 RAG 助手!用自然语音实时搜索向量数据库,革新语音交互体验!

作者:微信小助手

<p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 0px;color: rgb(10, 10, 10);font-family: ui-sans-serif, system-ui, sans-serif, " apple color emoji, segoe ui symbol, noto emoji;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 0px;line-height: 0; data-pm-slice="0 0 []"><span leaf="">&nbsp;</span></p> <section style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(10, 10, 10);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 0px 8px 1.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">传统的向量数据库搜索往往需要编写查询代码或手动输入关键词,对于非技术用户来说门槛较高。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">而现在随着 AI 的进步,大家可以直接用语音对话搜索你的知识库,而无需手动输入关键词。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">这不仅提升了查询效率,还能让 AI 理解你的问题语境,提供更精准的回答。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">今天的主角:</span><strong style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-weight: bold;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: inherit;color: rgb(66, 166, 100);><span leaf="">Oliva</span></strong><span leaf="">,正是这样一款可以通过自然语音实现对 Qdrant 向量数据库实时搜索的开源工具。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf=""><img alt="Oliva architecture" class="rich_pages wxw-img" data-imgfileid="100018095" data-ratio="0.682567726737338" src="/upload/847835dea636cf79a4da28d3d9b5794b.png" data-type="png" data-w="1698"></span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">它是由 Deluxer 团队开发并在 GitHub 上开源的语音 RAG 助手。能实时处理你的语音指令,从 Qdrant 数据库中检索信息并生成回答。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">无论是产品搜索、知识查询还是数据分析,它都能以自然、直观的方式提升效率。现在,这款工具已在 GitHub 开源,任何人都可以免费体验或改进它。</span></p> <h4 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 15px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(66, 166, 100);><span leaf="">Oliva 背景</span></h4> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">传统 RAG 技术主要基于文本搜索,虽然已经大幅提升 AI 的知识检索能力,但在实际应用中仍存在输入门槛高、交互不够自然、查询效率受限等问题。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">而 Oliva 通过语音驱动 RAG,让 AI 具备更自然的人机交互、实时信息检索、智能化任务协作等优势。</span></p> <h4 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 15px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(66, 166, 100);><span leaf="">主要功能</span></h4> <ul style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: circle;margin: 0px;padding: 0px 0px 0px 1em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;color: rgb(63, 63, 63); class="list-paddingleft-1"> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">•&nbsp;<span textstyle="" style="color: rgb(66, 166, 100);font-weight: bold;">实时语音搜索</span>:用自然语音提问,AI 实时响应</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">•&nbsp;<span textstyle="" style="color: rgb(66, 166, 100);font-weight: bold;">多智能体协作</span>:采用 Langchain 多智能体架构,可将复杂问题拆解成多个子任务</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">•&nbsp;<span textstyle="" style="color: rgb(66, 166, 100);font-weight: bold;">向量搜索优化</span>:基于 Qdrant 向量数据库,支持语义搜索</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">•&nbsp;<span textstyle="" style="color: rgb(66, 166, 100);font-weight: bold;">灵活集成</span>:可连接本地或云端知识库</span> </section></li> </ul> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">同时 Oliva 允许用户将 本地文档、API 数据源、在线网页 等作为 AI 的知识库,支持个性化配置。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">Oliva 集成了 Deepgram(语音转文本)和 LiveKit(实时语音通信),将用户的自然语言指令转化为对向量数据库的查询,最终返回结构化结果。</span></p> <h4 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 15px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(66, 166, 100);><span leaf="">快速使用</span></h4> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">Oliva 是由Python语言开发实现的,目前仅支持本地部署。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf=""><img alt="Livekit Agent Playground" class="rich_pages wxw-img" data-imgfileid="100018090" data-ratio="0.6018691588785047" src="/upload/de2fc887b42f1c969a3ade90c2545e3f.png" data-type="png" data-w="2140"></span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">首先,把项目克隆到本地</span></p> <pre style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;margin: 10px 8px;background: rgb(0, 0, 0);color: rgb(234, 234, 234);text-align: left;line-height: 1.5;overflow-x: auto;border-radius: 8px;padding: 0px !important;><span hidden style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));display: flex;padding: 10px 14px 0px;"> <svg viewbox="0 0 450 130" height="13px" width="45px" y="0px" x="0px" version="1.1" xmlns="http://www.w3.org/2000/svg"> <ellipse fill="rgb(237,108,96)" stroke-width="2" stroke="rgb(220,60,54)" ry="52" rx="50" cy="65" cx="50"></ellipse><ellipse fill="rgb(247,193,81)" stroke-width="2" stroke="rgb(218,151,33)" ry="52" rx="50" cy="65" cx="225"></ellipse><ellipse fill="rgb(100,200,86)" stroke-width="2" stroke="rgb(27,161,37)" ry="52" rx="50" cy="65" cx="400"></ellipse> </svg></span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: Menlo, " operator mono, consolas, monaco, monospace;font-feature-settings: normal;font-variation-settings: normal;font-size: 15px;display: -webkit-box;padding: 0.5em 1em 1em;overflow-x: auto;text-indent: 0px;text-align: left;line-height: 1.75;margin: 0px;white-space: nowrap;><span leaf="">git&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(231, 140, 69);"><span leaf="">clone</span></span><span leaf="">&nbsp;https://github.com/Deluxer/oliva.git</span><span leaf=""><br></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(231, 140, 69);"><span leaf="">cd</span></span><span leaf="">&nbsp;oliva</span></code></pre> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">再执行下面的命令,自动创建虚拟环境,安装依赖项</span></p> <pre style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;margin: 10px 8px;background: rgb(0, 0, 0);color: rgb(234, 234, 234);text-align: left;line-height: 1.5;overflow-x: auto;border-radius: 8px;padding: 0px !important;><span hidden style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));display: flex;padding: 10px 14px 0px;"> <svg viewbox="0 0 450 130" height="13px" width="45px" y="0px" x="0px" version="1.1" xmlns="http://www.w3.org/2000/svg"> <ellipse fill="rgb(237,108,96)" stroke-width="2" stroke="rgb(220,60,54)" ry="52" rx="50" cy="65" cx="50"></ellipse><ellipse fill="rgb(247,193,81)" stroke-width="2" stroke="rgb(218,151,33)" ry="52" rx="50" cy="65" cx="225"></ellipse><ellipse fill="rgb(100,200,86)" stroke-width="2" stroke="rgb(27,161,37)" ry="52" rx="50" cy="65" cx="400"></ellipse> </svg></span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: Menlo, " operator mono, consolas, monaco, monospace;font-feature-settings: normal;font-variation-settings: normal;font-size: 15px;display: -webkit-box;padding: 0.5em 1em 1em;overflow-x: auto;text-indent: 0px;text-align: left;line-height: 1.75;margin: 0px;white-space: nowrap;><span leaf="">uv&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(231, 140, 69);"><span leaf="">sync</span></span></code></pre> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">该工具,依赖 Livekit 账户,先注册登录,拿到APIKEY、APISECRET,配置环境变量</span></p> <pre style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;margin: 10px 8px;background: rgb(0, 0, 0);color: rgb(234, 234, 234);text-align: left;line-height: 1.5;overflow-x: auto;border-radius: 8px;padding: 0px !important;><span hidden style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));display: flex;padding: 10px 14px 0px;"> <svg viewbox="0 0 450 130" height="13px" width="45px" y="0px" x="0px" version="1.1" xmlns="http://www.w3.org/2000/svg"> <ellipse fill="rgb(237,108,96)" stroke-width="2" stroke="rgb(220,60,54)" ry="52" rx="50" cy="65" cx="50"></ellipse><ellipse fill="rgb(247,193,81)" stroke-width="2" stroke="rgb(218,151,33)" ry="52" rx="50" cy="65" cx="225"></ellipse><ellipse fill="rgb(100,200,86)" stroke-width="2" stroke="rgb(27,161,37)" ry="52" rx="50" cy="65" cx="400"></ellipse> </svg></span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: Menlo, " operator mono, consolas, monaco, monospace;font-feature-settings: normal;font-variation-settings: normal;font-size: 15px;display: -webkit-box;padding: 0.5em 1em 1em;overflow-x: auto;text-indent: 0px;text-align: left;line-height: 1.75;margin: 0px;white-space: nowrap;><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(150, 152, 150);"><span leaf=""># 注册登录&nbsp;</span></span><span leaf=""><br></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(150, 152, 150);"><span leaf=""># https://cloud.livekit.io</span></span><span leaf=""><br></span><span leaf=""><br></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(231, 140, 69);"><span leaf="">cp</span></span><span leaf="">&nbsp;.env.example .</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(231, 140, 69);"><span leaf="">env</span></span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">LIVEKIT_URL=wss://your-project.livekit.cloud</span><span leaf=""><br></span><span leaf="">LIVEKIT_API_KEY=secret</span><span leaf=""><br></span><span leaf="">LIVEKIT_API_SECRET=********</span></code></pre> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">使用Docker运行Qdrant,在想要的地方设置API密钥:</span></p> <pre style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;margin: 10px 8px;background: rgb(0, 0, 0);color: rgb(234, 234, 234);text-align: left;line-height: 1.5;overflow-x: auto;border-radius: 8px;padding: 0px !important;><span hidden style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));display: flex;padding: 10px 14px 0px;"> <svg viewbox="0 0 450 130" height="13px" width="45px" y="0px" x="0px" version="1.1" xmlns="http://www.w3.org/2000/svg"> <ellipse fill="rgb(237,108,96)" stroke-width="2" stroke="rgb(220,60,54)" ry="52" rx="50" cy="65" cx="50"></ellipse><ellipse fill="rgb(247,193,81)" stroke-width="2" stroke="rgb(218,151,33)" ry="52" rx="50" cy="65" cx="225"></ellipse><ellipse fill="rgb(100,200,86)" stroke-width="2" stroke="rgb(27,161,37)" ry="52" rx="50" cy="65" cx="400"></ellipse> </svg></span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: Menlo, " operator mono, consolas, monaco, monospace;font-feature-settings: normal;font-variation-settings: normal;font-size: 15px;display: -webkit-box;padding: 0.5em 1em 1em;overflow-x: auto;text-indent: 0px;text-align: left;line-height: 1.75;margin: 0px;white-space: nowrap;><span leaf="">docker run -p 6333:6333 -p 6334:6334 \</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; -e QDRANT__SERVICE__API_KEY=******** \</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; -v&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(185, 202, 74);"><span leaf="">"</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">$(pwd)</span></span><span leaf="">/qdrant_storage:/qdrant/storage:z"</span></span><span leaf="">&nbsp;\</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; qdrant/qdrant</span></code></pre> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">启动语音助手</span></p> <pre style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;margin: 10px 8px;background: rgb(0, 0, 0);color: rgb(234, 234, 234);text-align: left;line-height: 1.5;overflow-x: auto;border-radius: 8px;padding: 0px !important;><span hidden style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));display: flex;padding: 10px 14px 0px;"> <svg viewbox="0 0 450 130" height="13px" width="45px" y="0px" x="0px" version="1.1" xmlns="http://www.w3.org/2000/svg"> <ellipse fill="rgb(237,108,96)" stroke-width="2" stroke="rgb(220,60,54)" ry="52" rx="50" cy="65" cx="50"></ellipse><ellipse fill="rgb(247,193,81)" stroke-width="2" stroke="rgb(218,151,33)" ry="52" rx="50" cy="65" cx="225"></ellipse><ellipse fill="rgb(100,200,86)" stroke-width="2" stroke="rgb(27,161,37)" ry="52" rx="50" cy="65" cx="400"></ellipse> </svg></span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: Menlo, " operator mono, consolas, monaco, monospace;font-feature-settings: normal;font-variation-settings: normal;font-size: 15px;display: -webkit-box;padding: 0.5em 1em 1em;overflow-x: auto;text-indent: 0px;text-align: left;line-height: 1.75;margin: 0px;white-space: nowrap;><span leaf="">make oliva-start</span></code></pre> <h4 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 15px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(66, 166, 100);><span leaf="">适用场景</span></h4> <ul style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: circle;margin: 0px;padding: 0px 0px 0px 1em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;color: rgb(63, 63, 63); class="list-paddingleft-1"> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• 知识库搜索:企业内部文档、FAQ、技术手册等。</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• 智能客服:支持语音交互的 AI 客服助手。</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• 语音驱动 AI 应用:智能家居、移动端 AI 语音助手等。</span> </section></li> </ul> <h4 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 15px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(66, 166, 100);><span leaf="">写在最后</span></h4> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><strong style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-weight: bold;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: inherit;color: rgb(66, 166, 100);><span leaf="">Oliva</span></strong><span leaf="">&nbsp;通过语音搜索 + RAG + 多智能体协作,让 AI 交互更加自然、智能和高效。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">自然语言搜索,门槛低到极致;多智能体协作,响应快且精准;LangChain 和 Superlinked 强强联合。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">它不仅提升了信息检索的体验,还能帮助开发者搭建更加个性化的 AI 语音助手。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">GitHub 项目地址:&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 15px;color: rgb(87, 107, 149);><span leaf="">https://github.com/Deluxer/oliva</span></span></p> </section>

Second Me 开源了!第一个可以本地训练的 AI 身份模型

作者:微信小助手

<section style="color: rgb(62, 62, 62);"> <section style="font-size: 16px;margin-top: 10px;margin-bottom: 10px;"> <section style="text-align: left;"> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> <section style="font-size: 16px;"> <section style=""> <section style="text-align: unset;padding-right: 10px;padding-left: 10px;"> <p>除了通用大模型(LLM)和智能体(Agent),AI 还有第三个大赛道吗?</p> <p><br></p> <p>是的,随着越来越多人告诉我们,我们需要 AI 不仅仅成为工具,而是成为我们人的延伸,更多的对齐我们自己,成为我们的身份。于是我们需要:</p> <p><br></p> <p style="text-align: center;"><strong>AI 身份模型(AI Identity Model)</strong></p> <p style="text-align: center;"><strong><br></strong></p> <p style="text-align: left;"><strong>心识宇宙(Mindverse)发布的 Second Me 就是世界上第一个开源的 AI 身份模型,同时开源了背后的核心技术 - AI-Native Memory。</strong></p> <p style="text-align: left;"><br></p> <p style="text-align: left;">不仅如此,他还是本地训练和部署,<strong>你可以在电脑上训练 “第二自我”</strong>。并且在部署后,可以把你的 AI 身份,<strong>接入到整个互联网世界</strong>,让你的 AI 身份可以被所有人和应用访问、使用,无限放大你的存在感!<strong><br></strong></p> <p><br></p> <section style="margin-top: 10px;margin-bottom: 10px;color: rgb(62, 62, 62);font-size: 16px;letter-spacing: 0.578px;text-align: center;line-height: 0;"> <section style="vertical-align: middle;display: inline-block;line-height: 0;"> <img class="rich_pages wxw-img" data-backh="325" data-backw="578" data-cropselx1="0" data-cropselx2="578" data-cropsely1="0" data-cropsely2="325" data-imgfileid="100001602" data-ratio="0.562962962962963" data-s="300,640" src="/upload/7a7dd342d975390b8134eb8e2778d689.png" data-type="png" data-w="1080" style="vertical-align: middle;width: 578px;"> </section> </section> <section style="margin-bottom: 0px;color: rgb(148, 148, 148);font-size: 12px;letter-spacing: 0.578px;"> <strong>▲ 扫描二维码,来 GitHub 为我们点 🌟&nbsp;</strong> </section> <section style="margin-bottom: 0px;color: rgb(148, 148, 148);font-size: 12px;letter-spacing: 0.578px;"> <strong>开源地址:https://github.com/mindverse/Second-Me</strong> </section> <section style="margin-bottom: 0px;color: rgb(148, 148, 148);font-size: 12px;letter-spacing: 0.578px;"> <br> </section> </section> </section> </section> <p style="font-size: 16px;"><br></p> <section style="font-size: 16px;text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;"> <section style="vertical-align: middle;display: inline-block;line-height: 0;"> <img class="rich_pages wxw-img" data-imgfileid="100001588" data-ratio="0.3425925925925926" data-s="300,640" src="/upload/915fb2cb50e137496684738de5f38263.png" data-type="png" data-w="1080" style="vertical-align: middle;width: 100%;"> </section> </section> <p style="font-size: 16px;"><br></p> <section style="font-size: 18px;text-align: left;padding-right: 10px;padding-left: 10px;"> <p><strong>训练你的 “第二个自己”</strong></p> </section> <p style="font-size: 16px;"><br></p> <section style="font-size: 16px;"> <grammarly-extension style="top: 0px;left: 0px;pointer-events: none;"></grammarly-extension><grammarly-extension style="top: 0px;left: 0px;pointer-events: none;"></grammarly-extension> <section style=""> <section style="text-align: unset;padding-right: 10px;padding-left: 10px;"> <p>Second Me 与通用大模型生成标准化回答不同,它通过深度学习你的真实记忆数据,构建真正“关于你”的高度个性化身份模型。</p> <p><br></p> <p>训练中采用了独特的 AI-Native Memory 技术(<a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzkxODMzNTc2Mw==&amp;mid=2247486107&amp;idx=1&amp;sn=82d0f6cace1bd8f7ece687877f7e23c4&amp;scene=21#wechat_redirect" textvalue="未来已来?AI-native memory 让 LLMs 走向 AGI" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="2">未来已来?AI-native memory 让 LLMs 走向 AGI</a>),并所有数据都在本地处理,<strong>确保 100% 隐私安全</strong>。</p> <p><br></p> <p>这个 AI 原生记忆的技术,我们也完全 100% 代码开源。</p> <p><br></p> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100001605" data-ratio="0.5625" data-s="300,640" src="/upload/369e0a4c10758e7804b0e1139dc3fc57.png" data-type="gif" data-w="768" style=""></p> <p style="text-align: center;"><br></p> </section> </section> </section> <section style="font-size: 16px;"> <section style="text-align: unset;"> <p><br></p> </section> </section> <section style="font-size: 18px;text-align: left;padding-right: 10px;padding-left: 10px;"> <p><strong>Second Me 的互动模式</strong></p> </section> <section style="font-size: 16px;"> <grammarly-extension style="top: 0px;left: 0px;pointer-events: none;"></grammarly-extension><grammarly-extension style="top: 0px;left: 0px;pointer-events: none;"></grammarly-extension> <p><br></p> </section> <section style="font-size: 16px;"> <section style="text-align: unset;padding-right: 10px;padding-left: 10px;"> <p>在 <span style="color: rgb(68, 117, 238);"><strong>Chat Mode</strong></span> 中,你能与你的 Second Me 直接进行对话,但这不是普通的 AI 聊天:你可以调整记忆检索级别,也可以塑造 Second Me 的行为方式、精准地控制身份模型的思考过程,让所有的思考,发生在独特的个性化思维空间内。看下面这段和 Tao 的 Second Me 的对话:</p> <p><br></p> <section style="outline: 0px;font-family: " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;caret-color: rgb(62, 62, 62);color: 62);font-size: 16px;letter-spacing: normal;transform: translate3d(0px, 0px, 0px);text-align: center;> <section style="padding: 10px;outline: 0px;display: inline-block;width: 784px;height: 240px;vertical-align: top;overflow-y: auto;background-color: rgba(222, 237, 242, 0.89);"> <section style="outline: 0px;overflow: hidden;"> <p style="outline: 0px;"><span leaf="" style="outline: 0px;">问题:“什么是 Second Me?”</span></p> <p style="outline: 0px;"><span leaf="" style="outline: 0px;"><br style="outline: 0px;"></span></p> <section style="outline: 0px;display: inline-block;vertical-align: middle;width: 595.906px;align-self: center;flex: 0 0 auto;"> <p style="outline: 0px;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;"> <think> 好的,用户在询问我关于 Second Me 的信息,并且我的角色是 Tao。让我回顾一下所有的信息,来整体提供关于 Second Me 的答案。 </think></span></span></p> <p style="outline: 0px;white-space-collapse: preserve;text-align: left;"><span leaf="" style="outline: 0px;"><br style="outline: 0px;"></span></p> <p style="outline: 0px;white-space-collapse: preserve;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;">从我的个人记忆中,在“AI”兴趣部分,有一个关于 Second Me 的要点,提到它是一个个人 AI 成为数字人格的概念。关于 Mindverse 和 Upload Intelligence 等项目的各种讨论笔记也将 Second Me 视为一个关键组成部分。例如,在“未来计划与挑战”部分,注意到将 Second Me 作为核心产品是他们策略的一部分。此外,在与 Kolento 的讨论中,他们谈到 Second Me 允许用户创建代表他们在网络上的 AI 化身。</span></span></p> <p style="outline: 0px;white-space-collapse: preserve;text-align: left;"><span leaf="" style="outline: 0px;"><br style="outline: 0px;"></span></p> <p style="outline: 0px;white-space-collapse: preserve;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;">嗯,用户希望解释从 Tao 的视角出发,我需要将所有提到 Tao 的地方重新表述为“我”。</span></span></p> <p style="outline: 0px;white-space-collapse: preserve;text-align: left;"><span leaf="" style="outline: 0px;"><br style="outline: 0px;"></span></p> <p style="outline: 0px;white-space-collapse: preserve;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;">Second Me 的核心是创建一个作为用户延伸版本的数字身份。它用于各种交互,无论是在用户自己的工作空间中,还是上传到外部网络。需要包括的要点有核心产品焦点、AI 连接、化身在不同场景中代表用户,以及提到的技术方面,例如训练模型和用户交互指标。</span></span></p> <p style="outline: 0px;white-space-collapse: preserve;text-align: left;"><span leaf="" style="outline: 0px;"><br style="outline: 0px;"></span></p> <p style="outline: 0px;white-space-collapse: preserve;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;">另外,在与 Kevin/Ying 和其他人的会议中,讨论了社交应用和“me.bot”与 AI 伙伴的整合,这与 Second Me 在网络中的角色有关。需要确保所有提到 Tao 的地方都替换为“我”,并且答案涵盖关键要点,简洁而不冗余,避免包括详细的时间戳,但如果需要,可以提及相关会议,例如“正如在与 Kolento 的讨论中提到的”,但不包括具体时间。</span></span></p> <p style="outline: 0px;white-space-collapse: preserve;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;"></span></span></p> <p style="outline: 0px;white-space-collapse: preserve;text-align: left;"><span leaf="" style="outline: 0px;"><br style="outline: 0px;"></span></p> <p style="outline: 0px;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;"> <answer> &nbsp; </answer></span></span></p> <p style="outline: 0px;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;">Second Me 代表了我想要创建 AI 驱动的数字身份的愿景——“您的第二自我”——它增强了您的数字存在和代理交互。受到与 Kolento 和 Mindverse 团队讨论的启发,它概念化了您的独特数字双胞胎。</span></span></p> <p style="outline: 0px;text-align: left;"><span leaf="" style="outline: 0px;"><br style="outline: 0px;"></span></p> <p style="outline: 0px;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;">旨在:&nbsp;</span></span></p> <p style="outline: 0px;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;">1️⃣ **作为核心基础设施**:通过您的语音、偏好数据进行训练([458–480],[433–449]),Second Me 作为 AI 系统中可共享的身份([2774–2788],[3889–3893])</span></span></p> <p style="outline: 0px;text-align: left;"><span leaf="" style="outline: 0px;"><br style="outline: 0px;"></span></p> <p style="outline: 0px;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;">2️⃣ **启用网络化身份**:您的 “me.bot” 将注册到 Second Me,创建一个可扩展的个人资料网络(参考[3356–3369]和关于 A Agent Marketplace 的讨论)&nbsp;</span></span></p> <p style="outline: 0px;text-align: left;"><span leaf="" style="outline: 0px;"><br style="outline: 0px;"></span></p> <p style="outline: 0px;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;">3️⃣ **促进 AI 到 AI 的交互**:正如在 Mindverse 会议中注意到的([1723–1733],[1898–1924]),您的 Second Me 可以在无需人类监督的情况下处理自动化谈判/推荐。</span></span></p> <p style="outline: 0px;white-space-collapse: preserve;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;">这超越了个人生产力——它是关于创建一个可扩展的数字自我,体现您的认知模式,以在 AI 生态系统中进行有意义的参与。</span></span></p> <p style="outline: 0px;white-space-collapse: preserve;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;"></span></span></p> </section> </section> </section> </section> <p style="outline: 0px;caret-color: rgba(0, 0, 0, 0.9);font-family: " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.544px;><br></p> <p><span style="text-align: unset;font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.578px;>而&nbsp;</span><span style="text-align: unset;font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.578px;color: rgb(68, 117, 238);><strong>Bridge Mode</strong></span><span style="text-align: unset;font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.578px;>&nbsp;则让你的 AI 身份模型<strong>成为你和世界链接的桥梁</strong>,保持你的一致性表达:一方面根据你的风格和偏好来增强需求;另一方面代表你来个性化地反馈世界给你的任何信息。</span></p> <p><span style="text-align: unset;font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.578px;><br></span></p> <p><span style="text-align: unset;font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.578px;></span><span style="text-align: unset;font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.578px;>这就像一个思想同声传译系统,能在信息洪流中精准捕获你的认知频率。</span><span style="text-align: unset;font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.578px;>当你使用它时,你会真正意识到:</span><span style="text-align: unset;font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.578px;>Second Me 不只是一个工具,而是你思</span><span style="text-align: unset;font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.578px;>想的延伸。</span></p> <p><br></p> <section data-pm-slice="0 0 []" style="outline: 0px;caret-color: rgb(62, 62, 62);color: rgb(62, 62, 62);font-size: 16px;letter-spacing: normal;transform: translate3d(0px, 0px, 0px);text-align: center;"> <section style="padding: 10px;outline: 0px;display: inline-block;width: 784px;height: 240px;vertical-align: top;overflow-y: auto;background-color: rgba(222, 237, 242, 0.89);"> <section style="outline: 0px;overflow: hidden;"> <p style="outline: 0px;"><span leaf="" style="outline: 0px;">桥梁模式 Bridge Mode</span></p> <section style="outline: 0px;display: inline-block;vertical-align: middle;width: 595.906px;align-self: center;flex: 0 0 auto;"> <p style="outline: 0px;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;">「我 -&gt; 世界」样例:</span></span></p> <p style="outline: 0px;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;">用户:“请帮我找一家餐厅。”</span></span></p> <p style="outline: 0px;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;font-weight: bold;">Second Me 增强</span><span textstyle="" style="outline: 0px;font-size: 14px;">:“请帮我找一家餐厅,最好不要离未来科技城太远,口味重一点。”</span></span></p> <p style="outline: 0px;text-align: left;"><span leaf="" style="outline: 0px;"><br style="outline: 0px;"></span></p> <p style="outline: 0px;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;">「世界 -&gt; 我」样例:</span></span></p> <p style="outline: 0px;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;">世界反馈:“找到三个工作的岗位,分别是 A,B,C。”</span></span></p> <p style="outline: 0px;text-align: left;"><span leaf="" style="outline: 0px;"><span textstyle="" style="outline: 0px;font-size: 14px;font-weight: bold;">Second Me 评判</span><span textstyle="" style="outline: 0px;font-size: 14px;">:“A 和 B 做 AI 硬件,我更喜欢 AI 应用。请再找三家类似 C。”</span></span></p> </section> </section> </section> </section> </section> </section> <p style="font-size: 16px;"><br></p> <section style="font-size: 16px;text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;"> <br> </section> <section style="font-size: 18px;text-align: left;padding-right: 10px;padding-left: 10px;"> <p><strong>Second Me 网络:释放 AI 身份的潜力</strong></p> </section> <p style="font-size: 16px;"><br></p> <section style="font-size: 16px;padding-right: 10px;padding-left: 10px;"> <p>Second Me 的 <span style="color: rgb(68, 117, 238);"><strong>Roleplay Apps</strong></span> 能让“你”拥有专门化的 AI 版本,每个版本都有特定的角色和目的。</p> <p><br></p> <p>我们在日常生活中自然会切换不同的人格面具——职场专业模式、好友放飞模式、学习专注模式。Second Me 通过角色扮演模式,让你的 AI 身份智能适配各种场景,同时保持你最本真的核心身份。</p> <p><br></p> <p><span style="font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.034em;>Second Me 不仅仅是个人 AI,它还是一个去中心化网络的一部分。</span><span style="font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.034em;>在&nbsp;</span><span style="font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.034em;color: rgb(68, 117, 238);><strong>Network Apps</strong></span><span style="font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.034em;> 中,你的 AI 身份可以加入一个由代表真实个体的 AI 组成的互联网络,并在这里创建协作空间,与其他 AI 身份互动沟通、协作并创造价值。</span><span style="font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.034em;></span></p> </section> <section style="font-size: 16px;"> <section style="padding-right: 10px;padding-left: 10px;"> <p><br></p> <p>现在,只需一句“策划周末旅行”,三人朋友的 Second Me 就会在虚拟协作空间自动集结,开始一场你们看不见的高效讨论,省掉了<span style="color: rgb(62, 62, 62);font-size: 16px;letter-spacing: 0.578px;">无数条微信、几十个链接分享和漫长的讨论。</span></p> <p><br></p> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100001606" data-ratio="0.5625" data-s="300,640" src="/upload/9e2e96fec9970cec01033ab66b6fa089.png" data-type="gif" data-w="960" style=""></p> <p><span style="display: none;line-height: 0px;">‍</span><br></p> </section> </section> <section style=""> <span style="font-size: 16px;"> <grammarly-extension style="top: 0px;left: 0px;pointer-events: none;"></grammarly-extension> <grammarly-extension style="top: 0px;left: 0px;pointer-events: none;"></grammarly-extension></span> <section style="padding-right: 10px;padding-left: 10px;"> <p style="text-align: left;"><span style="font-size: 18px;"><strong><br></strong></span></p> <p style="text-align: left;"><span style="font-size: 18px;"><strong>One More Thing:让 AI 原生使用的应用</strong></span></p> <p style="font-size: 16px;"><br></p> <p style="font-size: 16px;">过去所有的应用为人使用而设计,但 AI 身份需要新的基础架构来释放全部潜力——这就是&nbsp;<span style="color: rgb(68, 117, 238);"><strong>Second X Apps</strong></span>。先瞥见两个例子:</p> <p style="font-size: 16px;"><br></p> <p style="font-size: 16px;">想象一个 <strong>Second LinkedIn</strong>,它能带着你的意志在数字宇宙疯狂淘金——自动谈判、智能社交、持续搞钱,而你只需要躺在沙滩上喝 Mojito!</p> <p style="font-size: 16px;"><br></p> <p style="font-size: 16px;">或者 <strong>Second Tinder</strong>?你的 AI 身份化身为爱情专家,24 小时不间断地为你寻找灵魂伴侣。当你熟睡时,它正在与潜在匹配对象进行初步对话。</p> </section> </section> <p style="font-size: 16px;"><br></p> <section style="font-size: 16px;text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;"> <section style="vertical-align: middle;display: inline-block;line-height: 0;width: 100%;height: auto;"> <img class="rich_pages wxw-img" data-imgfileid="100001595" data-ratio="0.4888888888888889" data-s="300,640" src="/upload/076ba27acce7e40dce242316e5f8e713.png" data-type="png" data-w="1080" style="vertical-align: middle;width: 100%;"> </section> </section> <p style="font-size: 16px;"><br></p> <p style="font-size: 16px;"><br></p> <section style="font-size: 16px;text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;"> <section style="vertical-align: middle;display: inline-block;line-height: 0;"> <img class="rich_pages wxw-img" data-imgfileid="100001596" data-ratio="0.4361111111111111" data-s="300,640" src="/upload/924f735064e8f00a153c15c6b86e220c.png" data-type="png" data-w="1080" style="vertical-align: middle;width: 100%;"> </section> </section> <section style="font-size: 16px;"> <grammarly-extension style="top: 0px;left: 0px;pointer-events: none;"></grammarly-extension><grammarly-extension style="top: 0px;left: 0px;pointer-events: none;"></grammarly-extension> <section style="padding-right: 10px;padding-left: 10px;"> <p><img class="rich_pages wxw-img" data-imgfileid="100001604" data-ratio="0.44036697247706424" src="/upload/fe441a23ef10ac2fcb9f130e2736fa4e.jpg" data-type="jpeg" data-w="763"></p> <p><br></p> <p style="text-align: left;">详细内容请见:<a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzkxODMzNTc2Mw==&amp;mid=2247486107&amp;idx=1&amp;sn=82d0f6cace1bd8f7ece687877f7e23c4&amp;scene=21#wechat_redirect" textvalue="未来已来?AI-native memory 让 LLMs 走向 AGI" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="2" style="font-size: 16px;letter-spacing: 0.578px;">未来已来?AI-native memory 让 LLMs 走向 AGI</a>,以及 https://arxiv.org/abs/2406.18312 和 https://arxiv.org/abs/2503.08102。</p> <p><br></p> <p><span style="font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.034em;>我们研究发现,现有大模型 LLMs 长上下文的不足,认为 AGI 不应只是盲目地增加模型的上下文长度,也不应该是粗犷的 RAG,而是一个更复杂、多层级、以AI身份模型为核心处理器的系统。</span></p> <p><br></p> <p><strong>最终,每个人都应该有自己的大型个人模型,即 AI 身份模型(LPM)</strong>,它可以看作一个记忆小球,里面参数化并压缩了关于个人的所有类型的记忆;并且,AI 原生记忆还将作为 AGI 时代参与、个性化、社会互动的变革性基础设施的巨大潜力,以及可能带来的隐私、安全挑战及初步解决方案,在主动互动、个性化服务、信息分发以及社交网络等方向上有巨大的潜力。</p> </section> </section> <p style="font-size: 16px;"><br></p> <section style="font-size: 16px;text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;"> <section style="vertical-align: middle;display: inline-block;line-height: 0;"> <img class="rich_pages wxw-img" data-imgfileid="100001594" data-ratio="0.4166666666666667" data-s="300,640" src="/upload/bf30f5ef5e62157a0c281762ddc6351b.png" data-type="png" data-w="1080" style="vertical-align: middle;width: 100%;"> </section> </section> <p style="font-size: 16px;"><br></p> <p style="font-size: 16px;"><br></p> <section style="font-size: 16px;transform: scale(0.8);transform-origin: center center;"> <section style="margin-top: 0.5em;margin-bottom: 0.5em;"> <section style="background-color: rgb(160, 160, 160);height: 2px;"> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> <p style="font-size: 16px;"><br></p> <section style="font-size: 16px;padding-right: 10px;padding-left: 10px;"> <p><strong style="font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.034em;><br>Second Me 是一个完全开源的项目,致力于保护你的隐私,帮助每个人构建真正属于自己的、安全的、本地的 AI 身份。</strong><span style="font-family: mp-quote, " pingfang sc, system-ui, -apple-system, blinkmacsystemfont, helvetica neue, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;letter-spacing: 0.034em;>在这里,你完全掌握数据和智能的主权,仅在你授权下通过安全私密的方式加入网络,共享信息。</span></p> <p><br></p> <p><strong>让 AI 不只是工具,而是我们独特意识的延伸</strong>。</p> </section> <p style="font-size: 16px;"><br></p> <section style="font-size: 16px;text-align: center;margin-top: 10px;margin-bottom: 10px;line-height: 0;"> <section style="vertical-align: middle;display: inline-block;line-height: 0;"> <img class="rich_pages wxw-img" data-backh="325" data-backw="578" data-cropselx1="0" data-cropselx2="578" data-cropsely1="0" data-cropsely2="325" data-imgfileid="100001593" data-ratio="0.562962962962963" data-s="300,640" src="/upload/7a7dd342d975390b8134eb8e2778d689.png" data-type="png" data-w="1080" style="vertical-align: middle;width: 100%;height: auto;"> </section> </section> <p style="font-size: 12px;margin-bottom: 0px;color: rgb(148, 148, 148);letter-spacing: 0.578px;"><strong>▲ 扫描二维码,来 GitHub 为我们点 🌟&nbsp;</strong></p> <p style="font-size: 12px;margin-bottom: 0px;color: rgb(148, 148, 148);letter-spacing: 0.578px;"><strong>成为最早一批加入未来 AI 互联网的人</strong></p> <p style="font-size: 12px;margin-bottom: 0px;color: rgb(148, 148, 148);letter-spacing: 0.578px;"><strong>开源地址:https://github.com/mindverse/Second-Me</strong></p> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>

RagFlow进阶|Text2SQL 优化方法明细大公开

作者:微信小助手

<p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;" data-pm-slice="0 0 []"><span style="color: rgb(63, 63, 63);"><span leaf="">之前我的一篇文章里提到的使用 RagFlow 知识库配置+Agent 结合的模式,实现简单的 Text2SQL。</span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;" data-pm-slice="0 0 []"><span style="color: rgb(63, 63, 63);"><span leaf=""><br></span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">后台很多小伙伴留言,按照文章提到的方法,进行 Agent 搭建时,遇到了各种各样的问题。我把问题类型做了一些整理,并且总结对应的优化方法。</span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span leaf=""><br></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">首先,我们先来看一下,影响 Text2SQL 成功的几大因素。再逐一分析在 RagFlow 框架中的解决方案。</span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf=""><br></span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">我把整体流程简单画了一下:</span></span></p> <section style="color: rgb(0, 0, 0);font-family: Times;font-size: medium;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;text-align: center;margin-bottom: 12px;" nodeleaf=""> <img alt="Image" class="rich_pages wxw-img" data-imgfileid="100001766" src="/upload/fc212a7d47ab1089059604d883162302.png" data-type="png" style="display: inline-block;max-width: 100%;height: auto;border-radius: 12px;"> </section> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span leaf=""><br></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">简单来说,从提问到 SQL 成功执行,有这些优化方法:</span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">0、拆解问题。有些问题一个 SQL 就能搞定,但是有些问题,得分成多个 SQL 去完成。</span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">1、确定要写几个 SQL 后,大模型得知道去找哪些表。单表比较简单,但是涉及到多表,就得搞定表关联问题。</span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">2、定位到表,还得知道去找哪个字段;</span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">3、写对 SQL 代码。</span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span leaf=""><br></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">接下来,分开一个个聊,各自的策略应该是怎样的。</span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span leaf=""><br></span></p> <h3 style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-weight: bold;color: rgb(50, 120, 71);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;letter-spacing: 0.578px;margin-top: 0px;margin-bottom: 8px;font-size: 20px;padding-bottom: 12px;"><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">一、拆解问题:复杂查询的SQL分步生成策略</span></span></h3> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">在Text2SQL任务中,很多时候,一条 SQL 是没办法直接搞定的。约38%的复杂查询需要拆解为多步SQL执行。</span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">例如用户提问“统计华东地区销售额TOP10客户过去三个月的复购率”,实际需要拆解为:</span></span></p> <ol style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;list-style: none;color: rgb(31, 35, 41);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;font-size: 15px;line-height: 34px;padding-left: 0px;" class="list-paddingleft-1"> <li style="text-align: left;"> <section> <span leaf="">1.&nbsp;</span><span style="color: rgb(63, 63, 63);"><span leaf="">查询客户近90天订单明细</span></span> </section></li> <li style="text-align: left;"> <section> <span leaf="">2.&nbsp;</span><span style="color: rgb(63, 63, 63);"><span leaf="">计算每位客户总销售额</span></span> </section></li> <li style="text-align: left;"> <section> <span leaf="">3.&nbsp;</span><span style="color: rgb(63, 63, 63);"><span leaf="">筛选华东地区TOP10客户</span></span> </section></li> <li style="text-align: left;"> <section> <span leaf="">4.&nbsp;</span><span style="color: rgb(63, 63, 63);"><span leaf="">关联历史订单计算复购周期</span></span> </section></li> </ol> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">在RAGFlow中,可以这么解决:</span></span></p> <ul style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;color: rgb(31, 35, 41);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;font-size: 15px;line-height: 34px;padding-left: 20px;" class="list-paddingleft-1"> <li style="text-align: left;"><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">Agent任务编排</span></span><span style="color: rgb(63, 63, 63);"><span leaf="">:通过内置工作流引擎自动拆解多步查询,每个子任务生成独立SQL</span></span></li> <li style="text-align: left;"><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">上下文继承机制</span></span><span style="color: rgb(63, 63, 63);"><span leaf="">:将前序查询结果作为后续SQL的临时表,例如将步骤1的中间表</span></span><span style="color: rgb(63, 63, 63);padding: 1px 2px;border: 1px solid rgb(222, 224, 227);border-radius: 4px;margin: 0px 3px;background-color: rgb(187, 191, 196);"><span leaf="">tmp_order_detail</span></span><span style="color: rgb(63, 63, 63);"><span leaf="">传递给步骤2使用</span></span></li> </ul> <hr style="color: rgb(0, 0, 0);font-family: Times;font-size: medium;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;margin: 24px 0px;border-style: solid;border-width: 1px 0px 0px;border-color: rgba(0, 0, 0, 0.1);"> <h3 style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-weight: bold;color: rgb(50, 120, 71);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;letter-spacing: 0.578px;margin-top: 0px;margin-bottom: 8px;font-size: 20px;padding-bottom: 12px;"><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">二、表定位:数据库模式理解的三大武器</span></span></h3> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">实际的 Text2SQL 中,最难的部分,在于让模型理解复杂的业务分析场景。那么,如何增强模型对于对业务背景知识的理解,如业务模型间的关联关系等。</span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">在RAGFlow通过四重知识库解决业务理解和表定位难题:</span></span></p> <ol style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;list-style: none;color: rgb(31, 35, 41);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;font-size: 15px;line-height: 34px;padding-left: 0px;" class="list-paddingleft-1"> <li style="text-align: left;"> <section> <span leaf="">1.&nbsp;</span><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">DSL知识库</span></span><span style="color: rgb(63, 63, 63);"><span leaf="">&nbsp;存储精确表结构定义,例如商品表的字段注释。模型通过字段语义匹配识别目标表。</span></span> </section></li> </ol> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">DSL 知识库举例:</span></span></p> <section style="color: rgb(0, 0, 0);font-family: Times;font-size: medium;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;margin-top: 12px;margin-bottom: 12px;"> <span style=" display: block;height: 30px;background-color: rgb(40, 44, 52);border-top-left-radius: 5px;border-top-right-radius: 5px; margin: 0px;color: rgb(0, 0, 0);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial; "><span style="height: 30px;line-height: 30px;margin-left: 10px;display: flex;"><span style="width: 10px;height: 10px;border-radius: 50%;background-color: rgb(255, 95, 86);margin-right: 8px;margin-top: 10px;"></span><span style="width: 10px;height: 10px;border-radius: 50%;background-color: rgb(255, 189, 46);margin-right: 8px;margin-top: 10px;"></span><span style="width: 10px;height: 10px;border-radius: 50%;background-color: rgb(39, 201, 63);margin-top: 10px;"></span></span></span> <pre style="margin: 0px;"><code style="color: rgb(171, 178, 191);background: rgb(40, 44, 52);padding: 4px 15px 15px;display: block;overflow-x: auto;border-bottom-left-radius: 5px;border-bottom-right-radius: 5px;font-family: Consolas, Monaco, Menlo, monospace;font-size: 14px;line-height: 1.5;"><br><span leaf="">用户表(users)</span><br><span leaf="">用户表用于存储网站或应用的用户信息。以下是该表中每个字段的含义:</span><br><span style="color: rgb(97, 174, 238);"><span leaf="">-</span></span><span leaf="">&nbsp;</span><span><span leaf="">`id`</span></span><span leaf="">: 这是一个整数类型的自增字段,作为用户的唯一标识符(主键)。每次添加新用户时,该字段会自动增加,确保每个用户都有一个唯一的ID。</span><br><span style="color: rgb(97, 174, 238);"><span leaf="">-</span></span><span leaf="">&nbsp;</span><span><span leaf="">`username`</span></span><span leaf="">: 字符串类型,用于存储用户的用户名。用户名通常是用户登录时使用的唯一标识符。</span><br><span style="color: rgb(97, 174, 238);"><span leaf="">-</span></span><span leaf="">&nbsp;</span><span><span leaf="">`password`</span></span><span leaf="">: 字符串类型,用于存储用户的密码。出于安全考虑,密码在存储前应进行加密处理。</span><br><span style="color: rgb(97, 174, 238);"><span leaf="">-</span></span><span leaf="">&nbsp;</span><span><span leaf="">`email`</span></span><span leaf="">: 字符串类型,用于存储用户的电子邮件地址。电子邮件地址可以是用户的另一个登录凭证,并且用于接收通知或重置密码。</span><br><span style="color: rgb(97, 174, 238);"><span leaf="">-</span></span><span leaf="">&nbsp;</span><span><span leaf="">`mobile`</span></span><span leaf="">: 字符串类型,用于存储用户的手机号码。手机号码可用于登录、接收短信通知或进行身份验证。</span><br><span style="color: rgb(97, 174, 238);"><span leaf="">-</span></span><span leaf="">&nbsp;</span><span><span leaf="">`create_time`</span></span><span leaf="">: 时间戳类型,记录用户账户创建的时间。默认值为当前时间。</span><br><span style="color: rgb(97, 174, 238);"><span leaf="">-</span></span><span leaf="">&nbsp;</span><span><span leaf="">`update_time`</span></span><span leaf="">: 时间戳类型,记录用户信息最后更新的时间。每次更新用户信息时,该字段都会自动更新为当前时间。</span></code></pre> </section> <ol style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;list-style: none;color: rgb(31, 35, 41);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;font-size: 15px;line-height: 34px;padding-left: 0px;" class="list-paddingleft-1"> <li style="text-align: left;"> <section> <span leaf="">2.&nbsp;</span><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">Q-&gt;SQL样本库</span></span><span style="color: rgb(63, 63, 63);"><span leaf="">&nbsp;相当于给模型 Few-shot,包含典型问题-SQL映射,相似问题触发快速匹配。如:</span></span> </section></li> </ol> <section style="font-size: medium;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;border-left: 3px solid rgb(50, 120, 71);padding: 0px 4px 0px 12px;margin-bottom: 12px;background-color: rgb(245, 247, 239);color: rgb(89, 89, 89);"> <p style="font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;text-align: left;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">问:"查手机库存" →</span></span></p> <p style="font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">SQL:</span></span><span style="color: rgb(63, 63, 63);padding: 1px 2px;border: 1px solid rgb(222, 224, 227);border-radius: 4px;margin: 0px 3px;background-color: rgb(187, 191, 196);"><span leaf="">SELECT stock FROM products WHERE name LIKE '%手机%'</span></span></p> </section> <ol style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;list-style: none;color: rgb(31, 35, 41);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;font-size: 15px;line-height: 34px;padding-left: 0px;" class="list-paddingleft-1"> <li style="text-align: left;"> <section> <span leaf="">3.&nbsp;</span><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">业务描述知识库</span></span><span style="color: rgb(63, 63, 63);"><span leaf="">&nbsp;定义表关联关系,例如:</span></span> </section></li> </ol> <section style="color: rgb(0, 0, 0);font-family: Times;font-size: medium;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;text-align: left;margin-top: 12px;margin-bottom: 12px;"> <span style=" display: block;height: 30px;background-color: rgb(40, 44, 52);border-top-left-radius: 5px;border-top-right-radius: 5px; margin: 0px;color: rgb(0, 0, 0);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial; "><span style="height: 30px;line-height: 30px;margin-left: 10px;display: flex;"><span style="width: 10px;height: 10px;border-radius: 50%;background-color: rgb(255, 95, 86);margin-right: 8px;margin-top: 10px;"></span><span style="width: 10px;height: 10px;border-radius: 50%;background-color: rgb(255, 189, 46);margin-right: 8px;margin-top: 10px;"></span><span style="width: 10px;height: 10px;border-radius: 50%;background-color: rgb(39, 201, 63);margin-top: 10px;"></span></span></span> <pre style="margin: 0px;"><code style="color: rgb(171, 178, 191);background: rgb(40, 44, 52);padding: 4px 15px 15px;display: block;overflow-x: auto;border-bottom-left-radius: 5px;border-bottom-right-radius: 5px;font-family: Consolas, Monaco, Menlo, monospace;font-size: 14px;line-height: 1.5;"><span><span leaf="">{</span></span><span style="color: rgb(209, 154, 102);"><span leaf="">"商品表"</span></span><span><span leaf="">:</span></span><span leaf="">&nbsp;</span><span><span leaf="">{</span></span><span style="color: rgb(209, 154, 102);"><span leaf="">"关联表"</span></span><span><span leaf="">:</span></span><span leaf="">&nbsp;</span><span><span leaf="">[</span></span><span style="color: rgb(152, 195, 121);"><span leaf="">"库存表"</span></span><span><span leaf="">,</span></span><span leaf="">&nbsp;</span><span style="color: rgb(152, 195, 121);"><span leaf="">"销售表"</span></span><span leaf="">,</span><span style="color: rgb(152, 195, 121);"><span leaf="">"计划表"</span></span><span><span leaf="">]</span></span><span><span leaf="">,</span></span><span leaf="">&nbsp;</span><span style="color: rgb(209, 154, 102);"><span leaf="">"外键"</span></span><span><span leaf="">:</span></span><span leaf="">&nbsp;</span><span style="color: rgb(152, 195, 121);"><span leaf="">"product_id"</span></span><span><span leaf="">}</span></span><span><span leaf="">}</span></span></code></pre> </section> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;text-align: left;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">当用户查询"华为手机的周销量和计划完成进度时,自动关联商品表、销售表和计划表。</span></span></p> <h3 style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-weight: bold;color: rgb(50, 120, 71);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;letter-spacing: 0.578px;margin-top: 0px;margin-bottom: 8px;font-size: 20px;padding-bottom: 12px;"><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">三、字段定位:语义理解的两层保障</span></span></h3> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">通过RAGFlow,可以采用两种组合策略提升字段匹配精度:</span></span></p> <ol style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;list-style: none;color: rgb(31, 35, 41);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;font-size: 15px;line-height: 34px;padding-left: 0px;" class="list-paddingleft-1"> <li style="text-align: left;"> <section> <span leaf="">1.&nbsp;</span><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">数据类型校验</span></span><span style="color: rgb(63, 63, 63);"><span leaf="">:通过DDL约束过滤无效字段,例如金额字段不会出现字符串比较。</span></span> </section></li> </ol> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">DDL 知识库举例:</span></span></p> <section style="color: rgb(0, 0, 0);font-family: Times;font-size: medium;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;text-align: left;margin-top: 12px;margin-bottom: 12px;"> <span style=" display: block;height: 30px;background-color: rgb(40, 44, 52);border-top-left-radius: 5px;border-top-right-radius: 5px; margin: 0px;color: rgb(0, 0, 0);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial; "><span style="height: 30px;line-height: 30px;margin-left: 10px;display: flex;"><span style="width: 10px;height: 10px;border-radius: 50%;background-color: rgb(255, 95, 86);margin-right: 8px;margin-top: 10px;"></span><span style="width: 10px;height: 10px;border-radius: 50%;background-color: rgb(255, 189, 46);margin-right: 8px;margin-top: 10px;"></span><span style="width: 10px;height: 10px;border-radius: 50%;background-color: rgb(39, 201, 63);margin-top: 10px;"></span></span></span> <pre style="margin: 0px;"><code style="color: rgb(171, 178, 191);background: rgb(40, 44, 52);padding: 4px 15px 15px;display: block;overflow-x: auto;border-bottom-left-radius: 5px;border-bottom-right-radius: 5px;font-family: Consolas, Monaco, Menlo, monospace;font-size: 14px;line-height: 1.5;"><span style="color: rgb(198, 120, 221);"><span leaf="">CREATE</span></span><span leaf="">&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">TABLE</span></span><span leaf="">&nbsp;`products` (</span><br><span leaf="">&nbsp; `id`&nbsp;</span><span style="color: rgb(209, 154, 102);"><span leaf="">INT</span></span><span leaf="">&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">NOT</span></span><span leaf="">&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">NULL</span></span><span leaf="">&nbsp;AUTO_INCREMENT,</span><br><span leaf="">&nbsp; `name`&nbsp;</span><span style="color: rgb(209, 154, 102);"><span leaf="">VARCHAR</span></span><span leaf="">(</span><span style="color: rgb(209, 154, 102);"><span leaf="">100</span></span><span leaf="">)&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">NOT</span></span><span leaf="">&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">NULL</span></span><span leaf="">,</span><br><span leaf="">&nbsp; `description` TEXT,</span><br><span leaf="">&nbsp; `price`&nbsp;</span><span style="color: rgb(209, 154, 102);"><span leaf="">DECIMAL</span></span><span leaf="">(</span><span style="color: rgb(209, 154, 102);"><span leaf="">10</span></span><span leaf="">,&nbsp;</span><span style="color: rgb(209, 154, 102);"><span leaf="">2</span></span><span leaf="">)&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">NOT</span></span><span leaf="">&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">NULL</span></span><span leaf="">,</span><br><span leaf="">&nbsp; `stock`&nbsp;</span><span style="color: rgb(209, 154, 102);"><span leaf="">INT</span></span><span leaf="">&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">NOT</span></span><span leaf="">&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">NULL</span></span><span leaf="">,</span><br><span leaf="">&nbsp; `category_id`&nbsp;</span><span style="color: rgb(209, 154, 102);"><span leaf="">INT</span></span><span leaf="">,</span><br><span leaf="">&nbsp; `merchant_id`&nbsp;</span><span style="color: rgb(209, 154, 102);"><span leaf="">INT</span></span><span leaf="">&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">NOT</span></span><span leaf="">&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">NULL</span></span><span leaf="">,</span><br><span leaf="">&nbsp; `create_time`&nbsp;</span><span style="color: rgb(209, 154, 102);"><span leaf="">TIMESTAMP</span></span><span leaf="">&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">NOT</span></span><span leaf="">&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">NULL</span></span><span leaf="">&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">DEFAULT</span></span><span leaf="">&nbsp;</span><span style="color: rgb(230, 192, 123);"><span leaf="">CURRENT_TIMESTAMP</span></span><span leaf="">,</span><br><span leaf="">&nbsp; `update_time`&nbsp;</span><span style="color: rgb(209, 154, 102);"><span leaf="">TIMESTAMP</span></span><span leaf="">&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">NOT</span></span><span leaf="">&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">NULL</span></span><span leaf="">&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">DEFAULT</span></span><span leaf="">&nbsp;</span><span style="color: rgb(230, 192, 123);"><span leaf="">CURRENT_TIMESTAMP</span></span><span leaf="">&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">ON</span></span><span leaf="">&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">UPDATE</span></span><span leaf="">&nbsp;</span><span style="color: rgb(230, 192, 123);"><span leaf="">CURRENT_TIMESTAMP</span></span><span leaf="">,</span><br><span leaf="">&nbsp;&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">PRIMARY</span></span><span leaf="">&nbsp;KEY (`id`),</span><br><span leaf="">&nbsp;&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">FOREIGN</span></span><span leaf="">&nbsp;KEY (`merchant_id`)&nbsp;</span><span style="color: rgb(198, 120, 221);"><span leaf="">REFERENCES</span></span><span leaf="">&nbsp;`merchants` (`id`)</span><br><span leaf="">)</span></code></pre> </section> <ol style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;list-style: none;color: rgb(31, 35, 41);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;font-size: 15px;line-height: 34px;padding-left: 0px;" class="list-paddingleft-1"> <li style="text-align: left;"> <section> <span leaf="">2.&nbsp;</span><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">管理特定领域的同义词</span></span> </section></li> </ol> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">一些行业专有术语在大模型的预训练数据集里并没有。增加专有名词知识库,可以让模型快速的反应,并且快速识别到准确的数据字段。</span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">专业的领域同义词可以极大地影响 SQL 查询条件的生成。因此,维护一个广泛且最新的同义词库对于缓解这一挑战至关重要。</span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">在业务知识库预置同义词映射关系,如:</span></span></p> <section style="color: rgb(0, 0, 0);font-family: Times;font-size: medium;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;text-align: left;margin-top: 12px;margin-bottom: 12px;"> <span style=" display: block;height: 30px;background-color: rgb(40, 44, 52);border-top-left-radius: 5px;border-top-right-radius: 5px; margin: 0px;color: rgb(0, 0, 0);font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial; "><span style="height: 30px;line-height: 30px;margin-left: 10px;display: flex;"><span style="width: 10px;height: 10px;border-radius: 50%;background-color: rgb(255, 95, 86);margin-right: 8px;margin-top: 10px;"></span><span style="width: 10px;height: 10px;border-radius: 50%;background-color: rgb(255, 189, 46);margin-right: 8px;margin-top: 10px;"></span><span style="width: 10px;height: 10px;border-radius: 50%;background-color: rgb(39, 201, 63);margin-top: 10px;"></span></span></span> <pre style="margin: 0px;"><code style="color: rgb(171, 178, 191);background: rgb(40, 44, 52);padding: 4px 15px 15px;display: block;overflow-x: auto;border-bottom-left-radius: 5px;border-bottom-right-radius: 5px;font-family: Consolas, Monaco, Menlo, monospace;font-size: 14px;line-height: 1.5;"><span leaf="">{"库存": ["stock", "库存量", "现货数"],</span><br><span leaf="">"批售": ["wholesale", "批发销售量", "批发量"],</span><br><span leaf="">"终端": ["terminal", "终端销售量", "零售量"]}</span></code></pre> </section> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span leaf=""><br></span></p> <h3 style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-weight: bold;color: rgb(50, 120, 71);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;letter-spacing: 0.578px;margin-top: 0px;margin-bottom: 8px;font-size: 20px;padding-bottom: 12px;"><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">四、SQL生成:工业级代码质量的保障体系</span></span></h3> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">RAGFlow中Text2SQL具备自动反思迭代的能力,相关功能集成在官方插件 ExeSQL 内。</span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">针对用户的问题,如果大语言模型生成的SQL查询成功则会直接将结果进行返回。</span></span></p> <section style="color: rgb(0, 0, 0);font-family: Times;font-size: medium;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;text-align: center;margin-bottom: 12px;" nodeleaf=""> <img alt="Image" class="rich_pages wxw-img" data-imgfileid="100001765" src="/upload/d53e12cc03c1a44c6efe4178139d3355.png" data-type="png" style="display: inline-block;max-width: 100%;height: auto;border-radius: 12px;"> </section> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">在配置这个插件的参数时,需要留意Loop参数,Loop 参数设置的是大模型的 SQL 代码执行错误后重试的次数。</span></span></p> <section style="color: rgb(0, 0, 0);font-family: Times;font-size: medium;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;text-align: center;margin-bottom: 12px;" nodeleaf=""> <img alt="Image" class="rich_pages wxw-img" data-imgfileid="100001767" src="/upload/2dacd3da36d7b1751f3d5d7ca94bdee1.png" data-type="png" style="display: inline-block;max-width: 100%;height: auto;border-radius: 12px;"> </section> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">如果大语言模型生成的SQL查询失败,则RAGFlow Text2SQL工作流,配置针对数据库查询返回的错误信息和SQL语句进行自动更正进行再次查询。我所使用的 RagFlow v0.17.1版本中,ExeSQL 插件已经内置自动重写 SQL功能。</span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span leaf=""><br></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">对应的,我们可以在其开源的代码</span></span><span style="color: rgb(63, 63, 63);font-weight: bold;padding: 1px 2px;background-color: rgb(245, 246, 247);border: 1px solid rgb(222, 224, 227);border-radius: 4px;margin: 0px 3px;"><span leaf="">exesql.py</span></span><span style="color: rgb(63, 63, 63);"><span leaf="">&nbsp;文件中,看这段代码。</span></span></p> <section style="color: rgb(0, 0, 0);font-family: Times;font-size: medium;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;text-align: center;margin-bottom: 12px;" nodeleaf=""> <img alt="Image" class="rich_pages wxw-img" data-imgfileid="100001769" src="/upload/3562d9b9f903f6290e68d851926164ab.png" data-type="png" style="display: inline-block;max-width: 100%;height: auto;border-radius: 12px;"> </section> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">这个插件配置项中的信息输入和大模型,就是用来做SQL 代码功能重写的。</span></span></p> <section style="color: rgb(0, 0, 0);font-family: Times;font-size: medium;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;text-align: center;margin-bottom: 12px;" nodeleaf=""> <img alt="Image" class="rich_pages wxw-img" data-imgfileid="100001768" src="/upload/433178d1a41f62a53d578528b8ec0835.png" data-type="png" style="display: inline-block;max-width: 100%;height: auto;border-radius: 12px;"> </section> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">该过程(查询失败-&gt;更正SQL语句-&gt;再次查询)最大迭代次数则为Loop参数的值,如果迭代次数超过Loop值,查询结果仍然失败,则程序自动结束过程。</span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">我们需要再针对错误类型优化用户问题或知识库数据后,再次做尝试。</span></span></p> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span leaf=""><br></span></p> <h3 style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-weight: bold;color: rgb(50, 120, 71);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;letter-spacing: 0.578px;margin-top: 0px;margin-bottom: 8px;font-size: 20px;padding-bottom: 12px;"><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">五、持续优化:构建闭环学习系统</span></span></h3> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span style="color: rgb(63, 63, 63);"><span leaf="">在系统上线后,还可以通过RAGFlow的运营优化,持续增强,方法包含:</span></span></p> <ol style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;list-style: none;color: rgb(31, 35, 41);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;font-size: 15px;line-height: 34px;padding-left: 0px;" class="list-paddingleft-1"> <li style="text-align: left;"> <section> <span leaf="">1.&nbsp;</span><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">错误SQL回收</span></span><span style="color: rgb(63, 63, 63);"><span leaf="">:将执行失败的SQL存入待审核库,人工修正后反哺训练</span></span> </section></li> <li style="text-align: left;"> <section> <span leaf="">2.&nbsp;</span><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">热点分析</span></span><span style="color: rgb(63, 63, 63);"><span leaf="">:统计高频访问表字段,动态调整知识库优先级</span></span> </section></li> <li style="text-align: left;"> <section> <span leaf="">3.&nbsp;</span><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">版本追溯</span></span><span style="color: rgb(63, 63, 63);"><span leaf="">:记录每次SQL生成参数,便于AB测试不同策略效果</span></span> </section></li> </ol> <p style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 15px;line-height: 26px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;color: rgb(63, 63, 63);margin: 0px 0px 4px;letter-spacing: 0.1em;word-break: break-all;min-height: 20px;"><span leaf=""><br></span></p> <h3 style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-weight: bold;color: rgb(50, 120, 71);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;letter-spacing: 0.578px;margin-top: 0px;margin-bottom: 8px;font-size: 20px;padding-bottom: 12px;"><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">六、延伸思考:Text2SQL的未来优化方式</span></span></h3> <ol style="font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;list-style: none;color: rgb(31, 35, 41);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, Cambria, Cochin, Georgia, Times, serif;font-size: 15px;line-height: 34px;padding-left: 0px;" class="list-paddingleft-1"> <li style="text-align: left;"> <section> <span leaf="">1.&nbsp;</span><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">混合执行模式</span></span><span style="color: rgb(63, 63, 63);"><span leaf="">:当前未经训练的大模型直出的 SQL只能满足简单场景的查询。当用户的问题涉及复杂场景的时候,或者需要进行数据分析报告,可以考虑将复杂场景转Python计算。</span></span> </section></li> <li style="text-align: left;"> <section> <span leaf="">2.&nbsp;</span><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">可视化解释</span></span><span style="color: rgb(63, 63, 63);"><span leaf="">:生成SQL执行流程图,帮助用户理解数据加工逻辑。</span></span> </section></li> <li style="text-align: left;"> <section> <span leaf="">3.&nbsp;</span><span style="color: rgb(63, 63, 63);font-weight: bold;"><span leaf="">权限融合</span></span><span style="color: rgb(63, 63, 63);"><span leaf="">:结合RBAC模型,将查询者的用户账号和权限记录带入查询参数,动态生成带权限过滤的SQL条件</span></span> </section></li> </ol> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>

Ragflow技术栈分析及二次开发指南

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 10px;padding-right: 10px;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: linear-gradient(90deg, rgba(50, 0, 0, 0.03) 0%, rgba(255, 255, 255, 0) 11.49%), linear-gradient(360deg, rgba(50, 0, 0, 0.04) 0%, rgba(255, 255, 255, 0) 12.16%);background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: repeat, repeat;background-size: 20px 20px, 20px 20px;width: auto;font-family: Optima, PingFangSC-light, serif;font-size: 16px;color: rgb(0, 0, 0);line-height: 1.5em;word-spacing: 0em;letter-spacing: 0em;word-break: break-word;overflow-wrap: break-word;text-align: left;"> <blockquote style="margin-top: 20px;margin-bottom: 20px;margin-left: 0px;margin-right: 0px;padding-top: 10px;padding-bottom: 10px;padding-left: 20px;padding-right: 10px;border-top-style: solid;border-bottom-style: solid;border-left-style: solid;border-right-style: solid;border-top-width: 1px;border-bottom-width: 1px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgba(64, 184, 255, 0.4);border-bottom-color: rgba(64, 184, 255, 0.4);border-left-color: rgba(64, 184, 255, 0.4);border-right-color: rgba(64, 184, 255, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;background-attachment: scroll;background-clip: border-box;background-color: rgba(64, 184, 250, 0.1);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;display: block;overflow-x: auto;overflow-y: auto;"> <span style="display: block;color: rgba(64, 184, 250, 0.5);font-size: 28px;line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;"><span leaf="">❝</span></span> <p style="text-indent: 0em;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;color: rgb(59, 59, 59);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;"><span leaf="">Ragflow是目前团队化部署大模型+RAG的优质方案,不过其仍不适合直接部署使用,本文将从实际使用的角度,对其进行二次开发。</span></p> </blockquote> <h1 data-tool="mdnice编辑器" style="border-bottom-color: rgb(89, 89, 89);margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(89, 89, 89);border-bottom-color: rgb(89, 89, 89);line-height: 1.5em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">1. Ragflow 存在问题</span></span><span style="display: none;"></span></h1> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">Ragflow 开源仓库地址:</span><span leaf="">https://github.com/infiniflow/ragflow</span><span leaf="">Ragflow 当前版本: v0.17.0</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">Ragflow 目前主要存在以下问题:</span></p> <ol style="list-style-type: decimal;margin-top: 8px;margin-bottom: 8px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 25px;padding-right: 0px;color: rgb(0, 0, 0);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <p style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">登录页开放注册</span><span leaf=""><br></span><span leaf="">当前版本,在login页面,用户可直接进行注册,在小规模私有化部署中,开放注册接口,易对用户产生困扰,甚至存在被频繁调用攻击的风险。</span></p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <p style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">知识库共享问题</span><span leaf=""><br></span><span leaf="">当前版本,团队成员进行知识库共享需要知识库的创建者邀请其它成员进团队,发出邀请时,需要其它成员点击接受才行,较为繁琐。</span></p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <p style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">模型设置问题</span><span leaf=""><br></span><span leaf="">当前版本,所有团队成员的模型设置是独立的,如需共用同一套模型配置,需要每个用户单独进行设置,不利于团队化协作。</span></p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <p style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">可视化管理</span><span leaf=""><br></span><span leaf="">当前版本,未存在超级管理员的后台界面,无法直观的对用户账户进行可视化管理。</span></p> </section></li> </ol> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">本文将围绕以上四点问题,对Ragflow进行二次开发解决。</span></p> <h1 data-tool="mdnice编辑器" style="border-bottom-color: rgb(89, 89, 89);margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(89, 89, 89);border-bottom-color: rgb(89, 89, 89);line-height: 1.5em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">2. 开源协议</span></span><span style="display: none;"></span></h1> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">Ragflow采用的是较为宽松的</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">Apache License 2.0&nbsp;</span></code><span leaf="">,这意味着其允许进行二次开发和商用,且修改后可无需开源。</span></p> <h1 data-tool="mdnice编辑器" style="border-bottom-color: rgb(89, 89, 89);margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(89, 89, 89);border-bottom-color: rgb(89, 89, 89);line-height: 1.5em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">3. 技术栈分析</span></span><span style="display: none;"></span></h1> <h2 data-tool="mdnice编辑器" style="border-bottom-color: rgb(89, 89, 89);margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(89, 89, 89);border-bottom-color: rgb(89, 89, 89);line-height: 1.5em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">3.1 容器组件分析</span></span><span style="display: none;"></span></h2> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">通过docker启动该服务时,</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">docker-compose-base.yml</span></code><span leaf="">包含了部分基础配置参数,可以看到整个服务共包含5个容器组件:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ibkkkoaqfco4yxzzqicvzogxxi0hzjbdiciamfnn9ueg4j58f1yacjjdv9f5nuqdff9xa6sw0psarfepjlgbvrgzmoonkibrkjds5 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">services:</span><span leaf=""><br></span><span leaf="">&nbsp; es01:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; container_name: ragflow-es-01</span><span leaf=""><br></span><span leaf="">&nbsp; infinity:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; container_name: ragflow-infinity</span><span leaf=""><br></span><span leaf="">&nbsp; mysql:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; container_name: ragflow-mysql</span><span leaf=""><br></span><span leaf="">&nbsp; minio:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; container_name: ragflow-minio</span><span leaf=""><br></span><span leaf="">&nbsp; redis:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; container_name: ragflow-redis</span><span leaf=""><br></span></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">各组件功能如下:</span></p> <ol style="list-style-type: decimal;margin-top: 8px;margin-bottom: 8px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 25px;padding-right: 0px;color: rgb(0, 0, 0);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <p style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">Elasticsearch</span><span leaf=""><br></span><span leaf="">主要用作文档引擎,负责存储和检索文本及向量数据,作为系统的知识库存储后端,用以支持向量存储和相似度搜索</span></p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <p style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">ragflow-infinity</span><span leaf=""><br></span><span leaf="">前端系统,包含基本的界面显示、数据交互、路由跳转等功能</span></p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <p style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">MySQL</span><span leaf=""><br></span><span leaf="">关系型数据库,存储系统的结构化数据,包括管理用户账户、权限等基础信息、存储知识库的元数据信息等</span></p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <p style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">MinIO</span><span leaf=""><br></span><span leaf="">对象存储服务,用于存储原始文档及文档切片图像信息</span></p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <p style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">Redis</span><span leaf=""><br></span><span leaf="">内存数据库, 采用Valkey版本,缓存大模型的响应结果,处理异步任务,临时保存对话上下文</span></p> </section></li> </ol> <h2 data-tool="mdnice编辑器" style="border-bottom-color: rgb(89, 89, 89);margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(89, 89, 89);border-bottom-color: rgb(89, 89, 89);line-height: 1.5em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">3.2 前后端框架分析</span></span><span style="display: none;"></span></h2> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">该系统前端框架使用React+Typescript,代码统一在</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">web</span></code><span leaf="">文件夹。 后端框架使用Flask+Python,代码分好几部分,具体内容如下:</span></p> <ul style="list-style-type: disc;margin-top: 8px;margin-bottom: 8px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 25px;padding-right: 0px;color: rgb(0, 0, 0);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <span leaf="">agent:对应前端agent相关模块功能</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <span leaf="">agentic_reasoning:对应前端搜索相关模块功能</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <span leaf="">api:核心后端程序,用来与前端进行数据对接,并提供后端服务和其它各组件连接及数据交互功能</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <span leaf="">deepdoc:提供文件ocr等解析相关功能</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <span leaf="">graphrag:知识图谱相关功能</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <span leaf="">rag:主要用以和大模型相关接口进行交互</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;"> <span leaf="">sdk:拓展型功能,用来提供系统的外部调用,目前不太完善,可忽略。</span> </section></li> </ul> <h2 data-tool="mdnice编辑器" style="border-bottom-color: rgb(89, 89, 89);margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(89, 89, 89);border-bottom-color: rgb(89, 89, 89);line-height: 1.5em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">3.3 前后端可视化分析</span></span><span style="display: none;"></span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 1px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);line-height: 1.8em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 10px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: solid;border-right-style: none;border-top-width: 1px;border-bottom-width: 1px;border-left-width: 5px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgb(0, 0, 0);border-left-color: rgb(248, 57, 41);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">3.3.1 前端可视化分析</span></span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">前端代码全部集成在web文件夹下,因此可直接在web路径下直接启动查看。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">先安装依赖:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ibkkkoaqfco4yxzzqicvzogxxi0hzjbdiciamfnn9ueg4j58f1yacjjdv9f5nuqdff9xa6sw0psarfepjlgbvrgzmoonkibrkjds5 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">yarn instsall&nbsp;</span><span leaf=""><br></span></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">依赖安装完成,生成</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">node_modules</span></code><span leaf="">再启动:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ibkkkoaqfco4yxzzqicvzogxxi0hzjbdiciamfnn9ueg4j58f1yacjjdv9f5nuqdff9xa6sw0psarfepjlgbvrgzmoonkibrkjds5 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">yarn start</span><span leaf=""><br></span></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">访问</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">http://localhost:9222&nbsp;</span></code><span leaf="">即可进入登录界面。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">考虑到登录需要和后端交互,密码验证通过后,才能进入主界面。如需直接进入主界面预览,可修改</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">web/src/utils/request.ts</span></code><span leaf="">: 这里的逻辑是:本来响应结果为504,弹出error,这里直接改成成功响应。</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ibkkkoaqfco4yxzzqicvzogxxi0hzjbdiciamfnn9ueg4j58f1yacjjdv9f5nuqdff9xa6sw0psarfepjlgbvrgzmoonkibrkjds5 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">request.interceptors.response.use(async (response: Response, options) =&gt; {</span><span leaf=""><br></span><span leaf="">&nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">if</span></span><span leaf="">&nbsp;(response?.status ===&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">413</span></span><span leaf="">&nbsp;|| response?.status ===&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">504</span></span><span leaf="">) {</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 原代码</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// message.error(RetcodeMessage[response?.status as ResultCode]);</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 修改</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">return</span></span><span leaf="">&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">new</span></span><span leaf="">&nbsp;Response(JSON.stringify({</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; code:&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">0</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; message:&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'Success'</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; data: {}</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; }));</span><span leaf=""><br></span><span leaf="">&nbsp; }</span><span leaf=""><br></span></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 1px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);line-height: 1.8em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 10px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: solid;border-right-style: none;border-top-width: 1px;border-bottom-width: 1px;border-left-width: 5px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgb(0, 0, 0);border-left-color: rgb(248, 57, 41);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">3.3.2 mysql可视化分析</span></span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">下面再可视化查看其它组件信息,在</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">docker/.env</span></code><span leaf="">文件中,包含了各组件的密码。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">启动docker服务,首先查看mysql数据库信息。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">使用</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">DBeaver</span></code><span leaf="">进行连接,连接参数如下,默认用户名为</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">root</span></code><span leaf="">,密码为</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">infini_rag_flow</span></code><span leaf="">。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/d64190bd0827d8b3e10f8da624ffbc3b.png" class="rich_pages wxw-img" data-ratio="1.09009009009009" data-type="png" data-w="777" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100003038"></span> </figure> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">可以看到,该数据库中包含多张数据表,后续在解决实际问题时,会进一步分析。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/1bfaad0ebf15db211fa4266f9059fb98.png" class="rich_pages wxw-img" data-ratio="0.827426810477658" data-type="png" data-w="649" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100003036"></span> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 1px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);line-height: 1.8em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 10px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: solid;border-right-style: none;border-top-width: 1px;border-bottom-width: 1px;border-left-width: 5px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgb(0, 0, 0);border-left-color: rgb(248, 57, 41);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">3.3.3 Elasticsearch可视化分析</span></span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">Elasticsearch需要通过</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">Kibana</span></code><span leaf="">进行可视化分析。虽然</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">.env</span></code><span leaf="">文件中写了Kibana的初始用户名和密码,但实际服务中,并未启用Kibana。看到仓库中有人提出过该问题,具体可参考该pr:</span><span leaf="">https://github.com/infiniflow/ragflow/pull/548/files</span></p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 1px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);line-height: 1.8em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 10px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: solid;border-right-style: none;border-top-width: 1px;border-bottom-width: 1px;border-left-width: 5px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgb(0, 0, 0);border-left-color: rgb(248, 57, 41);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">3.3.4 MinIO可视化分析</span></span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">MinIO自带了可视化管理的控制台,访问</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">http://localhost:9001/</span></code><span leaf="">即可进入,默认用户名为</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">rag_flow</span></code><span leaf="">,默认密码为</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">infini_rag_flow</span></code><span leaf="">。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">进入可看见,里面的容器包含了原始上传的pdf文件和切块分页的图像数据。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/80a5426d4f5c7b4b7f08cb053449d343.png" class="rich_pages wxw-img" data-ratio="0.9144316730523627" data-type="png" data-w="783" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100003040"></span> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 1px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(34, 34, 34);line-height: 1.8em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 10px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: solid;border-right-style: none;border-top-width: 1px;border-bottom-width: 1px;border-left-width: 5px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgb(0, 0, 0);border-left-color: rgb(248, 57, 41);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">3.3.5 Redis可视化分析</span></span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">使用</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">Rdis insight</span></code><span leaf="">连接Redis数据库,默认地址为</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">127.0.0.1:6379</span></code><span leaf="">,默认用户名为</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">default</span></code><span leaf="">,默认密码为</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">infini_rag_flow</span></code><span leaf="">。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/ab60b192e5f7163e3dd5f8f5298d2858.png" class="rich_pages wxw-img" data-ratio="0.7435185185185185" data-type="png" data-w="1080" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100003037"></span> </figure> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">进入可看见,里面存储了一些缓存数据。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/6b54048b7a552367261adb327c3fe235.png" class="rich_pages wxw-img" data-ratio="0.6194444444444445" data-type="png" data-w="1080" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100003039"></span> </figure> <h1 data-tool="mdnice编辑器" style="border-bottom-color: rgb(89, 89, 89);margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(89, 89, 89);border-bottom-color: rgb(89, 89, 89);line-height: 1.5em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">4. 问题解决方法</span></span><span style="display: none;"></span></h1> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">分析完了,开始解决开头提到的一些具体问题。</span></p> <h2 data-tool="mdnice编辑器" style="border-bottom-color: rgb(89, 89, 89);margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(89, 89, 89);border-bottom-color: rgb(89, 89, 89);line-height: 1.5em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">4.1 关闭注册通道</span></span><span style="display: none;"></span></h2> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">关闭注册通道,可直接将前端界面上的注册元素注释掉。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/89bb7efe6f033dc2a250bd139058b88c.png" class="rich_pages wxw-img" data-ratio="0.8380165289256198" data-type="png" data-w="605" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100003042"></span> </figure> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">具体方法是修改</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">src\pages\login\index.tsx</span></code><span leaf="">文件,注释掉以下内容:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ibkkkoaqfco4yxzzqicvzogxxi0hzjbdiciamfnn9ueg4j58f1yacjjdv9f5nuqdff9xa6sw0psarfepjlgbvrgzmoonkibrkjds5 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">{ </span></code> <div> <code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; {title ===&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'login'</span></span><span leaf="">&nbsp;&amp;&amp; (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; </span></code> <div> <code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; {t(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'signInTip'</span></span><span leaf="">)}</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; <button&nbsp;></button&nbsp;></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">type</span></span><span leaf="">=</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"link"</span></span><span leaf="">&nbsp;onClick={changeTitle}&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; {t(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'signUp'</span></span><span leaf="">)}</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &lt;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">/Button&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; <!--/</span--></span><span leaf="">div&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; )}</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; {title ===&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'register'</span></span><span leaf="">&nbsp;&amp;&amp; (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; </span></span></code> <div> <code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; {t(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'signUpTip'</span></span><span leaf="">)}</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; <button&nbsp;></button&nbsp;></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">type</span></span><span leaf="">=</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"link"</span></span><span leaf="">&nbsp;onClick={changeTitle}&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; {t(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'login'</span></span><span leaf="">)}</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &lt;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">/Button&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; <!--/</span--></span><span leaf="">div&gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; )}</span><span leaf=""><br></span><span leaf="">&lt;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">/div&gt;}</span><span leaf=""><br></span></span></span></code> </div> </div> </div></pre> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">这样修改,用户直接通过浏览器访问</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">/register</span></code><span leaf="">也是无法注册的,因为注册功能并不是一个单独界面,而是在login中,post到后端进行处理。</span></p> <h2 data-tool="mdnice编辑器" style="border-bottom-color: rgb(89, 89, 89);margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(89, 89, 89);border-bottom-color: rgb(89, 89, 89);line-height: 1.5em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">4.2 后台添加用户</span></span><span style="display: none;"></span></h2> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">阻止用户自己注册之后,管理员还需要为用户进行注册。可直接采用修改数据库内容的方式进行实现。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">连接mysql数据库,用户信息存储在</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">user</span></code><span leaf="">表中。该表包含以下字段,核心字段是</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">email</span></code><span leaf="">和</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">password</span></code><span leaf="">。</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/28f3f3e83cd18c002f3ec54531b8b7ab.png" class="rich_pages wxw-img" data-ratio="0.8087201125175809" data-type="png" data-w="711" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100003045"></span> </figure> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">email比较容易理解,存储的就是登陆明文邮箱,但密码是哈希字符串,为了防止被人攻击泄露,不能存储明文密码,因此,要解决注册问题,首先需要理清楚密码的加密逻辑。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">通过仔细阅读源代码,我理清楚了注册阶段,密码的加密存储过程: 首先,前端获取到用户原始输入密码后,先进行Base64编码,防止特殊字符造成解析失败,编码后利用公钥进行RSA加密; 后端接收到加密密码后,利用私钥进行RSA解密,最后通过Hash处理,存储到数据库。</span></p> <blockquote style="margin-top: 20px;margin-bottom: 20px;margin-left: 0px;margin-right: 0px;padding-top: 10px;padding-bottom: 10px;padding-left: 20px;padding-right: 10px;border-top-style: solid;border-bottom-style: solid;border-left-style: solid;border-right-style: solid;border-top-width: 1px;border-bottom-width: 1px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgba(64, 184, 255, 0.4);border-bottom-color: rgba(64, 184, 255, 0.4);border-left-color: rgba(64, 184, 255, 0.4);border-right-color: rgba(64, 184, 255, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;background-attachment: scroll;background-clip: border-box;background-color: rgba(64, 184, 250, 0.1);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;display: block;overflow-x: auto;overflow-y: auto;"> <span style="display: block;color: rgba(64, 184, 250, 0.5);font-size: 28px;line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;"><span leaf="">❝</span></span> <p style="text-indent: 0em;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;color: rgb(59, 59, 59);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;font-weight: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;"><span leaf="">A[原始密码] --&gt; B[前端Base64编码] --&gt; C[RSA加密] --&gt; D[后端RSA解密] --&gt; E[hash存储]</span></p> </blockquote> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">为了让这个过程更容易理解,我写了个python代码,模拟了该过程,其中,私钥数据可以在文件中找到,路径为&nbsp;</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">conf/private.pem</span></code><span leaf="">:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ibkkkoaqfco4yxzzqicvzogxxi0hzjbdiciamfnn9ueg4j58f1yacjjdv9f5nuqdff9xa6sw0psarfepjlgbvrgzmoonkibrkjds5 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;base64</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">from</span></span><span leaf="">&nbsp;Cryptodome.PublicKey&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;RSA</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">from</span></span><span leaf="">&nbsp;Cryptodome.Cipher&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;PKCS1_v1_5</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">from</span></span><span leaf="">&nbsp;werkzeug.security&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;generate_password_hash, check_password_hash</span><span leaf=""><br></span><span leaf=""><br></span><span leaf=""><br></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">def</span></span><span leaf="">&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">rsa_decrypt</span></span><span style="line-height: 26px;"><span leaf="">(encrypted_password: str, private_key_path: str, passphrase: str)</span></span><span leaf="">&nbsp;-&gt; str:</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 从文件中读取私钥</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">with</span></span><span leaf="">&nbsp;open(private_key_path,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"r"</span></span><span leaf="">)&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">as</span></span><span leaf="">&nbsp;key_file:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; private_key = key_file.read()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 导入私钥</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; rsa_key = RSA.importKey(private_key, passphrase=passphrase)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; cipher = PKCS1_v1_5.new(rsa_key)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># Base64 解码加密数据</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; encrypted_data = base64.b64decode(encrypted_password)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 解密数据</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; decrypted_data = cipher.decrypt(encrypted_data,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"Fail to decrypt password!"</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># Base64 解码解密后的数据</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">return</span></span><span leaf="">&nbsp;base64.b64decode(decrypted_data).decode(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'utf-8'</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf=""><br></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">def</span></span><span leaf="">&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">rsa_psw</span></span><span style="line-height: 26px;"><span leaf="">(password: str)</span></span><span leaf="">&nbsp;-&gt; str:</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 公钥</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; pub_key =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"""-----BEGIN PUBLIC KEY-----</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArq9XTUSeYr2+N1h3Afl/z8Dse/2yD0ZGrKwx+EEEcdsBLca9Ynmx3nIB5obmLlSfmskLpBo0UACBmB5rEjBp2Q2f3AG3Hjd4B+gNCG6BDaawuDlgANIhGnaTLrIqWrrcm4EMzJOnAOI1fgzJRsOOUEfaS318Eq9OVO3apEyCCt0lOQK6PuksduOjVxtltDav+guVAA068NrPYmRNabVKRNLJpL8w4D44sfth5RvZ3q9t+6RTArpEtc5sh5ChzvqPOzKGMXW83C95TxmXqpbK6olN4RevSfVjEAgCydH6HN6OhtOQEcnrU97r9H0iZOWwbw3pVrZiUkuRD1R56Wzs2wIDAQAB</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; -----END PUBLIC KEY-----"""</span></span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 导入公钥</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; rsa_key = RSA.import_key(pub_key)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; cipher = PKCS1_v1_5.new(rsa_key)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 对密码进行 Base64 编码</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; password_base64 = base64.b64encode(password.encode(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'utf-8'</span></span><span leaf="">))</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 使用 RSA 公钥加密</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; encrypted_data = cipher.encrypt(password_base64)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 对加密结果进行 Base64 编码并返回</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">return</span></span><span leaf="">&nbsp;base64.b64encode(encrypted_data).decode(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'utf-8'</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">if</span></span><span leaf="">&nbsp;__name__ ==&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"__main__"</span></span><span leaf="">:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 注册流程</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 1. 获取到用户输入的密码</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; password =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"test"</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 2. Base64编码</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; base64_password = base64.b64encode(password.encode()).decode()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; print(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"Base64:"</span></span><span leaf="">, base64_password)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 3. RSA加密</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; encrypted_password = rsa_psw(base64_password)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; print(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"RSA:"</span></span><span leaf="">, encrypted_password)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 4. 后端解密(使用private.pem)</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; private_key_path =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"private.pem"</span></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 私钥文件路径</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; passphrase =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"Welcome"</span></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 私钥的密码</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; decrypted_password = rsa_decrypt(encrypted_password, private_key_path, passphrase)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; print(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"Decrypted:"</span></span><span leaf="">, decrypted_password)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 5. 生成最终的hash</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; hash_password = generate_password_hash(decrypted_password)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; print(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"hash_password:"</span></span><span leaf="">, hash_password)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 登录验证匹配过程</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; is_match = check_password_hash(hash_password, decrypted_password)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; print(is_match)</span><span leaf=""><br></span></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">理解完这一过程之后,就可以通过python脚本插入一条用户数据:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ibkkkoaqfco4yxzzqicvzogxxi0hzjbdiciamfnn9ueg4j58f1yacjjdv9f5nuqdff9xa6sw0psarfepjlgbvrgzmoonkibrkjds5 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;mysql.connector</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;uuid</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;base64</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">from</span></span><span leaf="">&nbsp;datetime&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;datetime</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">from</span></span><span leaf="">&nbsp;Cryptodome.PublicKey&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;RSA</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">from</span></span><span leaf="">&nbsp;Cryptodome.Cipher&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;PKCS1_v1_5</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">from</span></span><span leaf="">&nbsp;werkzeug.security&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;generate_password_hash</span><span leaf=""><br></span><span leaf=""><br></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 数据库连接配置</span></span><span leaf=""><br></span><span leaf="">db_config = {</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"host"</span></span><span leaf="">:&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"localhost"</span></span><span leaf="">, &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 数据库地址</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"port"</span></span><span leaf="">:&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">5455</span></span><span leaf="">, &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 数据库端口</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"user"</span></span><span leaf="">:&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"root"</span></span><span leaf="">, &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 数据库用户名</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"password"</span></span><span leaf="">:&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"infini_rag_flow"</span></span><span leaf="">, &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 数据库密码</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"database"</span></span><span leaf="">:&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"rag_flow"</span></span><span leaf="">, &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 数据库名称</span></span><span leaf=""><br></span><span leaf="">}</span><span leaf=""><br></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 生成随机的 UUID 作为 id</span></span><span leaf=""><br></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">def</span></span><span leaf="">&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">generate_uuid</span></span><span style="line-height: 26px;"><span leaf="">()</span></span><span leaf="">:</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">return</span></span><span leaf="">&nbsp;str(uuid.uuid4()).replace(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"-"</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">""</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf=""><br></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">def</span></span><span leaf="">&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">rsa_decrypt</span></span><span style="line-height: 26px;"><span leaf="">(encrypted_password: str, private_key_path: str, passphrase: str)</span></span><span leaf="">&nbsp;-&gt; str:</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 从文件中读取私钥</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">with</span></span><span leaf="">&nbsp;open(private_key_path,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"r"</span></span><span leaf="">)&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">as</span></span><span leaf="">&nbsp;key_file:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; private_key = key_file.read()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 导入私钥</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; rsa_key = RSA.importKey(private_key, passphrase=passphrase)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; cipher = PKCS1_v1_5.new(rsa_key)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># Base64 解码加密数据</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; encrypted_data = base64.b64decode(encrypted_password)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 解密数据</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; decrypted_data = cipher.decrypt(encrypted_data,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"Fail to decrypt password!"</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># Base64 解码解密后的数据</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">return</span></span><span leaf="">&nbsp;base64.b64decode(decrypted_data).decode(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'utf-8'</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf=""><br></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">def</span></span><span leaf="">&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">encrypt_password</span></span><span style="line-height: 26px;"><span leaf="">(raw_password: str)</span></span><span leaf="">&nbsp;-&gt; str:</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 1. Base64编码</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; base64_password = base64.b64encode(raw_password.encode()).decode()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 2. RSA加密</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; encrypted_password = rsa_psw(base64_password)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 3. 后端解密(使用private.pem)</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; private_key_path =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"private.pem"</span></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 私钥文件路径</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; passphrase =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"Welcome"</span></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 私钥的密码</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; decrypted_password = rsa_decrypt(encrypted_password, private_key_path, passphrase)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 4. 生成最终的hash</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">return</span></span><span leaf="">&nbsp;generate_password_hash(decrypted_password)</span><span leaf=""><br></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># RSA 加密密码</span></span><span leaf=""><br></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">def</span></span><span leaf="">&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">rsa_psw</span></span><span style="line-height: 26px;"><span leaf="">(password: str)</span></span><span leaf="">&nbsp;-&gt; str:</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; pub_key =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"""-----BEGIN PUBLIC KEY-----</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArq9XTUSeYr2+N1h3Afl/z8Dse/2yD0ZGrKwx+EEEcdsBLca9Ynmx3nIB5obmLlSfmskLpBo0UACBmB5rEjBp2Q2f3AG3Hjd4B+gNCG6BDaawuDlgANIhGnaTLrIqWrrcm4EMzJOnAOI1fgzJRsOOUEfaS318Eq9OVO3apEyCCt0lOQK6PuksduOjVxtltDav+guVAA068NrPYmRNabVKRNLJpL8w4D44sfth5RvZ3q9t+6RTArpEtc5sh5ChzvqPOzKGMXW83C95TxmXqpbK6olN4RevSfVjEAgCydH6HN6OhtOQEcnrU97r9H0iZOWwbw3pVrZiUkuRD1R56Wzs2wIDAQAB</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; -----END PUBLIC KEY-----"""</span></span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; rsa_key = RSA.import_key(pub_key)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; cipher = PKCS1_v1_5.new(rsa_key)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; encrypted_data = cipher.encrypt(base64.b64encode(password.encode()))</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">return</span></span><span leaf="">&nbsp;base64.b64encode(encrypted_data).decode()</span><span leaf=""><br></span><span leaf=""><br></span><span leaf=""><br></span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">if</span></span><span leaf="">&nbsp;__name__ ==&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'__main__'</span></span><span leaf="">:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 插入数据的 SQL 语句</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; insert_query =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"""</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; INSERT INTO user (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; id, create_time, create_date, update_time, update_date, access_token,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; nickname, password, email, avatar, language, color_schema, timezone,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; last_login_time, is_authenticated, is_active, is_anonymous, login_channel,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; status, is_superuser</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; ) VALUES (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; %s, %s, %s, %s, %s, %s,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; %s, %s, %s, %s, %s, %s, %s,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; %s, %s, %s, %s, %s,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; %s, %s</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; )</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; """</span></span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 对密码进行加密</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; raw_password =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"123"</span></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 原始密码</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; hash_encrypted = encrypt_password(raw_password)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 学号</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; student_id =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"123456789"</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; student_email = student_id +&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"@xidian.cn"</span></span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 数据值</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; data = (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; generate_uuid(), &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># id</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">1741361741738</span></span><span leaf="">, &nbsp; &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># create_time</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; datetime.strptime(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"2025-03-07 23:35:41"</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"%Y-%m-%d %H:%M:%S"</span></span><span leaf="">), &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># create_date</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">1741416354403</span></span><span leaf="">, &nbsp; &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># update_time</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; datetime.strptime(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"2025-03-08 14:45:54"</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"%Y-%m-%d %H:%M:%S"</span></span><span leaf="">), &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># update_date</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #56b6c2;line-height: 26px;"><span leaf="">None</span></span><span leaf="">, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># access_token (默认为空)</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; student_id, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># nickname</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; hash_encrypted, &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># password</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; student_email, &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># email</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #56b6c2;line-height: 26px;"><span leaf="">None</span></span><span leaf="">, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># avatar (默认为空)</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"Chinese"</span></span><span leaf="">, &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># language</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"Bright"</span></span><span leaf="">, &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># color_schema</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"UTC+8 Asia/Shanghai"</span></span><span leaf="">, &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># timezone</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; datetime.strptime(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"2025-03-07 23:35:41"</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"%Y-%m-%d %H:%M:%S"</span></span><span leaf="">), &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># last_login_time</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">1</span></span><span leaf="">, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># is_authenticated</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">1</span></span><span leaf="">, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># is_active</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">0</span></span><span leaf="">, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># is_anonymous</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"password"</span></span><span leaf="">, &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># login_channel</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">1</span></span><span leaf="">, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># status</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">0</span></span><span leaf="">, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># is_superuser</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; )</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 连接数据库并插入数据</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">try</span></span><span leaf="">:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 建立数据库连接</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; conn = mysql.connector.connect(**db_config)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; cursor = conn.cursor()</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 执行插入操作</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; cursor.execute(insert_query, data)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; conn.commit() &nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 提交事务</span></span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; print(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"数据插入成功!"</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">except</span></span><span leaf="">&nbsp;mysql.connector.Error&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">as</span></span><span leaf="">&nbsp;err:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; print(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">f"数据库错误:&nbsp;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">{err}</span></span><span leaf="">"</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">finally</span></span><span leaf="">:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 关闭连接</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">if</span></span><span leaf="">&nbsp;conn.is_connected():</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.close()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conn.close()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"数据库连接已关闭。"</span></span><span leaf="">)</span><span leaf=""><br></span></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">注:这段代码实际上,可以再进行优化,获取到密码后,未涉及前后端传输,可以直接将base64编码的密码进行哈希操作,而省略RSA步骤。</span></p> <h2 data-tool="mdnice编辑器" style="border-bottom-color: rgb(89, 89, 89);margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(89, 89, 89);border-bottom-color: rgb(89, 89, 89);line-height: 1.5em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">4.3 设置用户模型</span></span><span style="display: none;"></span></h2> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">添加完用户,下面要设置用户模型配置。 模型配置涉及到</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">tenant</span></code><span leaf="">和</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">tenant_llm</span></code><span leaf="">两张数据表。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">tenant记录了每个用户的模型配置,对应前端界面如下:</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/fc0472bc3cfc9002e94ff4f48ba9ce43.png" class="rich_pages wxw-img" data-ratio="1.2170542635658914" data-type="png" data-w="516" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100003044"></span> </figure> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">tenant_llm记录了每个模型的基本信息,对应前端界面如下:</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/475ede49810e274b0cca44f53aa55765.png" class="rich_pages wxw-img" data-ratio="1.0154738878143132" data-type="png" data-w="517" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 8px;border-top-right-radius: 8px;border-bottom-right-radius: 8px;border-bottom-left-radius: 8px;object-fit: fill;box-shadow: rgb(153, 153, 153) 2px 4px 8px 0px;" data-imgfileid="100003043"></span> </figure> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">具体插入操作,后续将和用户团队表格一块进行更新。</span></p> <h2 data-tool="mdnice编辑器" style="border-bottom-color: rgb(89, 89, 89);margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(89, 89, 89);border-bottom-color: rgb(89, 89, 89);line-height: 1.5em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">4.4 设置用户团队</span></span><span style="display: none;"></span></h2> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">用户团队涉及的表格名为</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">user_tenant</span></code><span leaf="">。 设置用户团队需要插入两条记录,首先,用户自己注册时,单独有一个自己的团队,这样方便用户可以后续再组小团体。其次,需要将新用户的团队记录插入到老用户底下。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">结合4.2、4.3、4.4的内容,一次性批量插入用户的脚本如下:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ibkkkoaqfco4yxzzqicvzogxxi0hzjbdiciamfnn9ueg4j58f1yacjjdv9f5nuqdff9xa6sw0psarfepjlgbvrgzmoonkibrkjds5 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;mysql.connector</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;uuid</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;base64</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;json</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">from</span></span><span leaf="">&nbsp;datetime&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;datetime</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">from</span></span><span leaf="">&nbsp;Cryptodome.PublicKey&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;RSA</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">from</span></span><span leaf="">&nbsp;Cryptodome.Cipher&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;PKCS1_v1_5</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">from</span></span><span leaf="">&nbsp;werkzeug.security&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">import</span></span><span leaf="">&nbsp;generate_password_hash</span><span leaf=""><br></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 数据库连接配置</span></span><span leaf=""><br></span><span leaf="">db_config = {</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"host"</span></span><span leaf="">:&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"localhost"</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"port"</span></span><span leaf="">:&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">5455</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"user"</span></span><span leaf="">:&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"root"</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"password"</span></span><span leaf="">:&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"infini_rag_flow"</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"database"</span></span><span leaf="">:&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"rag_flow"</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">}</span><span leaf=""><br></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 生成随机的 UUID 作为 id</span></span><span leaf=""><br></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">def</span></span><span leaf="">&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">generate_uuid</span></span><span style="line-height: 26px;"><span leaf="">()</span></span><span leaf="">:</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">return</span></span><span leaf="">&nbsp;str(uuid.uuid4()).replace(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"-"</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">""</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># RSA 加密密码</span></span><span leaf=""><br></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">def</span></span><span leaf="">&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">rsa_psw</span></span><span style="line-height: 26px;"><span leaf="">(password: str)</span></span><span leaf="">&nbsp;-&gt; str:</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; pub_key =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"""-----BEGIN PUBLIC KEY-----</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArq9XTUSeYr2+N1h3Afl/z8Dse/2yD0ZGrKwx+EEEcdsBLca9Ynmx3nIB5obmLlSfmskLpBo0UACBmB5rEjBp2Q2f3AG3Hjd4B+gNCG6BDaawuDlgANIhGnaTLrIqWrrcm4EMzJOnAOI1fgzJRsOOUEfaS318Eq9OVO3apEyCCt0lOQK6PuksduOjVxtltDav+guVAA068NrPYmRNabVKRNLJpL8w4D44sfth5RvZ3q9t+6RTArpEtc5sh5ChzvqPOzKGMXW83C95TxmXqpbK6olN4RevSfVjEAgCydH6HN6OhtOQEcnrU97r9H0iZOWwbw3pVrZiUkuRD1R56Wzs2wIDAQAB</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; -----END PUBLIC KEY-----"""</span></span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; rsa_key = RSA.import_key(pub_key)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; cipher = PKCS1_v1_5.new(rsa_key)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; encrypted_data = cipher.encrypt(base64.b64encode(password.encode()))</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">return</span></span><span leaf="">&nbsp;base64.b64encode(encrypted_data).decode()</span><span leaf=""><br></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 加密密码</span></span><span leaf=""><br></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">def</span></span><span leaf="">&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">encrypt_password</span></span><span style="line-height: 26px;"><span leaf="">(raw_password: str)</span></span><span leaf="">&nbsp;-&gt; str:</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; base64_password = base64.b64encode(raw_password.encode()).decode()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; encrypted_password = rsa_psw(base64_password)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">return</span></span><span leaf="">&nbsp;generate_password_hash(base64_password)</span><span leaf=""><br></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 处理批量注册</span></span><span leaf=""><br></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">def</span></span><span leaf="">&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">batch_register_students</span></span><span style="line-height: 26px;"><span leaf="">()</span></span><span leaf="">:</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 从 JSON 文件加载学生数据</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">with</span></span><span leaf="">&nbsp;open(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"add.json"</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"r"</span></span><span leaf="">, encoding=</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"utf-8"</span></span><span leaf="">)&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">as</span></span><span leaf="">&nbsp;json_file:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; student_groups = json.load(json_file)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">try</span></span><span leaf="">:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 建立数据库连接</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; conn = mysql.connector.connect(**db_config)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; cursor = conn.cursor()</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">for</span></span><span leaf="">&nbsp;group&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">in</span></span><span leaf="">&nbsp;student_groups:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tenant_id = group[</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"tenant_id"</span></span><span leaf="">]</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; student_ids = group[</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"student_id"</span></span><span leaf="">]</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">for</span></span><span leaf="">&nbsp;student_id&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">in</span></span><span leaf="">&nbsp;student_ids:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 生成 ID 和时间戳</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; user_id = generate_uuid()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; create_time =&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">1741361741738</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; create_date = datetime.strptime(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"2025-03-07 23:35:41"</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"%Y-%m-%d %H:%M:%S"</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; update_time =&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">1741416354403</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; update_date = datetime.strptime(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"2025-03-08 14:45:54"</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"%Y-%m-%d %H:%M:%S"</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 用户信息</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; student_email = student_id +&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"@xidian.cn"</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; raw_password = student_id</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; hash_encrypted = encrypt_password(raw_password)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 插入 user 表数据</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; user_insert_query =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"""</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; INSERT INTO user (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; id, create_time, create_date, update_time, update_date, access_token,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nickname, password, email, avatar, language, color_schema, timezone,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; last_login_time, is_authenticated, is_active, is_anonymous, login_channel,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; status, is_superuser</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ) VALUES (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %s, %s, %s, %s, %s, %s,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %s, %s, %s, %s, %s, %s, %s,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %s, %s, %s, %s, %s,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %s, %s</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; """</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; user_data = (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; user_id, create_time, create_date, update_time, update_date,&nbsp;</span><span style="color: #56b6c2;line-height: 26px;"><span leaf="">None</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; student_id, hash_encrypted, student_email,&nbsp;</span><span style="color: #56b6c2;line-height: 26px;"><span leaf="">None</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"Chinese"</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"Bright"</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"UTC+8 Asia/Shanghai"</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; create_date,&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">1</span></span><span leaf="">,&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">1</span></span><span leaf="">,&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">0</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"password"</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">1</span></span><span leaf="">,&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">0</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.execute(user_insert_query, user_data)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 插入 tenant 表数据</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tenant_insert_query =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"""</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; INSERT INTO tenant (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; id, create_time, create_date, update_time, update_date, name,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; public_key, llm_id, embd_id, asr_id, img2txt_id, rerank_id, tts_id,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; parser_ids, credit, status</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ) VALUES (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %s, %s, %s, %s, %s, %s,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %s, %s, %s, %s, %s, %s, %s,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %s, %s, %s</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; """</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tenant_data = (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; user_id, create_time, create_date, update_time, update_date, student_id +&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"'s Kingdom"</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #56b6c2;line-height: 26px;"><span leaf="">None</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"deepseek-r1:1.5b@Ollama"</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"BAAI/bge-large-zh-v1.5@BAAI"</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">""</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">""</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">""</span></span><span leaf="">,&nbsp;</span><span style="color: #56b6c2;line-height: 26px;"><span leaf="">None</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"naive:General,qa:Q&amp;A,resume:Resume,manual:Manual,table:Table,paper:Paper,book:Book,laws:Laws,presentation:Presentation,picture:Picture,one:One,audio:Audio,email:Email,tag:Tag"</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">512</span></span><span leaf="">,&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">1</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.execute(tenant_insert_query, tenant_data)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 插入 user_tenant 表的第一条记录</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; user_tenant_insert_query =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"""</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; INSERT INTO user_tenant (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; id, create_time, create_date, update_time, update_date, user_id,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tenant_id, role, invited_by, status</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ) VALUES (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %s, %s, %s, %s, %s, %s,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %s, %s, %s, %s</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; """</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; user_tenant_data_owner = (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; generate_uuid(), create_time, create_date, update_time, update_date, user_id,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; user_id,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"owner"</span></span><span leaf="">, user_id,&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">1</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.execute(user_tenant_insert_query, user_tenant_data_owner)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 插入 user_tenant 表的第二条记录</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; user_tenant_data_normal = (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; generate_uuid(), create_time, create_date, update_time, update_date, user_id,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tenant_id,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"normal"</span></span><span leaf="">, tenant_id,&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">1</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.execute(user_tenant_insert_query, user_tenant_data_normal)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 插入 tenant_llm 表数据</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tenant_llm_insert_query =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"""</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; INSERT INTO tenant_llm (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; create_time, create_date, update_time, update_date, tenant_id,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; llm_factory, model_type, llm_name, api_key, api_base, max_tokens, used_tokens</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ) VALUES (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %s, %s, %s, %s, %s,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; %s, %s, %s, %s, %s, %s, %s</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; """</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tenant_llm_data = (</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; create_time, create_date, update_time, update_date, user_id,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"Ollama"</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"chat"</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"deepseek-r1:1.5b"</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"xxxxxxxxxxxxxxx"</span></span><span leaf="">,&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"http://10.195.140.47:11434"</span></span><span leaf="">,&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">88888888</span></span><span leaf="">,&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">0</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; )</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.execute(tenant_llm_insert_query, tenant_llm_data)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf=""># 提交事务</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; conn.commit()</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; print(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"批量用户数据添加成功!"</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">except</span></span><span leaf="">&nbsp;mysql.connector.Error&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">as</span></span><span leaf="">&nbsp;err:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; print(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">f"数据库错误:&nbsp;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">{err}</span></span><span leaf="">"</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">finally</span></span><span leaf="">:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">if</span></span><span leaf="">&nbsp;conn.is_connected():</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; cursor.close()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; conn.close()</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"数据库连接已关闭。"</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf=""><br></span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">if</span></span><span leaf="">&nbsp;__name__ ==&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'__main__'</span></span><span leaf="">:</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; batch_register_students()</span><span leaf=""><br></span></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">这里我将需要插入的用户写在json文件中,格式示例如下:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ibkkkoaqfco4yxzzqicvzogxxi0hzjbdiciamfnn9ueg4j58f1yacjjdv9f5nuqdff9xa6sw0psarfepjlgbvrgzmoonkibrkjds5 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">[</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; {</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">"student_id"</span></span><span leaf="">: [</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"123456789"</span></span><span leaf="">,</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"1234567810"</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; ],</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">"tenant_id"</span></span><span leaf="">:&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"d3de1596fb6911efa0f40242ac120006"</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; }</span><span leaf=""><br></span><span leaf="">]</span><span leaf=""><br></span></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">student_id</span></code><span leaf="">为需要插入的用户学号,密码默认和id一致,</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">tenant_id</span></code><span leaf="">对应的是团队队长的</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">id</span></code><span leaf="">,即需要共享数据库用户的id。代码中,模型名用的是</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">deepseek-r1:1.5b</span></code><span leaf="">型号的测试模型,如需配置其它型号,对应修改名称即可。</span></p> <h2 data-tool="mdnice编辑器" style="border-bottom-color: rgb(89, 89, 89);margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(89, 89, 89);border-bottom-color: rgb(89, 89, 89);line-height: 1.5em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">4.5 其它外观修改</span></span><span style="display: none;"></span></h2> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">主要问题已全部解决。最后,再进行一些外观上的调整。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">1.移除Agent菜单</span><span leaf=""><br></span><span leaf="">Agent目前比较复杂,也不实用。可以考虑移除。 具体修改方式是修改</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">web\src\layouts\components\header\index.tsx</span></code><span leaf="">,注释以下内容:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ibkkkoaqfco4yxzzqicvzogxxi0hzjbdiciamfnn9ueg4j58f1yacjjdv9f5nuqdff9xa6sw0psarfepjlgbvrgzmoonkibrkjds5 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">{ path:&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'/flow'</span></span><span leaf="">, name: t(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'flow'</span></span><span leaf="">), icon: GraphIcon },</span><span leaf=""><br></span></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">2.移除登陆页描述</span><span leaf=""><br></span><span leaf="">登录页描述有点花哨,进行移除。 修改</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">web\src\pages\login\right-panel.tsx</span></code><span leaf="">,注释以下内容:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ibkkkoaqfco4yxzzqicvzogxxi0hzjbdiciamfnn9ueg4j58f1yacjjdv9f5nuqdff9xa6sw0psarfepjlgbvrgzmoonkibrkjds5 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">&nbsp; <text classname="{classNames(styles.pink," styles.logindescription)}></text></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; {t(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'description'</span></span><span leaf="">)}</span><span leaf=""><br></span><span leaf=""></span><span leaf=""><br></span><span leaf=""> <flex align="</span"> <span style="color: #98c379;line-height: 26px;"><span leaf="">"center"</span></span> <span leaf="">&nbsp;gap={</span> <span style="color: #d19a66;line-height: 26px;"><span leaf="">16</span></span> <span leaf="">}&gt;</span> <span leaf=""><br></span> <span leaf="">&nbsp; &nbsp; <avatars></avatars></span> <span leaf=""><br></span> <span leaf="">&nbsp; &nbsp; <flex vertical></flex></span> <span leaf=""><br></span> <span leaf="">&nbsp; &nbsp; <space></space></span> <span leaf=""><br></span> <span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; <rate disabled defaultvalue="{</span"> <span style="color: #d19a66;line-height: 26px;"><span leaf="">5</span></span> <span leaf="">} /&gt;</span> <span leaf=""><br></span> <span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; <span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; className={classNames(styles.white, styles.loginRateNumber)}</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &gt;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #d19a66;line-height: 26px;"><span leaf="">5.0</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; </span></span> <span leaf=""><br></span> <span leaf="">&nbsp; &nbsp; </span> <span leaf=""><br></span> <span leaf="">&nbsp; &nbsp; <span classname="{classNames(styles.pink," styles.loginratereviews)}></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; {t(</span><span style="color: #98c379;line-height: 26px;"><span leaf="">'review'</span></span><span leaf="">)}</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; </span></span> <span leaf=""><br></span> <span leaf="">&nbsp; &nbsp; </span> </rate></span> </flex></span><span leaf=""><br></span><span leaf=""> }</span><span leaf=""><br></span></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">3.修改用户默认头像</span><span leaf=""><br></span><span leaf="">用户默认头像文件位置在</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">web\src\layouts\components\user\index.tsx</span></code><span leaf="">,可将</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png</span></code><span leaf="">修改为其它图像超链接,例如:</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">https://picx.zhimg.com/v2-aaf12b68b54b8812e6b449e7368d30cf_l.jpg</span></code><span leaf="">。</span></p> <h1 data-tool="mdnice编辑器" style="border-bottom-color: rgb(89, 89, 89);margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(89, 89, 89);border-bottom-color: rgb(89, 89, 89);line-height: 1.5em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">5. 前端修改文件上传</span></span><span style="display: none;"></span></h1> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">对于前端修改的文件,在docker里修改也不会生效。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">观察</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">docker/nginx/ragflow.conf</span></code><span leaf="">文件,不难发现,网页默认的访问的root路径为</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">&nbsp;/ragflow/web/dist</span></code><span leaf="">。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">因此,需要让前端修改内容生效,需要先将web文件进行打包。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">进入到web路径下,执行</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ibkkkoaqfco4yxzzqicvzogxxi0hzjbdiciamfnn9ueg4j58f1yacjjdv9f5nuqdff9xa6sw0psarfepjlgbvrgzmoonkibrkjds5 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">npm run build</span><span leaf=""><br></span></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">执行完之后,会在同级目录下生成</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">dist</span></code><span leaf="">文件。</span></p> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">进入到容器,删除容器中已有的</span><code style="color: rgb(53, 148, 247);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">/ragflow/web/dist</span></code><span leaf="">文件</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ibkkkoaqfco4yxzzqicvzogxxi0hzjbdiciamfnn9ueg4j58f1yacjjdv9f5nuqdff9xa6sw0psarfepjlgbvrgzmoonkibrkjds5 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">docker exec -it ragflow-server /bin/sh</span><span leaf=""><br></span><span leaf="">rm -rf /ragflow/web/dist</span><span leaf=""><br></span></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">将本地新生成的打包文件上传到容器:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg ibkkkoaqfco4yxzzqicvzogxxi0hzjbdiciamfnn9ueg4j58f1yacjjdv9f5nuqdff9xa6sw0psarfepjlgbvrgzmoonkibrkjds5 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">docker cp dist ragflow-server:/ragflow/web/</span><span leaf=""><br></span></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">重启容器,即可看到修改效果。</span></p> <h1 data-tool="mdnice编辑器" style="border-bottom-color: rgb(89, 89, 89);margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: flex;flex-direction: unset;float: unset;height: auto;justify-content: unset;line-height: 1.5em;overflow-x: unset;overflow-y: unset;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;text-align: left;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span style="display: none;"></span><span style="font-size: 22px;color: rgb(89, 89, 89);border-bottom-color: rgb(89, 89, 89);line-height: 1.5em;letter-spacing: 0em;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;align-items: unset;background-attachment: scroll;background-clip: border-box;background-color: unset;background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;border-top-style: none;border-bottom-style: solid;border-left-style: none;border-right-style: none;border-top-width: 1px;border-bottom-width: 2px;border-left-width: 1px;border-right-width: 1px;border-top-color: rgb(0, 0, 0);border-left-color: rgb(0, 0, 0);border-right-color: rgb(0, 0, 0);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-left-radius: 0px;border-bottom-right-radius: 0px;box-shadow: none;display: block;font-weight: bold;flex-direction: unset;float: unset;height: auto;justify-content: unset;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;overflow-x: unset;overflow-y: unset;text-align: left;text-indent: 0em;text-shadow: none;transform: none;width: auto;-webkit-box-reflect: unset;"><span leaf="">总结</span></span><span style="display: none;"></span></h1> <p data-tool="mdnice编辑器" style="color: rgb(43, 43, 43);font-size: 14px;line-height: 1.8em;letter-spacing: 0.02em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">作为高度团队协作的产品,ragflow用到的技术挺多。在此之前,我没接触过react和typescript,起初看起来有些费力。不过技术是相通的,慢慢看就能逐渐理解。这个系统代码规范性做的很好,即使拿来学习,也是一份不错的材料。</span></p> </section> <section> <span leaf=""><br></span> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>

软件离线授权码设计思路

作者:微信小助手

<p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 0px;color: rgb(10, 10, 10);font-family: ui-sans-serif, system-ui, sans-serif, " apple color emoji, segoe ui symbol, noto emoji;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 0px;line-height: 0; data-pm-slice="0 0 []"><span leaf="">&nbsp;</span></p> <section style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(10, 10, 10);font-size: 14px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;> <h1 data-heading="true" style="box-sizing: border-box;border-width: 0px 0px 2px;border-style: solid;border-bottom-color: rgb(15, 76, 129);font-size: 16.8px;font-weight: bold;margin: 0px auto 1em;text-align: center;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;display: table;padding: 0px 1em;color: rgb(63, 63, 63);><span leaf="">离线授权码设计</span></h1> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">对于自己的软件产品,希望别人付费、或者在我们授权的情况下才允许使用。那么我们应该如何去这个授权码 / 许可证的机制呢?</span></p> <h2 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 16.8px;font-weight: bold;margin: 4em auto 2em;text-align: center;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;display: table;padding: 0px 0.2em;color: rgb(255, 255, 255);background: rgb(15, 76, 129);><span leaf="">前言</span></h2> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">离线授权的方案无非就是两种,一种是软件层面的授权,一种是硬件层面的授权。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><strong style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-weight: bold;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: inherit;color: rgb(15, 76, 129);><span leaf="">软件层面</span></strong><span leaf="">:我们向用户提供一串特定的字符串,用户在软件中输入我们提供的字符串,在使用端校验用户输入的授权码,即可完成软件的授权操作。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><strong style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-weight: bold;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: inherit;color: rgb(15, 76, 129);><span leaf="">硬件层面</span></strong><span leaf="">:我们向用户提供一个 USB Key(加密狗),用户在运行软件时我们可以通过硬件加密狗来判断授权信息,这种加密狗在网上 几块钱到十几块钱就能买一个,有的加密狗还内置独立时钟,可以杜绝用户进行时钟回拨等。这种加密狗可以用在对授权安全级别更高的场景中,但需要承受额外的成本:用户的使用成本,授权分发成本(加密狗+快递费+快递时间)。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">软件层面的加密方案使用起来更加灵活,硬件层面加密狗安全级别更高,本篇文章主要是探讨软件层面的授权方式。</span></p> <h3 data-heading="true" style="box-sizing: border-box;border-width: 0px 0px 0px 3px;border-style: solid;border-left-color: rgb(15, 76, 129);font-size: 15.4px;font-weight: bold;margin: 2em 8px 0.75em 0px;text-align: left;line-height: 1.2;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;padding-left: 8px;color: rgb(63, 63, 63);><span leaf="">授权码要点</span></h3> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">那么设计一个相对安全的离线授权码,需要满足那些哪些特征呢?</span></p> <ul style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: circle;margin: 0px;padding: 0px 0px 0px 1em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;color: rgb(63, 63, 63); class="list-paddingleft-1"> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• 绑定性:每个授权码对应一台设备的授权,客户无法通过一个授权码激活多台设备。</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• 安全性:授权码应难以被伪造或篡改</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• 可验证:授权码应能被系统快速验证其合法性</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• 可复现:当客户授权码遗失时,我们可以根据客户的机器码重新生成授权码,避免用户无法使用软件的情况。</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• 时效性(可选):授权码可包含授权有效期,限定授权使用时长。</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• 可扩展(可选):可根据自己需求来灵活扩展授权码内容,以方便携带更多信息。</span> </section></li> </ul> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">你可以以任何形式生成一个满足上方条件的授权码,无需纠结生成的思路是否与我的思路一致</span></p> <h3 data-heading="true" style="box-sizing: border-box;border-width: 0px 0px 0px 3px;border-style: solid;border-left-color: rgb(15, 76, 129);font-size: 15.4px;font-weight: bold;margin: 2em 8px 0.75em 0px;text-align: left;line-height: 1.2;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;padding-left: 8px;color: rgb(63, 63, 63);><span leaf="">唯一标识</span></h3> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">在离线授权场景中,我们需要确定授权设备的唯一标识,这个标识需要具有不可更改性质,在正常情况下该唯一标识都不会发生变化(例如重启软件、重启系统不会发生变化,但重装系统、更换硬件等行为会发生变化是可接受的)。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">在这种场景中,我们唯一标识一般采用 CPUID、主板 BIOS UUID、网卡 MAC 地址、或自定义算法来生成唯一ID,提醒一下 如果产品是服务器应用,不应使用 硬盘序列号作为唯一标识的组成部分,因为服务器硬盘都有明确的生命周期会定期更换。当更换后就会造成授权失效的情况。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">这个唯一标识没有明确的授权规定,大家可以根据自己的需求来选择,也可以通过现成的开源库来获取。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">例如我开发的主语言是 Golang,我一般会使用 github.com/denisbrodbeck/machineid 这个库来获取硬件ID,并且可以在各个系统下运转良好。</span></p> <h2 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 16.8px;font-weight: bold;margin: 4em auto 2em;text-align: center;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;display: table;padding: 0px 0.2em;color: rgb(255, 255, 255);background: rgb(15, 76, 129);><span leaf="">授权码方案</span></h2> <h3 data-heading="true" style="box-sizing: border-box;border-width: 0px 0px 0px 3px;border-style: solid;border-left-color: rgb(15, 76, 129);font-size: 15.4px;font-weight: bold;margin: 2em 8px 0.75em 0px;text-align: left;line-height: 1.2;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;padding-left: 8px;color: rgb(63, 63, 63);><span leaf="">对称方案</span></h3> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">对称方案是指授权码的生成逻辑、校验逻辑完全一样。所谓校验就是客户端内部生成正确的授权码,然后和用户输入的授权码做对比,对比成功,则说明授权有效。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">以我个人习惯为例,授权码的字符串一般包含“机器码”、“项目名称”、“到期时间”、“盐值”,其中盐值用于增加授权码的复杂性,即使客户知道了授权码的生成方式,在不知道盐值的情况下,无法自行伪造授权码。</span></p> <h4 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 14px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(15, 76, 129);><span leaf="">生成过程</span></h4> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">我们先生成一个明文的字符串,然后通过特定分隔符拼接出明文的授权码,格式可以是:&nbsp;</span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 12.6px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">机器码:项目名称:到期时间:盐值</span></code><span leaf="">,例如:</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 12.6px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">123456:tpamis:281231:abcdef</span></code></p> <ul style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: circle;margin: 0px;padding: 0px 0px 0px 1em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;color: rgb(63, 63, 63); class="list-paddingleft-1"> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">•&nbsp;</span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 12.6px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">123456</span></code><span leaf="">:客户提供的机器码,这里以 123456 代替</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">•&nbsp;</span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 12.6px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">tpamis</span></code><span leaf="">:授权项目名称,同一个机器上可能存在多个软件产品,可以加一个项目名称用于区分。</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">•&nbsp;</span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 12.6px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">281231</span></code><span leaf="">:到期时间,这里取&nbsp;</span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 12.6px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">2028-12-31</span></code><span leaf="">&nbsp;的后6位作为到期时间。这里也可以写成授权天数,先选定一个时间作为起始日期,然后在这个时间上叠加偏移时间,得到的最终时间作为授权到期时间。例如:我出生的时间是:</span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 12.6px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">1998-11-11</span></code><span leaf="">,我以此作为起始时间。偏移时间:9628 天,得到授权到期时间为&nbsp;</span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 12.6px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">2028-12-31</span></code><span leaf="">。</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">•&nbsp;</span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 12.6px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">abcdef</span></code><span leaf="">:盐值,可以防止彩虹表攻击,即使攻击者知道生成算法,也无法通过预计算破解授权码。</span> </section></li> </ul> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">接着,我们通过一个 MD5 算法(也可使用其他 HASH 摘要算法)得到一个签名 "cfb9fc32230fa1a19423ef8b6af63a61",此签名就是一个授权码。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">但这时的授权码有一个问题,签名是不可逆的,所以我们无法在验证签名时通过签名得到授权到期时间,所以我们需要人为的拼接一下:</span></p> <ul style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: circle;margin: 0px;padding: 0px 0px 0px 1em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;color: rgb(63, 63, 63); class="list-paddingleft-1"> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• 直接拼接:&nbsp;</span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 12.6px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">cfb9fc32230fa1a19423ef8b6af63a61281231</span></code> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• 使用分隔字符:&nbsp;</span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 12.6px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">cfb9fc32230fa1a19423ef8b6af63a61-281231</span></code> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• 舍去后六位,以 UUID 的方式呈现:&nbsp;</span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 12.6px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">cfb9fc32-230f-a1a1-9423-ef8b6a281231</span></code> </section></li> </ul> <h4 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 14px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(15, 76, 129);><span leaf="">掩藏到期时间</span></h4> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">这个时你会发现 后六位明晃晃的摆在那里,太容易被人猜到是到期时间了,虽然不会被篡改,但仍希望隐藏在授权码中,我们可以通过 十进制转十六进制来实现:281231 转十六进制为:44a8f,这时授权码变成:</span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 12.6px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">cfb9fc32-230f-a1a1-9423-ef8b6a44a8f</span></code><span leaf="">。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">同时你可以将到期时间藏在授权码中间,替换掉对应位置的签名值,得到这样的授权码:</span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 12.6px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">cf44a8f2-230f-a1a1-9423ef8b6af63a61</span></code><span leaf="">。</span></p> <h4 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 14px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(15, 76, 129);><span leaf="">验证授权码</span></h4> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">到这一步,已经完成了授权码的生成过程,客户端程序需要提前内置盐值和同样的生成算法,在用户输入授权码激活时,先从授权码中截取出到期时间。再用客户端生成的授权码进行对比验证是否正确,以及是否过期。</span></p> <h4 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 14px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(15, 76, 129);><span leaf="">用户体验优化</span></h4> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">签名生成的授权码以及可以满足正常的离线授权的功能了,但有一些不允许插入U盘或联网的场景中,客户可能需要手动输入授权码,我们应该尽可能缩短授权码长度,方便用户输入。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">我们可以在前面授权码的基础上,参考 Windows 的授权码长度 (AAAAA-BBBBB-CCCCC-DDDD-EEEEE),每组5个字符,5 组共25个字符,通过横杠分割方便用户输入。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">前面 MD5 生成的签名是 128 位的二进制,转换为16进制后,长度为 32 个字符。其实我们可以 MD5 转为 36 进制得到:&nbsp;</span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 12.6px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">CAQ3DFUC0YPEHDZLA7ZKHHYLD</span></code><span leaf="">。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">我们再拼接上前面得到的十六进制到期时间,并转为全大写,就得到了方便输入的授权码格式:</span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 12.6px;text-align: left;line-height: 1.75;color: rgb(221, 17, 68);background: rgba(27, 31, 35, 0.05);padding: 3px 5px;border-radius: 4px;><span leaf="">CAQ3D-FUC0Y-PEHDZ-LA7ZK-HHYLD-44A8F</span></code><span leaf="">。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">如果需要长度和 Windows 一模一样,则需要在 36 进制转换后,再截取掉 5 位,拼接时间戳。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">这里提供一个 Go 语言 十六进制转36进制的方法示例:</span></p> <pre style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;margin: 10px 8px;color: rgb(201, 209, 217);background: rgb(13, 17, 23);text-align: left;line-height: 1.5;overflow-x: auto;border-radius: 8px;padding: 0px !important;><span hidden style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));display: flex;padding: 10px 14px 0px;"> <svg viewbox="0 0 450 130" height="13px" width="45px" y="0px" x="0px" version="1.1" xmlns="http://www.w3.org/2000/svg"> <ellipse fill="rgb(237,108,96)" stroke-width="2" stroke="rgb(220,60,54)" ry="52" rx="50" cy="65" cx="50"></ellipse><ellipse fill="rgb(247,193,81)" stroke-width="2" stroke="rgb(218,151,33)" ry="52" rx="50" cy="65" cx="225"></ellipse><ellipse fill="rgb(100,200,86)" stroke-width="2" stroke="rgb(27,161,37)" ry="52" rx="50" cy="65" cx="400"></ellipse> </svg></span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: Menlo, " operator mono, consolas, monaco, monospace;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;display: -webkit-box;padding: 0.5em 1em 1em;overflow-x: auto;text-indent: 0px;text-align: left;line-height: 1.75;margin: 0px;white-space: nowrap;><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">package</span></span><span leaf="">&nbsp;main</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">import</span></span><span leaf="">&nbsp;(</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"crypto/md5"</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"encoding/hex"</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"fmt"</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"math/big"</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(139, 148, 158);"><span leaf="">// 将 MD5 哈希值转换为 36 进制字符串</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">func</span></span><span leaf="">&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(210, 168, 255);"><span leaf="">md5ToBase36</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">(md5Hash&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">string</span></span><span leaf="">)</span></span></span><span leaf="">&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">string</span></span><span leaf="">&nbsp;{</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(139, 148, 158);"><span leaf="">// 将 MD5 哈希值(十六进制)转换为大整数</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; bigInt :=&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 166, 87);"><span leaf="">new</span></span><span leaf="">(big.Int)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; bigInt.SetString(md5Hash,&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">16</span></span><span leaf="">)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(139, 148, 158);"><span leaf="">// 定义 36 进制的字符集</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">const</span></span><span leaf="">&nbsp;charset =&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"0123456789abcdefghijklmnopqrstuvwxyz"</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(139, 148, 158);"><span leaf="">// 将大整数转换为 36 进制</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; base36 :=&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">""</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; base := big.NewInt(</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">36</span></span><span leaf="">)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; zero := big.NewInt(</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">0</span></span><span leaf="">)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; remainder :=&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 166, 87);"><span leaf="">new</span></span><span leaf="">(big.Int)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">for</span></span><span leaf="">&nbsp;bigInt.Cmp(zero) &gt;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">0</span></span><span leaf="">&nbsp;{</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; bigInt.DivMod(bigInt, base, remainder)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; base36 =&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">string</span></span><span leaf="">(charset[remainder.Int64()]) + base36</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; }</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">return</span></span><span leaf="">&nbsp;base36</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">}</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">func</span></span><span leaf="">&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(210, 168, 255);"><span leaf="">main</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">()</span></span></span><span leaf="">&nbsp;{</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(139, 148, 158);"><span leaf="">// 计算字符串的 MD5 哈希值</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; data :=&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"123456:tpamis:281231:abcdef"</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; hash := md5.Sum([]</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">byte</span></span><span leaf="">(data))</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; md5Hash := hex.EncodeToString(hash[:])&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(139, 148, 158);"><span leaf="">// 转换为十六进制字符串</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; fmt.Println(</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"MD5 哈希值:"</span></span><span leaf="">, md5Hash)&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(139, 148, 158);"><span leaf="">// 输出: cfb9fc32230fa1a19423ef8b6af63a61</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(139, 148, 158);"><span leaf="">// 将 MD5 哈希值转换为 36 进制</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; base36Code := md5ToBase36(md5Hash)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; fmt.Println(</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"36 进制编码:"</span></span><span leaf="">, base36Code)&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(139, 148, 158);"><span leaf="">// 输出: caq3dfuc0ypehdzla7zkhhyld</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">}</span></code></pre> <h4 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 14px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(15, 76, 129);><span leaf="">几个问题补充</span></h4> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><strong style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-weight: bold;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: inherit;color: rgb(15, 76, 129);><span leaf="">为什么要转 36进制而不是直接截取 MD5?</span></strong></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">因为截取后过短的 MD5 增加了碰撞的概率,转为 36进制,会包含 0-9、A-Z 36 个字符。36进制相比 16进制更为紧凑,在缩短长度同时保留较高的信息密度。且 36 进制在客户输入时,不需要考虑大小写问题,用户体验更好。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><strong style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-weight: bold;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: inherit;color: rgb(15, 76, 129);><span leaf="">摘要算法选择</span></strong></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">MD5 算法已被证实存在碰撞漏洞,但在安全性要求相对不是很高的场景中,还是可以接受的。如果需要安全性更高的摘要算法,可以换成例如 SHA-256、国密 SM3 等更为安全算法,在得到签名后截取 32 位 当作 MD5 使用,实现安全性、用户体验的兼顾。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><strong style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-weight: bold;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: inherit;color: rgb(15, 76, 129);><span leaf="">36进制字符集</span></strong></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">因为 36 进制是自行实现的,所以可以自定义字符集,大家可以在这一步对字符集排布顺序进行打乱,实现混淆效果。</span></p> <h3 data-heading="true" style="box-sizing: border-box;border-width: 0px 0px 0px 3px;border-style: solid;border-left-color: rgb(15, 76, 129);font-size: 15.4px;font-weight: bold;margin: 2em 8px 0.75em 0px;text-align: left;line-height: 1.2;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;padding-left: 8px;color: rgb(63, 63, 63);><span leaf="">非对称方案</span></h3> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">前面的授权码方案可以提供一个方便输入,长度较短的授权码字符串,但携带授权信息较少、密钥(盐值)需要内置在客户端中,遇到逆行破解场景,有盐值泄露的可能性。</span></p> <h4 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 14px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(15, 76, 129);><span leaf="">授权码设计</span></h4> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">非对称加密我们可以使用 RSA 算法来实现。当我们使用 RSA 算法时,我们可以通过授权码给客户端携带更多信息,所以我们就以 JSON 为许可证内容的载体。我们可以这样设计:</span></p> <pre style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;margin: 10px 8px;color: rgb(201, 209, 217);background: rgb(13, 17, 23);text-align: left;line-height: 1.5;overflow-x: auto;border-radius: 8px;padding: 0px !important;><span hidden style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));display: flex;padding: 10px 14px 0px;"> <svg viewbox="0 0 450 130" height="13px" width="45px" y="0px" x="0px" version="1.1" xmlns="http://www.w3.org/2000/svg"> <ellipse fill="rgb(237,108,96)" stroke-width="2" stroke="rgb(220,60,54)" ry="52" rx="50" cy="65" cx="50"></ellipse><ellipse fill="rgb(247,193,81)" stroke-width="2" stroke="rgb(218,151,33)" ry="52" rx="50" cy="65" cx="225"></ellipse><ellipse fill="rgb(100,200,86)" stroke-width="2" stroke="rgb(27,161,37)" ry="52" rx="50" cy="65" cx="400"></ellipse> </svg></span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: Menlo, " operator mono, consolas, monaco, monospace;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;display: -webkit-box;padding: 0.5em 1em 1em;overflow-x: auto;text-indent: 0px;text-align: left;line-height: 1.75;margin: 0px;white-space: nowrap;><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">{</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">"iss"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">:</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"tpamis"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">,</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">"sub"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">:</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"pord"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">,</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">"aud"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">:</span></span><span leaf="">&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"123456"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">,</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">"exp"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">:</span></span><span leaf="">&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"1861804800"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">,</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">"nbf"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">:</span></span><span leaf="">&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"1743436800"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">,</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">"iat"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">:</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"1742728673"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">,</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">"rge"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">:</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">[</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"功能a"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">,</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"功能b"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">,</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"功能b"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">]</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">}</span></span></code></pre> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">接参考了 JWT 官方规定的 Payload 字段,设计的许可证 JSON 内容,且这些字段可以根据需求随意添加调整。</span></p> <ul style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: circle;margin: 0px;padding: 0px 0px 0px 1em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;color: rgb(63, 63, 63); class="list-paddingleft-1"> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• iss (issuer):授权项目</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• sub (subject):授权方式,prod 正式授权、test 测试授权</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• aud (audience):授权对象,客户的机器码</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• exp (expiration time):过期时间</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• nbf (Not Before):生效时间</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• iat (Issued At):签发时间</span> </section></li> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">• rge:授权功能列表</span> </section></li> </ul> <h4 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 14px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(15, 76, 129);><span leaf="">生成授权码</span></h4> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">我们生成一对 RSA 公私钥,公钥保存在客户端,私钥在我们手里,我们根据用户的机器码,生成一个授权码,以上面为例,我额外扩展了授权模块功能,可以精确控制客户允许使用的功能范围。</span></p> <ol style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: none;margin: 0px;padding: 0px 0px 0px 1em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;color: rgb(63, 63, 63); class="list-paddingleft-1"> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">1. 生成包含许可证信息的JSON 字符串</span> </section></li> </ol> <pre style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;margin: 10px 8px;color: rgb(201, 209, 217);background: rgb(13, 17, 23);text-align: left;line-height: 1.5;overflow-x: auto;border-radius: 8px;padding: 0px !important;><span hidden style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));display: flex;padding: 10px 14px 0px;"> <svg viewbox="0 0 450 130" height="13px" width="45px" y="0px" x="0px" version="1.1" xmlns="http://www.w3.org/2000/svg"> <ellipse fill="rgb(237,108,96)" stroke-width="2" stroke="rgb(220,60,54)" ry="52" rx="50" cy="65" cx="50"></ellipse><ellipse fill="rgb(247,193,81)" stroke-width="2" stroke="rgb(218,151,33)" ry="52" rx="50" cy="65" cx="225"></ellipse><ellipse fill="rgb(100,200,86)" stroke-width="2" stroke="rgb(27,161,37)" ry="52" rx="50" cy="65" cx="400"></ellipse> </svg></span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: Menlo, " operator mono, consolas, monaco, monospace;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;display: -webkit-box;padding: 0.5em 1em 1em;overflow-x: auto;text-indent: 0px;text-align: left;line-height: 1.75;margin: 0px;white-space: nowrap;><span leaf="">{"iss":"tpamis","sub":"pord","aud":"123456","exp":"1861804800","nbf":"1743436800","iat":"1742728673","rge":["功能a","功能b","功能b"]}</span></code></pre> <ol style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));list-style: none;margin: 0px;padding: 0px 0px 0px 1em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;color: rgb(63, 63, 63); class="list-paddingleft-1"> <li style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;text-indent: -1em;display: block;margin: 0.2em 8px;color: rgb(63, 63, 63);> <section> <span leaf="">2. 然后我们使用 RSA 私钥加密生成密文,这个密文就是我们需要提供给客户的授权码。</span> </section></li> </ol> <pre style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;margin: 10px 8px;color: rgb(201, 209, 217);background: rgb(13, 17, 23);text-align: left;line-height: 1.5;overflow-x: auto;border-radius: 8px;padding: 0px !important;><span hidden style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));display: flex;padding: 10px 14px 0px;"> <svg viewbox="0 0 450 130" height="13px" width="45px" y="0px" x="0px" version="1.1" xmlns="http://www.w3.org/2000/svg"> <ellipse fill="rgb(237,108,96)" stroke-width="2" stroke="rgb(220,60,54)" ry="52" rx="50" cy="65" cx="50"></ellipse><ellipse fill="rgb(247,193,81)" stroke-width="2" stroke="rgb(218,151,33)" ry="52" rx="50" cy="65" cx="225"></ellipse><ellipse fill="rgb(100,200,86)" stroke-width="2" stroke="rgb(27,161,37)" ry="52" rx="50" cy="65" cx="400"></ellipse> </svg></span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: Menlo, " operator mono, consolas, monaco, monospace;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;display: -webkit-box;padding: 0.5em 1em 1em;overflow-x: auto;text-indent: 0px;text-align: left;line-height: 1.75;margin: 0px;white-space: nowrap;><span leaf="">I0UQvjrw3achexYK/D2ciNbsN+d28meH56aQPvosR9ZAKX2xp+kFNMfOjgBH+ZCL5+ir0h+pibfyva5weFBEEy1WgPMSqSiFGL5jfNIpzRY+Ct8hqsrjZm20TONvEjE7gwhFHW0m0NvdpFmwvbOjQPLk5ipZkNWW2l/DvEkYyogVMxCAfcNmczv1x9c1MeyXp0ru7GQifF1q1wGn4SBljc61zfUbtsv5aHk7zibOrNu4DsXnGjnYmwRCqYogAhB7g4Wzxfx0chMED9ulakTC8G5rBwT2w+LNgxKP+Si/nsOL0PeBzwrLTYulJIQEoqNsjMkDJ4JbXa/uoWrRoIuMTg==</span></code></pre> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">当许可证内容过多,导致密文过长时,可以考虑输出一个密钥文件给客户,客户在产品中上传、选择 密钥文件,我们通过读取密钥文件来获取授权码。这样体验更好。</span></p> <h4 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 14px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(15, 76, 129);><span leaf="">授权码验证</span></h4> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">用户将我们的授权码输入到软件中,客户端使用公钥解密,解密成功则读取进入进行进一步的授权校验,解密失败直接提示授权码错误。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">说明:将公钥内置到客户端,在极端情况下,存在反编译的可能性。所以我们可以假设公钥已经泄露、不安全的状态。不过只要私钥不泄露,别人拿到公钥也只能解密我们的许可证密文,而不能伪造一个许可证,相对来说也是可以接受的。</span></p> <h4 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 14px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(15, 76, 129);><span leaf="">代码示例</span></h4> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">以 Go 语言为例 加密解密过程如下</span></p> <pre style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;margin: 10px 8px;color: rgb(201, 209, 217);background: rgb(13, 17, 23);text-align: left;line-height: 1.5;overflow-x: auto;border-radius: 8px;padding: 0px !important;><span hidden style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));display: flex;padding: 10px 14px 0px;"> <svg viewbox="0 0 450 130" height="13px" width="45px" y="0px" x="0px" version="1.1" xmlns="http://www.w3.org/2000/svg"> <ellipse fill="rgb(237,108,96)" stroke-width="2" stroke="rgb(220,60,54)" ry="52" rx="50" cy="65" cx="50"></ellipse><ellipse fill="rgb(247,193,81)" stroke-width="2" stroke="rgb(218,151,33)" ry="52" rx="50" cy="65" cx="225"></ellipse><ellipse fill="rgb(100,200,86)" stroke-width="2" stroke="rgb(27,161,37)" ry="52" rx="50" cy="65" cx="400"></ellipse> </svg></span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: Menlo, " operator mono, consolas, monaco, monospace;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;display: -webkit-box;padding: 0.5em 1em 1em;overflow-x: auto;text-indent: 0px;text-align: left;line-height: 1.75;margin: 0px;white-space: nowrap;><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">package</span></span><span leaf="">&nbsp;main</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">import</span></span><span leaf="">&nbsp;(</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"encoding/json"</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"fmt"</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"github.com/dromara/dongle"</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">func</span></span><span leaf="">&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(210, 168, 255);"><span leaf="">main</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">()</span></span></span><span leaf="">&nbsp;{</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(139, 148, 158);"><span leaf="">// 声明 map[string]any 许可证结构</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; licenseData :=&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">map</span></span><span leaf="">[</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">string</span></span><span leaf="">]any{</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"iss"</span></span><span leaf="">:&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"tpamis"</span></span><span leaf="">,</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"sub"</span></span><span leaf="">:&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"pord"</span></span><span leaf="">,</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"aud"</span></span><span leaf="">:&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"123456"</span></span><span leaf="">,</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"exp"</span></span><span leaf="">:&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"1861804800"</span></span><span leaf="">,</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"nbf"</span></span><span leaf="">:&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"1743436800"</span></span><span leaf="">,</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"iat"</span></span><span leaf="">:&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"1742728673"</span></span><span leaf="">,</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"rge"</span></span><span leaf="">: []</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">string</span></span><span leaf="">{</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"功能a"</span></span><span leaf="">,&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"功能b"</span></span><span leaf="">,&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"功能b"</span></span><span leaf="">},</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; }</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(139, 148, 158);"><span leaf="">// 将 map 转换为 JSON 字符串</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; jsonData, _ := json.Marshal(licenseData)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(139, 148, 158);"><span leaf="">// 使用RSA 私钥 授权Json</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; cipherText := dongle.Encrypt.FromBytes(jsonData).ByRsa(pkcs1PrivateKey).ToBase64String()</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; fmt.Println(</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"RSA密文"</span></span><span leaf="">, cipherText)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(139, 148, 158);"><span leaf="">// 客户端 使用 公钥进行解密</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; licenseJson := dongle.Decrypt.FromBase64String(cipherText).ByRsa(pkcs1PublicKey).ToString()</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp; fmt.Println(</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"许可证Json"</span></span><span leaf="">, licenseJson)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">}</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">var</span></span><span leaf="">&nbsp;pkcs1PublicKey = []</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">byte</span></span><span leaf="">(</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">`-----BEGIN RSA PUBLIC KEY-----</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">MIGJAoGBAK12MTd84qkCZzp4iLUj8YSUglaFMsFlv9KlIL4+Xts40PK3+wbsXPEw</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">cujGeUmdgMeZiK7SLLSz8QeE0v7Vs+cGK4Bs4qLtMGCiO6wEuyt10KsafTyBktFn</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">dk/+gBLr7B/b+9+HaMIIoJUdsFksdAg3cxTSpwVApe98loFNRfqDAgMBAAE=</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">-----END RSA PUBLIC KEY-----`</span></span><span leaf="">)</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">var</span></span><span leaf="">&nbsp;pkcs1PrivateKey = []</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(255, 123, 114);"><span leaf="">byte</span></span><span leaf="">(</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">`-----BEGIN RSA PRIVATE KEY-----</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">MIICXQIBAAKBgQCtdjE3fOKpAmc6eIi1I/GElIJWhTLBZb/SpSC+Pl7bONDyt/sG</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">7FzxMHLoxnlJnYDHmYiu0iy0s/EHhNL+1bPnBiuAbOKi7TBgojusBLsrddCrGn08</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">gZLRZ3ZP/oAS6+wf2/vfh2jCCKCVHbBZLHQIN3MU0qcFQKXvfJaBTUX6gwIDAQAB</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">AoGAFwAfEo56t5JcAcLNzccQVVYj2jkbO820G8hNiSxYA5WLD0QaAxcAU/Lqqbb3</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">ii1aUB0ppJS13NgnU6nnGGdZzUYBG1Hai6EkVyCGrI4amQ93AaVdKncL8gJ4RZAm</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">YzPPUwSMEESsu24pS1NF1G1Y8C+28b/Wr0oqOsCvL6PhsMECQQDwsPJJoWRx7ZJw</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">E1K5KLT0cXKyrIpyXY3I6tyA5imCzOzccf3d1vDgB0L9sdSO7bG3ceSwpAeiWEbg</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">5jGZemPzAkEAuH6U4pEI4AMbWnatpK55Rc235NDgmT3VyIuRaKC02YXAZ+jznFep</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">XMd4DTli4R9r3j2YVhUpyDVbdQpFH98DMQJAQpOvcU6DSkA80WOG7lCkPTlkUKgJ</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">Y7kdDwZoF/+SW+vzWMbvQf3CgzV/Ak2+TgrRrbyDVZkJw45HjM4fyiRgoQJBALH/</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">/qlxgPyQQs3O/s2KQBsm1auAE5IF5MLuVUZ69sF/mBko2hEXSqHnGV645TuKU0pC</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">Zz12ga9WO3z6gaK0SaECQQDah1pKt9ViBBy4USXK3OWXEloHuTwmyr9AbLqqI5tQ</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">2eNuH0NkuJYQmnXmHLbKOELoYocldEBXmkzPXSN+X9kV</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">-----END RSA PRIVATE KEY-----`</span></span><span leaf="">)</span></code></pre> <h3 data-heading="true" style="box-sizing: border-box;border-width: 0px 0px 0px 3px;border-style: solid;border-left-color: rgb(15, 76, 129);font-size: 15.4px;font-weight: bold;margin: 2em 8px 0.75em 0px;text-align: left;line-height: 1.2;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;padding-left: 8px;color: rgb(63, 63, 63);><span leaf="">JWT 方案</span></h3> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">JWT 方案则是直接使用标准的 JWT 库来实现授权码的签发功能,客户端和服务端共享 JWT 的密钥来验证授权签名的有效性。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">本方案的优点是可以充分利用现有的标准化 JWT 库,只需定义一个密钥,而无需进行过多的开发,但许可证内容会直接暴露给客户,也可以考虑 JWE,需自行抉择。</span></p> <pre style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;margin: 10px 8px;color: rgb(201, 209, 217);background: rgb(13, 17, 23);text-align: left;line-height: 1.5;overflow-x: auto;border-radius: 8px;padding: 0px !important;><span hidden style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));display: flex;padding: 10px 14px 0px;"> <svg viewbox="0 0 450 130" height="13px" width="45px" y="0px" x="0px" version="1.1" xmlns="http://www.w3.org/2000/svg"> <ellipse fill="rgb(237,108,96)" stroke-width="2" stroke="rgb(220,60,54)" ry="52" rx="50" cy="65" cx="50"></ellipse><ellipse fill="rgb(247,193,81)" stroke-width="2" stroke="rgb(218,151,33)" ry="52" rx="50" cy="65" cx="225"></ellipse><ellipse fill="rgb(100,200,86)" stroke-width="2" stroke="rgb(27,161,37)" ry="52" rx="50" cy="65" cx="400"></ellipse> </svg></span><code style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-family: Menlo, " operator mono, consolas, monaco, monospace;font-feature-settings: normal;font-variation-settings: normal;font-size: 14px;display: -webkit-box;padding: 0.5em 1em 1em;overflow-x: auto;text-indent: 0px;text-align: left;line-height: 1.75;margin: 0px;white-space: nowrap;><span leaf="">JWT Header</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">{</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">"alg"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">:</span></span><span leaf="">&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"HS256"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">,</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">"typ"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">:</span></span><span leaf="">&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"JWT"</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">}</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">JWT Payload</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">{</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">"iss"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">:</span></span><span leaf="">&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"tpamis"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">,</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">"sub"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">:</span></span><span leaf="">&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"pord"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">,</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">"aud"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">:</span></span><span leaf="">&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"123456"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">,</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">"exp"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">:</span></span><span leaf="">&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"1861804800"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">,</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">"nbf"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">:</span></span><span leaf="">&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"1743436800"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">,</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">"iat"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">:</span></span><span leaf="">&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"1742728673"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">,</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(121, 192, 255);"><span leaf="">"rge"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">:</span></span><span leaf="">&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">[</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"功能a"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">,</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"功能b"</span></span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">,</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));color: rgb(165, 214, 255);"><span leaf="">"功能b"</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">&nbsp;&nbsp;</span><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">]</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">}</span></span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">密钥</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">dbkuaizi.com</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">JWT Token</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0cGFtaXMiLCJzdWIiOiJwb3JkIiwiYXVkIjoiMTIzNDU2IiwiZXhwIjoiMTg2MTgwNDgwMCIsIm5iZiI6IjE3NDM0MzY4MDAiLCJpYXQiOiIxNzQyNzI4NjczIiwicmdlIjpbIuWKn-iDvWEiLCLlip_og71iIiwi5Yqf6IO9YiJdfQ.izIAwMyiLxPiHrWf-FDGu3fHMvfaC7bqEh40ha8YYAA</span></code></pre> <h2 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 16.8px;font-weight: bold;margin: 4em auto 2em;text-align: center;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;display: table;padding: 0px 0.2em;color: rgb(255, 255, 255);background: rgb(15, 76, 129);><span leaf="">结尾</span></h2> <h3 data-heading="true" style="box-sizing: border-box;border-width: 0px 0px 0px 3px;border-style: solid;border-left-color: rgb(15, 76, 129);font-size: 15.4px;font-weight: bold;margin: 2em 8px 0.75em 0px;text-align: left;line-height: 1.2;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;padding-left: 8px;color: rgb(63, 63, 63);><span leaf="">没有绝对的安全</span></h3> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">任何安全领域的手段都是相对安全,没有绝对的安全。再复杂的授权码的本质只能是&nbsp;</span><strong style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-weight: bold;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: inherit;color: rgb(15, 76, 129);><span leaf="">防君子不防小人</span></strong><span leaf="">,例如用户可以通过逆向 得到你的盐值、甚至直接修改你的程序逻辑跳过验证的逻辑,更何况我们的场景中只有离线校验的逻辑。</span></p> <h3 data-heading="true" style="box-sizing: border-box;border-width: 0px 0px 0px 3px;border-style: solid;border-left-color: rgb(15, 76, 129);font-size: 15.4px;font-weight: bold;margin: 2em 8px 0.75em 0px;text-align: left;line-height: 1.2;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;padding-left: 8px;color: rgb(63, 63, 63);><span leaf="">防止时钟回拨</span></h3> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">时钟回拨是指,就是用户直接通过修改系统时间到软件授权到期之前,从而继续使用软件的目的。那么我们在离线场景中如何去避免这样的情况发生呢?</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">首先我需要声明的是,离线授权场景中,不能彻底避免这种情况(除了独立时钟的加密狗),我们能做的就是通过代码逻辑尽可能规避这种情况的发生,一般有这几种手段:</span></p> <h4 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 14px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(15, 76, 129);><span leaf="">记录上一次运行时间</span></h4> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">众所周知,时间是不会倒流的,也就是说软件的第二次运行时间,</span><strong style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-weight: bold;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: inherit;color: rgb(15, 76, 129);><span leaf="">不可能小于</span></strong><span leaf="">上一次运行时的系统时间。</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">所以,在软件每次运行时我们可以先记录当前时间,并与上一次系统时间做对比,若第二次运行时的系统时间小于之前记录的时间,则认为出现了系统时钟回拨的问题,直接提示用户并终止软件运行。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><strong style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-weight: bold;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: inherit;color: rgb(15, 76, 129);><span leaf="">安全的存储时间标记</span></strong><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">那么如何保证我们存储的时间没有被篡改呢?我们可以通过 (时间戳.盐)+md5 的方式实现:</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">例如:时间戳为 1717487962 盐 是 abcdefg,</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">通过: md5('1717487962.abcdefg') 摘要算法,获得时间戳签名:a06de98fc28e45bf38a9a5f27630cd03。</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">然后将这样的字符串进行存储:1717487962.a06de98fc28e45bf38a9a5f27630cd03,启动时再通过上面的逻辑进行校验,即可保证 记录的时间不被修改。</span></p> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><strong style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-weight: bold;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: inherit;color: rgb(15, 76, 129);><span leaf="">如何防止用户删除时间标记</span></strong><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">可以在打包的时候,就记录一个打包时间作为初始化时间戳,这样即使用户第一次运行也必须有时间戳。</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">若没读取不到时间戳标记,则说明用户人为清理了时间标记,结束运行。</span></p> <h4 data-heading="true" style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));font-size: 14px;font-weight: bold;margin: 2em 8px 0.5em;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;color: rgb(15, 76, 129);><span leaf="">与业务数据强关联</span></h4> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">如果你产品运行过程中产生的业务数据很重要,也可以使用业务中的时间戳来做时钟回拨校验,例如使用最后一条订单的创建时间。</span><br style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));"><span leaf="">若业务数据很重要,用户总不可能为了继续使用软件而删掉业务数据吧。</span></p> <h3 data-heading="true" style="box-sizing: border-box;border-width: 0px 0px 0px 3px;border-style: solid;border-left-color: rgb(15, 76, 129);font-size: 15.4px;font-weight: bold;margin: 2em 8px 0.75em 0px;text-align: left;line-height: 1.2;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;padding-left: 8px;color: rgb(63, 63, 63);><span leaf="">抛砖引玉</span></h3> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 1.5em 8px;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;font-size: 14px;letter-spacing: 0.1em;color: rgb(63, 63, 63);><span leaf="">授权码的设计方案有很多,这里只是整理了我用过的几种方案,大家可以根据自己的需要对逻辑进行调整,如果你有更好的方案,欢迎留言交流。</span></p> </section> <p style="box-sizing: border-box;border-width: 0px;border-style: solid;border-color: hsl(var(--border));margin: 0px;color: rgb(10, 10, 10);font-family: ui-sans-serif, system-ui, sans-serif, " apple color emoji, segoe ui symbol, noto emoji;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;white-space: normal;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 0px;line-height: 0;><span leaf="">&nbsp;</span></p> <section> <span leaf=""><br></span> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>

超硬核:为什么 SpringBoot 宁可挨骂也要干掉 spring.factories?

作者:微信小助手

<section> <span leaf=""><img src="/upload/08a263ede13d33448d78713510cc9d81.png" alt="图片" class="rich_pages wxw-img" data-ratio="0.125" data-w="640"></span> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 10px;padding-right: 10px;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;font-family: Optima, 'Microsoft YaHei', PingFangSC-regular, serif;font-size: 16px;color: rgb(0, 0, 0);line-height: 1.5em;word-spacing: 0em;letter-spacing: 0em;word-break: break-word;overflow-wrap: break-word;text-align: left;" data-pm-slice="0 0 []"> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">SpringBoot 3.0之后为什么取消了</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code></strong></p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;"><span style="display: none;"></span><span style="font-size: 20px;color: rgb(53, 179, 120);line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">1. 引言</span></span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">在SpringBoot的演进过程中,3.0版本带来了一次重大变革——取消了长期以来作为自动配置和扩展机制核心的</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">文件。这个改变对于习惯了SpringBoot旧版本开发的工程师来说,需要了解新的机制和迁移策略。</span></p> <blockquote style="margin-top: 20px;margin-bottom: 20px;margin-left: 0px;margin-right: 0px;padding-top: 10px;padding-bottom: 10px;padding-left: 20px;padding-right: 10px;border-top-style: none;border-bottom-style: none;border-left-style: solid;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgb(53, 179, 120);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;background-attachment: scroll;background-clip: border-box;background-color: rgb(251, 249, 253);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;display: block;overflow-x: auto;overflow-y: auto;"> <span style="display: none;color: rgb(0, 0, 0);font-size: 16px;line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: normal;"></span> <p style="text-indent: 0em;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;"><span leaf="">本文将深入探讨这一变更的原因、影响以及替代方案。</span></p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;"><span style="display: none;"></span><span style="font-size: 20px;color: rgb(53, 179, 120);line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">2. spring.factories是什么</span></span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">在讨论它的取消之前,我们首先需要理解</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">文件在SpringBoot中扮演的角色。</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">2.1 基本概念</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">是一个位于</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">META-INF/</span></code><span leaf="">目录下的配置文件,它基于Java的SPI(</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">Service Provider Interface</span></code><span leaf="">)机制的变种实现。这个文件的主要功能是允许开发者声明接口的实现类,从而实现SpringBoot的自动装配和扩展点注册。</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">2.2 主要用途</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">在SpringBoot 3.0之前,</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">文件有以下几个主要用途:</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/32bbcd6240ca1d6dd14e0c3f9d7d1b31.png" class="rich_pages wxw-img" data-ratio="0.456575682382134" data-type="png" data-w="806" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;" data-imgfileid="100079138"></span> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">2.3 工作原理</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">SpringBoot启动时,会使用</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">SpringFactoriesLoader</span></code><span leaf="">类扫描类路径下所有JAR包中的</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">META-INF/spring.factories</span></code><span leaf="">文件,读取配置信息并加载对应的类。这种机制使得SpringBoot能够以"</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">约定优于配置</span></code><span leaf="">"的方式实现自动装配。</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg wjibwkqn1bumbc0hh3ffs6jtqywibylibs6nkh0tqj4eauwzbkicot8ibspmaqh3qtvt724riwdfwre3veibzaoqcosbd9nctlgqhc 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// SpringFactoriesLoader核心代码示例(SpringBoot 2.x)</span></span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">final</span></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">class</span></span><span leaf="">&nbsp;</span><span style="color: #e6c07b;line-height: 26px;"><span leaf="">SpringFactoriesLoader</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// ...</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">static</span></span><span leaf="">&nbsp; <t>&nbsp; </t></span><span style="line-height: 26px;"><span leaf="">List <t>&nbsp; </t></span><span style="color: #61aeee;line-height: 26px;"><span leaf="">loadFactories</span></span><span style="line-height: 26px;"><span leaf="">(Class <t> factoryType, @Nullable ClassLoader classLoader) </t></span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// ...&nbsp;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 加载META-INF/spring.factories中的配置</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; Map <string, list<string>&gt; result = loadSpringFactories(classLoader); </string,></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// ...</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; }</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">private</span></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">static</span></span><span leaf="">&nbsp;Map <string, list<string>&gt; loadSpringFactories( </string,></span><span style="color: #61aeee;line-height: 26px;"><span leaf="">@Nullable</span></span><span leaf="">&nbsp;ClassLoader classLoader) {</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 从类路径中加载所有META-INF/spring.factories文件</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// ...</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; }</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// ...</span></span><span leaf=""><br></span><span leaf="">}</span><span leaf=""><br></span></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;"><span style="display: none;"></span><span style="font-size: 20px;color: rgb(53, 179, 120);line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">3. 为什么要取消spring.factories</span></span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">SpringBoot团队决定取消</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">机制有几个关键原因:</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">3.1 性能问题</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">机制需要在启动时扫描所有JAR包中的配置文件,当项目依赖较多时,这个过程会消耗大量时间,影响应用启动性能。</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">3.2 缺乏模块化支持</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">随着Java 9引入模块系统(JPMS),传统的基于类路径扫描的方式与模块化设计理念存在冲突。</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">无法很好地支持Java模块系统。</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">3.3 缺乏条件加载能力</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">文件中的配置是静态的,无法根据条件动态决定是否加载某个实现。虽然可以在实现类上使用</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">@Conditional</span></code><span leaf="">注解,但这种方式效率较低,因为所有类都会被加载到内存中进行条件评估。</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">3.4 配置分散难以管理</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">在大型项目中,</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">配置分散在多个JAR包中,难以集中管理和查看全局配置。</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">3.5 GraalVM原生镜像支持</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">SpringBoot 3.0的一个重要目标是提供对GraalVM原生镜像的一流支持。而</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">基于运行时类路径扫描的机制与GraalVM的提前编译(</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">Ahead-of-Time Compilation</span></code><span leaf="">, AOT)模型存在根本性冲突。具体来说:</span></p> <ul style="list-style-type: disc;margin-top: 8px;margin-bottom: 8px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 25px;padding-right: 0px;color: rgb(0, 0, 0);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">静态分析限制:</span></strong><span leaf="">&nbsp;GraalVM在构建原生镜像时需要静态分析代码,而</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">的类路径扫描是动态执行的,无法在构建时确定。</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">反射使用问题:</span></strong><span leaf="">&nbsp;</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">依赖于反射加载类,而GraalVM需要预先知道所有使用反射的类,这需要额外的配置和处理。</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">资源访问限制:</span></strong><span leaf="">&nbsp;在GraalVM原生镜像中,资源文件的访问机制与JVM有所不同,</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">文件的扫描方式需要特殊处理。</span> </section></li> </ul> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">为了更好地支持GraalVM,SpringBoot需要一种在构建时就能确定的静态配置方式,而不是运行时的动态扫描。</span></p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;"><span style="display: none;"></span><span style="font-size: 20px;color: rgb(53, 179, 120);line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">4. 替代方案:imports文件</span></span><span style="display: none;"></span></h3> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">4.1 新机制介绍</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">从SpringBoot 3.0开始,引入了基于imports文件的新机制,作为</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">的替代方案。这些文件位于</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">META-INF/spring/</span></code><span leaf="">目录下,每种类型的扩展点对应一个专门的文件:</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/e06581cda8f827c3097989e5438735b5.png" class="rich_pages wxw-img" data-ratio="0.21679197994987467" data-type="png" data-w="798" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;" data-imgfileid="100079135"></span> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">4.2 新机制优势</span></span><span style="display: none;"></span></h4> <ul style="list-style-type: disc;margin-top: 8px;margin-bottom: 8px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 25px;padding-right: 0px;color: rgb(0, 0, 0);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">更好的性能:</span></strong><span leaf="">&nbsp;每种扩展点类型使用单独的文件,避免了加载不必要的配置</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">支持Java模块系统:</span></strong><span leaf="">&nbsp;新机制与Java模块系统兼容</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">简化配置:</span></strong><span leaf="">&nbsp;每行一个全限定类名,无需键值对形式,更易读易写</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">更好的组织结构:</span></strong><span leaf="">&nbsp;配置按功能分类到不同文件,结构更清晰</span> </section></li> </ul> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">4.3 示例对比</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">旧方式(</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">):</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg wjibwkqn1bumbc0hh3ffs6jtqywibylibs6nkh0tqj4eauwzbkicot8ibspmaqh3qtvt724riwdfwre3veibzaoqcosbd9nctlgqhc 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">org.springframework.boot.autoconfigure.EnableAutoConfiguration=\</span><span leaf=""><br></span><span leaf="">com.example.FooAutoConfiguration,\</span><span leaf=""><br></span><span leaf="">com.example.BarAutoConfiguration</span><span leaf=""><br></span></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">新方式(</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">AutoConfiguration.imports</span></code><span leaf="">):</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg wjibwkqn1bumbc0hh3ffs6jtqywibylibs6nkh0tqj4eauwzbkicot8ibspmaqh3qtvt724riwdfwre3veibzaoqcosbd9nctlgqhc 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">com.example.FooAutoConfiguration</span><span leaf=""><br></span><span leaf="">com.example.BarAutoConfiguration</span><span leaf=""><br></span></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;"><span style="display: none;"></span><span style="font-size: 20px;color: rgb(53, 179, 120);line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">5. 迁移指南</span></span><span style="display: none;"></span></h3> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">5.1 自动配置类迁移</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">将原来在</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">中注册的自动配置类移动到</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports</span></code><span leaf="">文件中:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg wjibwkqn1bumbc0hh3ffs6jtqywibylibs6nkh0tqj4eauwzbkicot8ibspmaqh3qtvt724riwdfwre3veibzaoqcosbd9nctlgqhc 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 原来的自动配置类</span></span><span leaf=""><br></span><span style="color: #61aeee;line-height: 26px;"><span leaf="">@Configuration</span></span><span leaf=""><br></span><span style="color: #61aeee;line-height: 26px;"><span leaf="">@ConditionalOnXxx</span></span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span leaf="">&nbsp;</span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">class</span></span><span leaf="">&nbsp;</span><span style="color: #e6c07b;line-height: 26px;"><span leaf="">MyAutoConfiguration</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// ...</span></span><span leaf=""><br></span><span leaf="">}</span><span leaf=""><br></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 在META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中添加:</span></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// com.example.MyAutoConfiguration</span></span><span leaf=""><br></span></code></pre> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">5.2 其他扩展点如何迁移</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">对于其他类型的扩展点,SpringBoot 3.0保留了</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">机制,但推荐在新项目中使用新的注册方式:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg wjibwkqn1bumbc0hh3ffs6jtqywibylibs6nkh0tqj4eauwzbkicot8ibspmaqh3qtvt724riwdfwre3veibzaoqcosbd9nctlgqhc 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 示例:注册ApplicationListener</span></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// SpringBoot 3.0之前:在spring.factories中配置</span></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// org.springframework.context.ApplicationListener=com.example.MyListener</span></span><span leaf=""><br></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// SpringBoot 3.0之后:使用@Bean方式注册</span></span><span leaf=""><br></span><span style="color: #61aeee;line-height: 26px;"><span leaf="">@Configuration</span></span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span leaf="">&nbsp;</span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">class</span></span><span leaf="">&nbsp;</span><span style="color: #e6c07b;line-height: 26px;"><span leaf="">MyConfiguration</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">@Bean</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span leaf="">&nbsp;MyListener&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">myListener</span></span><span style="line-height: 26px;"><span leaf="">()</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">return</span></span><span leaf="">&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">new</span></span><span leaf="">&nbsp;MyListener();</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; }</span><span leaf=""><br></span><span leaf="">}</span><span leaf=""><br></span></code></pre> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">5.3 自定义扩展点迁移</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">对于自定义的扩展点,需要提供类似的imports文件机制:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg wjibwkqn1bumbc0hh3ffs6jtqywibylibs6nkh0tqj4eauwzbkicot8ibspmaqh3qtvt724riwdfwre3veibzaoqcosbd9nctlgqhc 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 自定义扩展点加载器示例</span></span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">class</span></span><span leaf="">&nbsp;</span><span style="color: #e6c07b;line-height: 26px;"><span leaf="">MyExtensionLoader</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span leaf="">&nbsp;List <myextension>&nbsp; </myextension></span><span style="color: #61aeee;line-height: 26px;"><span leaf="">loadExtensions</span></span><span style="line-height: 26px;"><span leaf="">()</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">return</span></span><span leaf="">&nbsp;SpringFactoriesLoader.loadFactories(MyExtension</span><span style="line-height: 26px;"><span leaf="">.</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">class</span></span><span leaf="">,&nbsp;</span><span style="color: #e6c07b;line-height: 26px;"><span leaf="">null</span></span><span leaf="">)</span></span><span leaf="">;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; }</span><span leaf=""><br></span><span leaf="">}</span><span leaf=""><br></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 迁移到新机制</span></span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">class</span></span><span leaf="">&nbsp;</span><span style="color: #e6c07b;line-height: 26px;"><span leaf="">MyExtensionLoader</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span leaf="">&nbsp;List <myextension>&nbsp; </myextension></span><span style="color: #61aeee;line-height: 26px;"><span leaf="">loadExtensions</span></span><span style="line-height: 26px;"><span leaf="">()</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; List <string> classNames = SpringFactoriesLoader.loadFactoryNames( </string></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; MyExtension</span><span style="line-height: 26px;"><span leaf="">.</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">class</span></span><span leaf="">,&nbsp;</span><span style="color: #e6c07b;line-height: 26px;"><span leaf="">null</span></span><span leaf="">)</span></span><span leaf="">;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 或者实现自己的imports文件加载逻辑</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// ...</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; }</span><span leaf=""><br></span><span leaf="">}</span><span leaf=""><br></span></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;"><span style="display: none;"></span><span style="font-size: 20px;color: rgb(53, 179, 120);line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">6. SpringFactoriesLoader的变化</span></span><span style="display: none;"></span></h3> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">6.1 API变更</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">在SpringBoot 3.0中,</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">SpringFactoriesLoader</span></code><span leaf="">类本身也经历了重大改变:</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/589852f3c10a5db1e2b91b9b7f98e440.png" class="rich_pages wxw-img" data-ratio="0.24447717231222385" data-type="png" data-w="679" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;" data-imgfileid="100079134"></span> </figure> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg wjibwkqn1bumbc0hh3ffs6jtqywibylibs6nkh0tqj4eauwzbkicot8ibspmaqh3qtvt724riwdfwre3veibzaoqcosbd9nctlgqhc 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// SpringBoot 3.x中新的SpringFactoriesLoader用法</span></span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">final</span></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">class</span></span><span leaf="">&nbsp;</span><span style="color: #e6c07b;line-height: 26px;"><span leaf="">SpringFactoriesLoader</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 过时的方法</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">@Deprecated</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">static</span></span><span leaf="">&nbsp; <t>&nbsp; </t></span><span style="line-height: 26px;"><span leaf="">List <t>&nbsp; </t></span><span style="color: #61aeee;line-height: 26px;"><span leaf="">loadFactories</span></span><span style="line-height: 26px;"><span leaf="">(Class <t> factoryType, @Nullable ClassLoader classLoader) </t></span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// ...</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; }</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 新方法</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span leaf="">&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">static</span></span><span leaf="">&nbsp;List <string>&nbsp; </string></span><span style="color: #61aeee;line-height: 26px;"><span leaf="">loadFactoryNames</span></span><span style="line-height: 26px;"><span leaf="">(Class<!--?--> factoryType, @Nullable ClassLoader classLoader)</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 加载对应的imports文件</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// ...</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; }</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// ...</span></span><span leaf=""><br></span><span leaf="">}</span><span leaf=""><br></span></code></pre> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">6.2 兼容性考虑</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">为了保持向后兼容性,SpringBoot 3.0仍然支持通过</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">注册某些类型的扩展点,但新的项目应该优先考虑使用新机制。</span></p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;"><span style="display: none;"></span><span style="font-size: 20px;color: rgb(53, 179, 120);line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">7. 实战示例</span></span><span style="display: none;"></span></h3> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">7.1 创建自定义自动配置</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">下面是一个完整的示例,展示如何在SpringBoot 3.0中创建和注册自动配置:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg wjibwkqn1bumbc0hh3ffs6jtqywibylibs6nkh0tqj4eauwzbkicot8ibspmaqh3qtvt724riwdfwre3veibzaoqcosbd9nctlgqhc 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 1. 创建配置属性类</span></span><span leaf=""><br></span><span style="color: #61aeee;line-height: 26px;"><span leaf="">@ConfigurationProperties</span></span><span leaf="">(prefix =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"myapp"</span></span><span leaf="">)</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">class</span></span><span leaf="">&nbsp;</span><span style="color: #e6c07b;line-height: 26px;"><span leaf="">MyProperties</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">private</span></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">boolean</span></span><span leaf="">&nbsp;enabled =&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">true</span></span><span leaf="">;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">private</span></span><span leaf="">&nbsp;String name =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"default"</span></span><span leaf="">;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// getter和setter方法</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// ...</span></span><span leaf=""><br></span><span leaf="">}</span><span leaf=""><br></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 2. 创建自动配置类</span></span><span leaf=""><br></span><span style="color: #61aeee;line-height: 26px;"><span leaf="">@AutoConfiguration</span></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 注意这里使用了@AutoConfiguration而非@Configuration</span></span><span leaf=""><br></span><span style="color: #61aeee;line-height: 26px;"><span leaf="">@EnableConfigurationProperties</span></span><span leaf="">(MyProperties</span><span style="line-height: 26px;"><span leaf="">.</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">class</span></span><span leaf="">)</span><span leaf=""><br></span><span leaf="">@</span><span style="color: #e6c07b;line-height: 26px;"><span leaf="">ConditionalOnProperty</span></span><span leaf="">(</span><span style="color: #e6c07b;line-height: 26px;"><span leaf="">prefix</span></span><span leaf="">&nbsp;</span></span><span leaf="">=&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"myapp"</span></span><span leaf="">, name =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"enabled"</span></span><span leaf="">, havingValue =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"true"</span></span><span leaf="">, matchIfMissing =&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">true</span></span><span leaf="">)</span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">class</span></span><span leaf="">&nbsp;</span><span style="color: #e6c07b;line-height: 26px;"><span leaf="">MyAutoConfiguration</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">private</span></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">final</span></span><span leaf="">&nbsp;MyProperties properties;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span leaf="">&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">MyAutoConfiguration</span></span><span style="line-height: 26px;"><span leaf="">(MyProperties properties)</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">this</span></span><span leaf="">.properties = properties;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; }</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">@Bean</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">@ConditionalOnMissingBean</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span leaf="">&nbsp;MyService&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">myService</span></span><span style="line-height: 26px;"><span leaf="">()</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 根据属性创建服务</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">return</span></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">new</span></span><span leaf="">&nbsp;MyServiceImpl(properties.getName());</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; }</span><span leaf=""><br></span><span leaf="">}</span><span leaf=""><br></span></code></pre> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">7.2 注册自动配置</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">然后,在</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">META-INF/spring/</span></code><span leaf="">目录下创建</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">org.springframework.boot.autoconfigure.AutoConfiguration.imports</span></code><span leaf="">文件:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg wjibwkqn1bumbc0hh3ffs6jtqywibylibs6nkh0tqj4eauwzbkicot8ibspmaqh3qtvt724riwdfwre3veibzaoqcosbd9nctlgqhc 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">com.example.MyAutoConfiguration</span><span leaf=""><br></span></code></pre> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">7.3 项目结构</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">完整的项目结构如下:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg wjibwkqn1bumbc0hh3ffs6jtqywibylibs6nkh0tqj4eauwzbkicot8ibspmaqh3qtvt724riwdfwre3veibzaoqcosbd9nctlgqhc 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span leaf="">myproject/</span><span leaf=""><br></span><span leaf="">├── src/</span><span leaf=""><br></span><span leaf="">│ &nbsp; └── main/</span><span leaf=""><br></span><span leaf="">│ &nbsp; &nbsp; &nbsp; ├── java/</span><span leaf=""><br></span><span leaf="">│ &nbsp; &nbsp; &nbsp; │ &nbsp; └── com/</span><span leaf=""><br></span><span leaf="">│ &nbsp; &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; └── example/</span><span leaf=""><br></span><span leaf="">│ &nbsp; &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ├── MyProperties.java</span><span leaf=""><br></span><span leaf="">│ &nbsp; &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ├── MyService.java</span><span leaf=""><br></span><span leaf="">│ &nbsp; &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ├── MyServiceImpl.java</span><span leaf=""><br></span><span leaf="">│ &nbsp; &nbsp; &nbsp; │ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; └── MyAutoConfiguration.java</span><span leaf=""><br></span><span leaf="">│ &nbsp; &nbsp; &nbsp; └── resources/</span><span leaf=""><br></span><span leaf="">│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; └── META-INF/</span><span leaf=""><br></span><span leaf="">│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; └── spring/</span><span leaf=""><br></span><span leaf="">│ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; └── org.springframework.boot.autoconfigure.AutoConfiguration.imports</span><span leaf=""><br></span><span leaf="">└── pom.xml</span><span leaf=""><br></span></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;"><span style="display: none;"></span><span style="font-size: 20px;color: rgb(53, 179, 120);line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">8. 性能对比</span></span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">在一个典型的中型SpringBoot应用中,使用新机制后的启动性能对比:</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/7f2160d4c749613727b46892949e3b18.png" class="rich_pages wxw-img" data-ratio="0.2879858657243816" data-type="png" data-w="566" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;" data-imgfileid="100079136"></span> </figure> <blockquote style="margin-top: 20px;margin-bottom: 20px;margin-left: 0px;margin-right: 0px;padding-top: 10px;padding-bottom: 10px;padding-left: 20px;padding-right: 10px;border-top-style: none;border-bottom-style: none;border-left-style: solid;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgb(53, 179, 120);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;background-attachment: scroll;background-clip: border-box;background-color: rgb(251, 249, 253);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;display: block;overflow-x: auto;overflow-y: auto;"> <span style="display: none;color: rgb(0, 0, 0);font-size: 16px;line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: normal;"></span> <p style="text-indent: 0em;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;margin-top: 0px;margin-right: 0px;margin-bottom: 0px;margin-left: 0px;"><span leaf="">注:实际性能提升取决于项目规模和结构</span></p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;"><span style="display: none;"></span><span style="font-size: 20px;color: rgb(53, 179, 120);line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">9. 常见问题与解决方案</span></span><span style="display: none;"></span></h3> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">9.1 兼容性问题</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">问题:现有的依赖库仍使用spring.factories,会有兼容问题吗?</span></strong></p> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">解决方案:SpringBoot 3.0保留了对</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">的支持,旧的库仍然可以正常工作。但新的代码应该使用新机制。</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">9.2 迁移困难</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">问题:大型项目迁移到新机制工作量大</span></strong></p> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">解决方案:可以分阶段迁移,先迁移自动配置类,再逐步迁移其他扩展点。</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">9.3 自定义加载器</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">问题:自定义的SpringFactoriesLoader使用者如何迁移?</span></strong></p> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">解决方案:参考SpringBoot的新实现,为自定义扩展点提供类似的imports文件加载机制。</span></p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;"><span style="display: none;"></span><span style="font-size: 20px;color: rgb(53, 179, 120);line-height: 1.5em;letter-spacing: 0em;font-weight: bold;display: block;"><span leaf="">10. SpringBoot 3.0与GraalVM集成</span></span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">SpringBoot 3.0对GraalVM的支持是取消</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">的主要原因之一。</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">10.1 GraalVM简介</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">GraalVM是一个高性能的JDK实现,它的一个重要特性是能够将Java应用编译成独立的原生可执行文件(</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">Native Image</span></code><span leaf="">)。这些原生镜像具有以下特点:</span></p> <ul style="list-style-type: disc;margin-top: 8px;margin-bottom: 8px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 25px;padding-right: 0px;color: rgb(0, 0, 0);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">快速启动:</span></strong><span leaf="">&nbsp;启动时间通常在毫秒级,比传统JVM应用快10-100倍</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">低内存占用:</span></strong><span leaf="">&nbsp;内存占用显著降低,适合云原生和容器环境</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">无需JVM:</span></strong><span leaf="">&nbsp;可以独立运行,不需要Java运行时环境</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">预先编译:</span></strong><span leaf="">&nbsp;所有代码在构建时就编译为机器码,而非运行时编译</span> </section></li> </ul> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">10.2 SpringBoot对GraalVM的支持挑战</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">SpringBoot框架面临的主要挑战是其动态特性与GraalVM静态分析模型之间的矛盾:</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/f06920ad85d4a80935a544656bb809e1.png" class="rich_pages wxw-img" data-ratio="0.4121306376360809" data-type="png" data-w="643" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;" data-imgfileid="100079137"></span> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">10.3 imports文件与GraalVM的兼容性</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">新的imports文件机制解决了与GraalVM集成的关键问题:</span></p> <ul style="list-style-type: disc;margin-top: 8px;margin-bottom: 8px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 25px;padding-right: 0px;color: rgb(0, 0, 0);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">静态可分析性:</span></strong><span leaf="">&nbsp;imports文件中明确列出所有配置类,可以在构建时静态分析</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">路径明确性:</span></strong><span leaf="">&nbsp;每种扩展点对应特定的文件路径,减少了运行时扫描</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">更少的反射:</span></strong><span leaf="">&nbsp;imports文件的解析机制更简单,减少了对反射的依赖</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">构建时处理:</span></strong><span leaf="">&nbsp;可以在AOT编译阶段处理imports文件并生成相应的元数据</span> </section></li> </ul> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">10.4 SpringBoot AOT引擎</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">为了更好地支持GraalVM,SpringBoot 3.0引入了一个新的AOT引擎,它在构建时执行以下操作:</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg wjibwkqn1bumbc0hh3ffs6jtqywibylibs6nkh0tqj4eauwzbkicot8ibspmaqh3qtvt724riwdfwre3veibzaoqcosbd9nctlgqhc 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// SpringBoot 3.0 AOT处理示例</span></span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">class</span></span><span leaf="">&nbsp;</span><span style="color: #e6c07b;line-height: 26px;"><span leaf="">SpringAotProcessor</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span leaf="">&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">void</span></span><span leaf="">&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">process</span></span><span style="line-height: 26px;"><span leaf="">()</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 1. 读取imports文件而非扫描spring.factories</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; List <string> configurations = readImportsFiles(); </string></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 2. 预先评估条件而非运行时评估</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; List <string> effectiveConfigurations =&nbsp; </string></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; evaluateConditions(configurations, buildTimeProperties);</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 3. 生成代理类而非运行时动态生成</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; generateProxies(effectiveConfigurations);</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 4. 生成反射配置</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; generateReflectionConfig(effectiveConfigurations);</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 5. 生成资源配置</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; generateResourcesConfig();</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; }</span><span leaf=""><br></span><span leaf="">}</span><span leaf=""><br></span></code></pre> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">10.5 GraalVM集成实例</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">下面是一个完整的示例,展示如何在SpringBoot 3.0项目中配置和构建GraalVM原生镜像:</span></p> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">Maven配置</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg wjibwkqn1bumbc0hh3ffs6jtqywibylibs6nkh0tqj4eauwzbkicot8ibspmaqh3qtvt724riwdfwre3veibzaoqcosbd9nctlgqhc 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">dependencies</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">dependency</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">groupId</span></span><span leaf="">&gt;</span></span><span leaf="">org.springframework.boot</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">groupId</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">artifactId</span></span><span leaf="">&gt;</span></span><span leaf="">spring-boot-starter</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">artifactId</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">dependency</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">dependency</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">groupId</span></span><span leaf="">&gt;</span></span><span leaf="">org.springframework.experimental</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">groupId</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">artifactId</span></span><span leaf="">&gt;</span></span><span leaf="">spring-native</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">artifactId</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">version</span></span><span leaf="">&gt;</span></span><span leaf="">${spring-native.version}</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">version</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">dependency</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">dependencies</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf=""><br></span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">build</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">plugins</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">plugin</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">groupId</span></span><span leaf="">&gt;</span></span><span leaf="">org.springframework.boot</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">groupId</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">artifactId</span></span><span leaf="">&gt;</span></span><span leaf="">spring-boot-maven-plugin</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">artifactId</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">configuration</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">image</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">builder</span></span><span leaf="">&gt;</span></span><span leaf="">paketobuildpacks/builder:tiny</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">builder</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">env</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">BP_NATIVE_IMAGE</span></span><span leaf="">&gt;</span></span><span leaf="">true</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">BP_NATIVE_IMAGE</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">env</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">image</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">configuration</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">plugin</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">plugin</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">groupId</span></span><span leaf="">&gt;</span></span><span leaf="">org.springframework.experimental</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">groupId</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">artifactId</span></span><span leaf="">&gt;</span></span><span leaf="">spring-aot-maven-plugin</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">artifactId</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">executions</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">execution</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">id</span></span><span leaf="">&gt;</span></span><span leaf="">generate</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">id</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">goals</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf="">&lt;</span><span style="color: #e06c75;line-height: 26px;"><span leaf="">goal</span></span><span leaf="">&gt;</span></span><span leaf="">generate</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">goal</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">goals</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">execution</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">executions</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">plugin</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">plugins</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span><span style="line-height: 26px;"><span leaf=""><!--/</span--><span style="color: #e06c75;line-height: 26px;"><span leaf="">build</span></span><span leaf="">&gt;</span></span><span leaf=""><br></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">自动配置迁移示例</span></p> <pre data-tool="mdnice编辑器" style="border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;text-align: left;margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;"><span data-cacheurl="" data-remoteid="" style="display: block;background: none;height: 30px;width: 100%;background-size: 40px;background-repeat: no-repeat;background-color: #282c34;margin-bottom: -7px;border-radius: 5px;background-position: 10px 10px;background-image: url(" https: mmbiz.qpic.cn mmbiz_svg wjibwkqn1bumbc0hh3ffs6jtqywibylibs6nkh0tqj4eauwzbkicot8ibspmaqh3qtvt724riwdfwre3veibzaoqcosbd9nctlgqhc 640?wx_fmt="svg&amp;from=appmsg&quot;);&quot;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;padding-top: 15px;background: #282c34;border-radius: 5px;display: -webkit-box;font-family: Consolas, Monaco, Menlo, monospace;font-size: 12px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 旧的方式 - spring.factories配置:</span></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// META-INF/spring.factories:</span></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.MyNativeCompatibleConfig</span></span><span leaf=""><br></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 新的方式 - imports文件:</span></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports:</span></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// com.example.MyNativeCompatibleConfig</span></span><span leaf=""><br></span><span leaf=""><br></span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// 自动配置类</span></span><span leaf=""><br></span><span style="color: #61aeee;line-height: 26px;"><span leaf="">@AutoConfiguration</span></span><span leaf=""><br></span><span style="color: #61aeee;line-height: 26px;"><span leaf="">@NativeHint</span></span><span leaf="">(options =&nbsp;</span><span style="color: #98c379;line-height: 26px;"><span leaf="">"--enable-url-protocols=http"</span></span><span leaf="">)&nbsp;</span><span style="color: #5c6370;font-style: italic;line-height: 26px;"><span leaf="">// GraalVM特定的提示</span></span><span leaf=""><br></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">class</span></span><span leaf="">&nbsp;</span><span style="color: #e6c07b;line-height: 26px;"><span leaf="">MyNativeCompatibleConfig</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">@Bean</span></span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp;&nbsp;</span><span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;"><span leaf="">public</span></span><span leaf="">&nbsp;MyService&nbsp;</span><span style="color: #61aeee;line-height: 26px;"><span leaf="">myService</span></span><span style="line-height: 26px;"><span leaf="">()</span></span><span leaf="">&nbsp;</span></span><span leaf="">{</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;</span><span style="color: #c678dd;line-height: 26px;"><span leaf="">return</span></span><span style="color: #c678dd;line-height: 26px;"><span leaf="">new</span></span><span leaf="">&nbsp;MyNativeCompatibleService();</span><span leaf=""><br></span><span leaf="">&nbsp; &nbsp; }</span><span leaf=""><br></span><span leaf="">}</span><span leaf=""><br></span></code></pre> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">10.6 性能对比:传统JVM vs GraalVM原生镜像</span></span><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">使用新的imports机制后,SpringBoot应用在GraalVM原生镜像中的性能表现:</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <span leaf=""><img src="/upload/33fdbfeb68bd927841732d0cb7ad1095.png" class="rich_pages wxw-img" data-ratio="0.32792207792207795" data-type="png" data-w="616" style="display: block;margin-top: 0px;margin-right: auto;margin-bottom: 0px;margin-left: auto;max-width: 100%;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;object-fit: fill;box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px;" data-imgfileid="100079143"></span> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">10.7 GraalVM集成的最佳实践</span></span><span style="display: none;"></span></h4> <ul style="list-style-type: disc;margin-top: 8px;margin-bottom: 8px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 25px;padding-right: 0px;color: rgb(0, 0, 0);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">减少反射使用:</span></strong><span leaf="">&nbsp;尽量使用构造函数注入而非字段注入</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">避免动态代理:</span></strong><span leaf="">&nbsp;减少使用需要动态代理的特性</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">静态初始化:</span></strong><span leaf="">&nbsp;在构建时初始化静态数据而非运行时</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">使用imports文件:</span></strong><span leaf="">&nbsp;确保所有配置类都通过imports文件注册</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">添加必要的提示:</span></strong><span leaf="">&nbsp;使用</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">@NativeHint</span></code><span leaf="">等注解提供GraalVM所需的提示</span> </section></li> </ul> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;display: block;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;text-align: left;font-weight: bold;display: block;"><span leaf="">10.8 GraalVM集成的限制和注意事项</span></span><span style="display: none;"></span></h4> <ul style="list-style-type: disc;margin-top: 8px;margin-bottom: 8px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 25px;padding-right: 0px;color: rgb(0, 0, 0);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">动态特性受限:</span></strong><span leaf="">&nbsp;诸如运行时生成字节码、动态加载类等特性在原生镜像中受限</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">反射使用:</span></strong><span leaf="">&nbsp;必须明确声明使用反射的类</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">构建时间:</span></strong><span leaf="">&nbsp;原生镜像构建时间较长,需要合理规划CI/CD流程</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">调试复杂度:</span></strong><span leaf="">&nbsp;原生镜像的调试比传统JVM更复杂</span> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;font-weight: normal;"> <strong style="color: rgb(53, 179, 120);font-weight: bold;background-attachment: scroll;background-clip: border-box;background-color: rgba(0, 0, 0, 0);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 0px;padding-bottom: 0px;padding-left: 0px;padding-right: 0px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgba(0, 0, 0, 0.4);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 0px;border-top-right-radius: 0px;border-bottom-right-radius: 0px;border-bottom-left-radius: 0px;"><span leaf="">第三方库兼容性:</span></strong><span leaf="">&nbsp;某些依赖可能尚未针对GraalVM优化</span> </section></li> </ul> <p data-tool="mdnice编辑器" style="color: rgb(89, 89, 89);font-size: 15px;line-height: 1.8em;letter-spacing: 0.04em;text-align: left;text-indent: 0em;margin-top: 0px;margin-bottom: 0px;margin-left: 0px;margin-right: 0px;padding-top: 8px;padding-bottom: 8px;padding-left: 0px;padding-right: 0px;"><span leaf="">通过取消</span><code style="color: rgb(30, 107, 184);font-size: 14px;line-height: 1.8em;letter-spacing: 0em;background-attachment: scroll;background-clip: border-box;background-color: rgba(27, 31, 35, 0.05);background-image: none;background-origin: padding-box;background-position-x: 0%;background-position-y: 0%;background-repeat: no-repeat;background-size: auto;width: auto;height: auto;margin-top: 0px;margin-bottom: 0px;margin-left: 2px;margin-right: 2px;padding-top: 2px;padding-bottom: 2px;padding-left: 4px;padding-right: 4px;border-top-style: none;border-bottom-style: none;border-left-style: none;border-right-style: none;border-top-width: 3px;border-bottom-width: 3px;border-left-width: 3px;border-right-width: 3px;border-top-color: rgb(0, 0, 0);border-bottom-color: rgba(0, 0, 0, 0.4);border-left-color: rgba(0, 0, 0, 0.4);border-right-color: rgba(0, 0, 0, 0.4);border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;overflow-wrap: break-word;font-family: Consolas, Monaco, Menlo, monospace;word-break: break-all;"><span leaf="">spring.factories</span></code><span leaf="">并引入新的imports文件机制,SpringBoot 3.0显著改善了与GraalVM的集成体验,让开发者能够更容易地构建高性能、低延迟的云原生应用。</span></p> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" data-pm-slice="0 0 []" style="-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px 10px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;word-spacing: 0em;-webkit-text-stroke-width: 0px;white-space: normal;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(0, 0, 0, 0);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;width: auto;font-family: Optima, " microsoft yahei, pingfangsc-regular, serif;font-size: 16px;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;word-break: break-word;text-align: left;visibility: visible;> <p style="-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;clear: both;min-height: 1em;text-indent: 0px;text-align: center;"><span leaf="" mpa-font-style="m872towr1o29" style="-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-transform: none;widows: 2;word-spacing: 0em;-webkit-text-stroke-width: 0px;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(0, 0, 0, 0);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-family: Optima, " microsoft yahei, pingfangsc-regular, serif;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;word-break: break-word;visibility: visible;clear: both;min-height: 1em;text-indent: 0px;text-align: center;font-size: 12px;><span textstyle="" style="color: rgb(136, 136, 136);">来源</span></span><span leaf="" mpa-font-style="m872towr1o29" style="-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-transform: none;widows: 2;word-spacing: 0em;-webkit-text-stroke-width: 0px;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(0, 0, 0, 0);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-family: Optima, " microsoft yahei, pingfangsc-regular, serif;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;word-break: break-word;visibility: visible;clear: both;min-height: 1em;text-indent: 0px;text-align: center;font-size: 12px;box-sizing: border-box !important;overflow-wrap: break-word !important;><span textstyle="" style="color: rgb(136, 136, 136);">:</span></span><span leaf="" style="-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-transform: none;widows: 2;word-spacing: 0em;-webkit-text-stroke-width: 0px;background: none 0% 0% / auto no-repeat scroll padding-box border-box rgba(0, 0, 0, 0);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-family: Optima, " microsoft yahei, pingfangsc-regular, serif;color: rgb(0, 0, 0);line-height: 1.5em;letter-spacing: 0em;word-break: break-word;visibility: visible;clear: both;min-height: 1em;text-indent: 0px;text-align: center;font-size: 12px;box-sizing: border-box !important;overflow-wrap: break-word !important;><span textstyle="" style="color: rgb(136, 136, 136);">blog.csdn.net/AWen_Jack/article/details/146455281</span></span></p> </section> <figure data-tool="mdnice编辑器" style="-webkit-tap-highlight-color: transparent;margin: 10px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;orphans: 2;text-indent: 0px;text-transform: none;widows: 2;-webkit-text-stroke-width: 0px;white-space: normal;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;font-size: 16px;text-align: left;color: rgb(53, 53, 53);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, " pingfang sc, cambria, cochin, georgia, times, times new roman, serif;letter-spacing: 0.8px;word-spacing: 0.8px;background-color: rgb(255, 255, 255);display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;> <figure data-tool="mdnice编辑器" style="-webkit-tap-highlight-color: transparent;margin: 10px 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;letter-spacing: 0.8px;word-spacing: 0.8px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <em style="-webkit-tap-highlight-color: transparent;margin: 0px;padding: 0px;outline: 0px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;font-style: italic;font-family: -apple-system, BlinkMacSystemFont, " helvetica neue, pingfang sc, hiragino sans gb, microsoft yahei ui, yahei, arial, sans-serif;text-align: right;word-spacing: 0.8px;color: rgb(136, 136, 136);font-size: 12px;letter-spacing: 0.5px;visibility: visible;></em> </figure> </figure>

货拉拉压测平台的建设与实践

作者:微信小助手

<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 15px;padding-left: 15px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, " pingfang sc, cambria, cochin, georgia, times, times new roman, serif;> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;border-left-color: rgba(0, 0, 0, 0.4);background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">作者简介:</p> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">魏占飞,来自货拉拉/技术中心/质量保障部,负责货拉拉性能测试领域的质量保障和效能建设工作。</p> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">李鹏飞,来自货拉拉/技术中心/质量保障部,负责货拉拉货运性能压测保障和效能建设工作。</p> </blockquote> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>一、背景与挑战</h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在过去的几年里,货拉拉的用户和货运订单数量都实现了快速增长,系统稳定性的保障愈发重要,性能测试及全链路压测的测试频率加快,主流性能测试工具均为本地单机软件,存在性能测试过程的效率、协作、数据保存等问题,需要一个高性能的性能测试平台来提供相关能力。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">对于平台实现,需要满足以下主要的要求。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>分布式压测机:</strong> 需要避免压测机的Master/Slave模式,以便保持实现压测机平等以实现快速动态扩容及减少通信压力。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>提高压测效率:</strong> 提供包含了脚本维护,办公协作,场景化压测相关流程,通过资源、脚本、场景的权限内共享,实现及时、高效的全链路压测。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>保障平台性能:</strong> 压测所产生的大量数据,需要及时收集、分析并展示到性能平台上,因此,需要保障压测性能相关性能,保障系统能实时高效地展现性能数据。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>二、方案与目标</h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在构思初始方案时,我们在行业内寻找并参考了相关方案设计,在结合对比开源性、工具资料、上手难度后,选择了基于开源的Jmeter的做为压测引擎进行二次开发,结合性能测试的相关实践操作,整体设计框架如下图如示。</p> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100021687" data-ratio="0.37037037037037035" data-s="300,640" src="/upload/41a20c600e34ffd4a1e7eebccfe3fd23.png" data-type="png" data-w="1080" style=""></p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>三、能力建设</h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">压测平台整体能力建设内容较多,我们将以重点功能组件为例,以时间顺利列出相关的思考及相关改进思路。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">功能模块规划图</p> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100021688" data-ratio="0.562962962962963" data-s="300,640" src="/upload/4d2cf322f4ac8c2e8500f70e11eba818.png" data-type="png" data-w="1080" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">代码模块结构图</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><br>├──&nbsp;Dockerfile<br>├──&nbsp;README.md<br>├──&nbsp;pom.xml<br>├──&nbsp;qapt-agent&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//压测机服务<br>├──&nbsp;qapt-agent-base&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//压测机基础类<br>├──&nbsp;qapt-agent-plugin&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//压测机&amp;jmeter插件<br>├──&nbsp;qapt-api&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//管理平台api<br>├──&nbsp;qapt-collector&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//数据收集器<br>├──&nbsp;qapt-hsmart&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//脚本处理<br>├──&nbsp;qapt-monitor&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//数据监控<br>└──&nbsp;springboot-module&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//基础模块<br>&nbsp;&nbsp;&nbsp;&nbsp;├──&nbsp;pom.xml<br>&nbsp;&nbsp;&nbsp;&nbsp;├──&nbsp;springboot-base-boot&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//项目基础&amp;公用类<br>&nbsp;&nbsp;&nbsp;&nbsp;├──&nbsp;springboot-base-msg&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//消息管理<br>&nbsp;&nbsp;&nbsp;&nbsp;├──&nbsp;springboot-mongodb-auth&nbsp;&nbsp;&nbsp;//权限管理<br>&nbsp;&nbsp;&nbsp;&nbsp;├──&nbsp;springboot-mongodb-file&nbsp;&nbsp;&nbsp;//文件管理<br>&nbsp;&nbsp;&nbsp;&nbsp;└──&nbsp;springboot-mongodb-quartz&nbsp;//定时任务<br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>3.1 公共模块<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">基础公共模块是提取比较公共的功能来形成的独立模块,其功能职责比较独立且公用比较多,主要分为基础&amp;公共类及消息管理、权限管理、文件管理及定时任务管理几个主要模块,以基础模块为例需要对Spring的项目进行统一返回处理、统一日志、统一异常处理等操作。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>3.1.1 Jmeter配置元件<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Jmeter为本地软件,如果想放在Spring容器中启动,需要配置相关配置文件放到指定路径公位置并配置Jmeter本地配置文件的路径配置。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #61aeee;line-height: 26px;">@Configuration</span><br><span style="color: #61aeee;line-height: 26px;">@Slf</span>4j<br><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">JmeterFileConfig</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;jmeterHome&nbsp;=&nbsp;FilesUtil.getJarPath(SpringbootMongodbFileApplication<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>)</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(<span style="color: #98c379;line-height: 26px;">"================Jmeter&nbsp;Info====================,JmeterHome:{}"</span>,&nbsp;jmeterHome);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">//主要解决编译调试时与部署时的路径和目录结构不一致的问题</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(jmeterHome.endsWith(<span style="color: #98c379;line-height: 26px;">"lib"</span>))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jmeterHome&nbsp;=&nbsp;FilesUtil.getParentPath(jmeterHome);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #c678dd;line-height: 26px;">else</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(jmeterHome.endsWith(<span style="color: #98c379;line-height: 26px;">"qapt-api"</span>))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jmeterHome&nbsp;=&nbsp;jmeterHome&nbsp;+&nbsp;<span style="color: #98c379;line-height: 26px;">"/src/main/resources"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;jmeterProperties&nbsp;=&nbsp;jmeterHome&nbsp;+&nbsp;File.separator&nbsp;+&nbsp;<span style="color: #98c379;line-height: 26px;">"bin"</span>&nbsp;+&nbsp;File.separator&nbsp;+&nbsp;<span style="color: #98c379;line-height: 26px;">"jmeter.properties"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(<span style="color: #98c379;line-height: 26px;">"================Jmeter&nbsp;Info====================,JmeterHome:{}"</span>,&nbsp;jmeterHome);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JMeterUtils.setJMeterHome(jmeterHome);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JMeterUtils.getProperties(jmeterProperties);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">//设置本地脚本路径</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;localScriptHome&nbsp;=&nbsp;jmeterHome&nbsp;+&nbsp;File.separator&nbsp;+&nbsp;<span style="color: #98c379;line-height: 26px;">"scripts"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JMeterUtils.setProperty(<span style="color: #98c379;line-height: 26px;">"LocalScriptHome"</span>,&nbsp;localScriptHome);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">//配置Jmeter变量</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JMeterUtils.setProperty(<span style="color: #98c379;line-height: 26px;">"search_paths"</span>,&nbsp;jmeterHome&nbsp;+&nbsp;File.separator&nbsp;+&nbsp;<span style="color: #98c379;line-height: 26px;">"lib"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JMeterUtils.setProperty(<span style="color: #98c379;line-height: 26px;">"jmeter.home"</span>,&nbsp;jmeterHome);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FilesUtil.addPath(JMeterUtils.getProperty(<span style="color: #98c379;line-height: 26px;">"search_paths"</span>));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">//日志</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(<span style="color: #98c379;line-height: 26px;">"================Jmeter&nbsp;Bean&nbsp;Started====================="</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>3.1.2 统一日志处理<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">对日志进行统一过滤、加追踪信息、公共打印、监听分析错误日志等功能,以下为监听Jmeter运行日志、并把相关错误信息回传到相关报告的日志队列实现示例代码。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><br><span style="color: #5c6370;font-style: italic;line-height: 26px;">/*<br>日志监听队列,注册日志监听指定文件,并发送日志消息。<br>*/</span><br><span style="color: #61aeee;line-height: 26px;">@Component</span><br><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">LoggerDisruptorQueue</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">final</span>&nbsp;Pattern&nbsp;LOG_PATTERN&nbsp;=&nbsp;Pattern.compile(<span style="color: #98c379;line-height: 26px;">"^(\d{4}-\d{2}-\d{2}&nbsp;\d{2}:\d{2}:\d{2},\d{3})\s+(\w+)\s+([\w\.]+):\s+(.*)$"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;RingBuffer <loggerevent>&nbsp;ringBuffer; <br> <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #61aeee;line-height: 26px;">@Autowired</span> <br>&nbsp;&nbsp;&nbsp;&nbsp;LoggerDisruptorQueue(LoggerEventHandler&nbsp;eventHandler)&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ThreadFactory&nbsp;threadFactory&nbsp;=&nbsp;Executors.defaultThreadFactory(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LoggerEventFactory&nbsp;factory&nbsp;=&nbsp; <span style="color: #c678dd;line-height: 26px;">new</span>&nbsp;LoggerEventFactory(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">int</span>&nbsp;bufferSize&nbsp;=&nbsp; <span style="color: #d19a66;line-height: 26px;">2</span>&nbsp;*&nbsp; <span style="color: #d19a66;line-height: 26px;">1024</span>; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Disruptor <loggerevent>&nbsp;disruptor&nbsp;=&nbsp; <span style="color: #c678dd;line-height: 26px;">new</span>&nbsp;Disruptor&lt;&gt;(factory,&nbsp;bufferSize,&nbsp;threadFactory); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;disruptor.handleEventsWith(eventHandler); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ringBuffer&nbsp;=&nbsp;disruptor.getRingBuffer(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;disruptor.start(); <br>&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">publishEvent</span><span style="line-height: 26px;">(LoggerMessage&nbsp;log)</span>&nbsp;</span>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">long</span>&nbsp;sequence&nbsp;=&nbsp;ringBuffer.next();&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">try</span>&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LoggerEvent&nbsp;event&nbsp;=&nbsp;ringBuffer.get(sequence);&nbsp; <span style="color: #5c6370;font-style: italic;line-height: 26px;">//&nbsp;Get&nbsp;the&nbsp;entry&nbsp;in&nbsp;the&nbsp;Disruptor</span> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;event.setLog(log); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <span style="color: #c678dd;line-height: 26px;">finally</span>&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ringBuffer.publish(sequence); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;} <br> <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">publishEvent</span><span style="line-height: 26px;">(String&nbsp;reportId,&nbsp;String&nbsp;logLine)</span>&nbsp;</span>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Matcher&nbsp;matcher&nbsp;=&nbsp;LOG_PATTERN.matcher(logLine); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(matcher.matches())&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;timestamp&nbsp;=&nbsp;matcher.group( <span style="color: #d19a66;line-height: 26px;">1</span>); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;level&nbsp;=&nbsp;matcher.group( <span style="color: #d19a66;line-height: 26px;">2</span>); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;className&nbsp;=&nbsp;matcher.group( <span style="color: #d19a66;line-height: 26px;">3</span>); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;message&nbsp;=&nbsp;matcher.group( <span style="color: #d19a66;line-height: 26px;">4</span>); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LoggerMessage&nbsp;tempLoggerMessage&nbsp;=&nbsp; <span style="color: #c678dd;line-height: 26px;">new</span>&nbsp;LoggerMessage(message,&nbsp;timestamp,&nbsp; <span style="color: #98c379;line-height: 26px;">""</span>,&nbsp;className,&nbsp;level,&nbsp;reportId); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">long</span>&nbsp;sequence&nbsp;=&nbsp;ringBuffer.next(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">try</span>&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LoggerEvent&nbsp;event&nbsp;=&nbsp;ringBuffer.get(sequence); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;event.setLog(tempLoggerMessage); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <span style="color: #c678dd;line-height: 26px;">finally</span>&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ringBuffer.publish(sequence); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br> <br>&nbsp;&nbsp;&nbsp;&nbsp;} <br> <br>} <br> </loggerevent> </loggerevent></code></pre> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span></h2> <h3 style="margin-top: 30px;margin-bottom: 15px;color: rgb(0, 0, 0);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, " pingfang sc, cambria, cochin, georgia, times, times new roman, serif;letter-spacing: normal;text-align: left;background-color: rgb(255, 255, 255);>3.2 压测机管理</h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, " pingfang sc, cambria, cochin, georgia, times, times new roman, serif;font-size: 16px;letter-spacing: normal;text-align: left;background-color: rgb(255, 255, 255);>压测机管理的最初实现到后期优化,是变动最大的一个模块,从最初的Web程序内运行到后期的命令行运行,从ECS部署到容器实现,都是踩的比较大的坑,分享相关有进行过模块优化的思考及思路。</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>3.2.1 Jmeter引擎<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><span style="color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, " pingfang sc, cambria, cochin, georgia, times, times new roman, serif;font-size: 16px;letter-spacing: normal;text-align: left;background-color: rgb(255, 255, 255);>在最初选择如何实现Jmeter引擎方式时,有Srpingboot容器内启动和命令行启动原生Jmeter程序两种实现的选择,最初的考虑是Web容器内实现可精准控制Jmeter的并发线程,获取数据也可直接在程序内获取,当时选择了Web容器内启动。随着压测活动的增加,发现了两个比较难克服的问题,一是Jmeter在大压力的情况容易引起程序无响应,Web容器内的启动Jmeter引擎容易导致Web容器的通信也会无响应,影响压测停止的成功率; 二是Web依赖的Jar包版本与Jmeter依赖的Jar包冲突问题。后期优化的方案就是服务内启动的Jmeter对象只做脚本预处理为主,压测时用命令行方式来Jmeter。</span></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #5c6370;font-style: italic;line-height: 26px;">/*<br>原生Jmeter的启动方式<br>*/</span><br><span style="color: #61aeee;line-height: 26px;">@Slf</span>4j<br><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">OriginalJmeterService</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;String&nbsp;javaHome&nbsp;=&nbsp;SystemUtil.getJavaRuntimeInfo().getHomeDir();<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;String&nbsp;jmeterHome&nbsp;=&nbsp;FilesUtil.getJarPath(YiapiAgentServerApplication<span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>)</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;String&nbsp;classpath;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;String&nbsp;jarPath;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;ExecutorService&nbsp;executorService&nbsp;=&nbsp;ThreadUtil.newExecutor();<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;ScheduledExecutorService&nbsp;exec&nbsp;=&nbsp;Executors.newScheduledThreadPool(<span style="color: #d19a66;line-height: 26px;">1</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;ScheduledFuture<!--?-->&nbsp;scheduledFuture;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">long</span>&nbsp;lastTimeFileSize&nbsp;=&nbsp;<span style="color: #d19a66;line-height: 26px;">0</span>;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">//上次文件大小</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;String&nbsp;scriptPath&nbsp;=&nbsp;jmeterHome&nbsp;+&nbsp;File.separator&nbsp;+&nbsp;<span style="color: #98c379;line-height: 26px;">"scripts"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;Process&nbsp;process;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">//主要解决编译调试时与部署时的路径和目录结构不一致的问题</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(jmeterHome.endsWith(<span style="color: #98c379;line-height: 26px;">"lib"</span>))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jmeterHome&nbsp;=&nbsp;FilesUtil.getParentPath(jmeterHome);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #c678dd;line-height: 26px;">else</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(jmeterHome.endsWith(<span style="color: #98c379;line-height: 26px;">"classes"</span>))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jmeterHome&nbsp;=&nbsp;FilesUtil.getParentPath(FilesUtil.getParentPath(jmeterHome))&nbsp;+&nbsp;<span style="color: #98c379;line-height: 26px;">"/target/dest"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;classpath&nbsp;=&nbsp;jmeterHome&nbsp;+&nbsp;<span style="color: #98c379;line-height: 26px;">"/jmeter/lib/*"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jarPath&nbsp;=&nbsp;jmeterHome&nbsp;+&nbsp;<span style="color: #98c379;line-height: 26px;">"/jmeter/bin/ApacheJMeter.jar"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;String&nbsp;<span style="color: #61aeee;line-height: 26px;">run</span><span style="line-height: 26px;">(String&nbsp;scriptPath,&nbsp;ScriptDTO&nbsp;scriptDTO)</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">throws</span>&nbsp;IOException&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;reportId&nbsp;=&nbsp;scriptDTO.getReportId();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Report&nbsp;report&nbsp;=&nbsp;scriptDTO.getReport();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;logPath&nbsp;=&nbsp;FilesUtil.getParentPath(scriptPath)&nbsp;+&nbsp;File.separator&nbsp;+&nbsp;<span style="color: #98c379;line-height: 26px;">"jmeter.log"</span>;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(<span style="color: #98c379;line-height: 26px;">"FilesUtil.getParentPath:{}"</span>,&nbsp;logPath);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;cmd&nbsp;=&nbsp;javaHome&nbsp;+&nbsp;<span style="color: #98c379;line-height: 26px;">"/bin/java"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+&nbsp;<span style="color: #98c379;line-height: 26px;">"&nbsp;-Xms4G&nbsp;-Xmx4G"</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+&nbsp;<span style="color: #98c379;line-height: 26px;">"&nbsp;-jar&nbsp;"</span>&nbsp;+&nbsp;getSystemProperties(scriptDTO)&nbsp;+&nbsp;jarPath<br>+&nbsp;<span style="color: #98c379;line-height: 26px;">"&nbsp;-n&nbsp;-t&nbsp;"</span>&nbsp;+&nbsp;scriptPath<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;+&nbsp;<span style="color: #98c379;line-height: 26px;">"&nbsp;-j&nbsp;"</span>&nbsp;+&nbsp;logPath;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(<span style="color: #98c379;line-height: 26px;">"run&nbsp;original&nbsp;jmeter&nbsp;&nbsp;and&nbsp;the&nbsp;cmd&nbsp;is&nbsp;:{}"</span>,&nbsp;cmd);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AgentInfo.setAgentStatus(Agent.AGENT_BUSYING);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;File&nbsp;logFile&nbsp;=&nbsp;FileUtil.newFile(logPath);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;executorService.execute(()&nbsp;-&gt;&nbsp;process&nbsp;=&nbsp;RuntimeUtils.exec(<span style="color: #98c379;line-height: 26px;">"output.log"</span>,&nbsp;cmd));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(report.getType()&nbsp;==&nbsp;Report.REPORT_TYPE_DEBUG)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(scheduledFuture&nbsp;!=&nbsp;<span style="color: #c678dd;line-height: 26px;">null</span>)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scheduledFuture.cancel(<span style="color: #c678dd;line-height: 26px;">true</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scheduledFuture&nbsp;=&nbsp;exec.scheduleWithFixedDelay(()&nbsp;-&gt;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">//创建WatchService实例,并注册要监视的事件类型</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">final</span>&nbsp;RandomAccessFile&nbsp;randomFile;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">try</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;randomFile&nbsp;=&nbsp;<span style="color: #c678dd;line-height: 26px;">new</span>&nbsp;RandomAccessFile(logFile,&nbsp;<span style="color: #98c379;line-height: 26px;">"rw"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #c678dd;line-height: 26px;">catch</span>&nbsp;(FileNotFoundException&nbsp;e)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">throw</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">new</span>&nbsp;RuntimeException(e);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">try</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;randomFile.seek(lastTimeFileSize);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;tmp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">while</span>&nbsp;((tmp&nbsp;=&nbsp;randomFile.readLine())&nbsp;!=&nbsp;<span style="color: #c678dd;line-height: 26px;">null</span>)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;text&nbsp;=&nbsp;<span style="color: #c678dd;line-height: 26px;">new</span>&nbsp;String(tmp.getBytes(StandardCharsets.UTF_8));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LoggerDisruptorQueue.publishEvent(reportId,&nbsp;text);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lastTimeFileSize&nbsp;=&nbsp;randomFile.length();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #c678dd;line-height: 26px;">catch</span>&nbsp;(IOException&nbsp;e)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},&nbsp;<span style="color: #d19a66;line-height: 26px;">0</span>,&nbsp;<span style="color: #d19a66;line-height: 26px;">1</span>,&nbsp;TimeUnit.SECONDS);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">return</span>&nbsp;executorService.toString();<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></code></pre> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>3.2.2 压测机部署<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">压测机最初采用 ECS 集群部署,在达到约 200 台时压测机规模时,其硬件成本已经比较高了,后把压测机改造采用 Serverless Container 弹性容器实例,通过 ASK 竞价申请 POD 资源,1 分钟内可完成 500 台压测机的申请与部署,在申请后,及时进行压测任务后自动或手工释放,使压测机的硬件成本得到了大幅降低。</p> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100021689" data-ratio="0.32407407407407407" data-s="300,640" src="/upload/2d70e0e9de2ada572541f08f90cdb048.png" data-type="png" data-w="1080" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">同时,压测机资源还会根据不同项目、不同申请人、公用、私用等维度进行管理,普通用户可使用自已申请的、当前项目拥有的及公用的压测机进行压测,使压测机资源的综合利用率更高,压测启动后会先把压测任务所需要的压测资源分发到对应权限的空闲压测机中。</p> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100021690" data-ratio="0.34444444444444444" data-s="300,640" src="/upload/877d9059f3b4627889b541bd89447fc7.png" data-type="png" data-w="1080" style=""></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>3.2.3 压测文件处理<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">平台在执行具体的压测任务后,会拆分压测任务的场景、脚本、数据文件及依赖 JAR 包,并按照一定要求把对应的脚本和数据文件分发到对应的目标压测机,这中间涉及到任务的分发,文件的下载与预处理,同时为了避免压测机在各项目之间的文件冲突、数据冲突或 JAR 包冲突,还需要对相关文件做对应处理后放入纯净的压测空间。</p> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100021691" data-ratio="0.4351851851851852" data-s="300,640" src="/upload/bc380d2ec9425ea8869703b77cf3de72.png" data-type="png" data-w="1080" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Jmeter脚本预处理,以检测压测环境是否符合环境要求为例</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #61aeee;line-height: 26px;">@Slf</span>4j<br><span style="color: #61aeee;line-height: 26px;">@Service</span><br><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">JmeterService</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #61aeee;line-height: 26px;">@Autowired</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;JMeterEngines&nbsp;jMeterEngine;<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #61aeee;line-height: 26px;">@Autowired</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;LoggerEventHandler&nbsp;loggerEventHandler;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">boolean</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">hasEnvironmentalRisk</span><span style="line-height: 26px;">(HashTree&nbsp;tree,&nbsp;ScriptDTO&nbsp;scriptDTO)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #5c6370;font-style: italic;line-height: 26px;">//检查默认配置里是否有与当前环境相同</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SearchByClass <configtestelement>&nbsp;configTestElementListeners&nbsp;=&nbsp; <span style="color: #c678dd;line-height: 26px;">new</span>&nbsp;SearchByClass&lt;&gt;(ConfigTestElement <span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>)</span>; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tree.traverse(configTestElementListeners); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Collection <configtestelement>&nbsp;configTestElements&nbsp;=&nbsp;configTestElementListeners.getSearchResults(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #5c6370;font-style: italic;line-height: 26px;">//1.检查配置元件中是否有不符合环境的请求</span> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">for</span>&nbsp;(ConfigTestElement&nbsp;configTestElement&nbsp;:&nbsp;configTestElements)&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(configTestElement.isEnabled())&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;domain&nbsp;=&nbsp;configTestElement.getPropertyAsString( <span style="color: #98c379;line-height: 26px;">"HTTPSampler.domain"</span>); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(!StringUtils.isEmpty(domain))&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;env&nbsp;=&nbsp;scriptDTO.getReport().getEnv(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(!hasDomainContainEnv(domain,&nbsp;env))&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sendStopReportErrorMsg(scriptDTO,&nbsp;domain,&nbsp;configTestElement.getName(),&nbsp;env); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">return</span>&nbsp; <span style="color: #c678dd;line-height: 26px;">true</span>; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #5c6370;font-style: italic;line-height: 26px;">//检查http组件是否有与当前环境相同</span> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SearchByClass <httpsamplerproxy>&nbsp;httpSamplerProxyListeners&nbsp;=&nbsp; <span style="color: #c678dd;line-height: 26px;">new</span>&nbsp;SearchByClass&lt;&gt;(HTTPSamplerProxy <span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>)</span>; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tree.traverse(httpSamplerProxyListeners); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Collection <httpsamplerproxy>&nbsp;httpSamplerProxies&nbsp;=&nbsp;httpSamplerProxyListeners.getSearchResults(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">for</span>&nbsp;(HTTPSamplerProxy&nbsp;http&nbsp;:&nbsp;httpSamplerProxies)&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;domain&nbsp;=&nbsp;http.getPropertyAsString( <span style="color: #98c379;line-height: 26px;">"HTTPSampler.domain"</span>); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;env&nbsp;=&nbsp;scriptDTO.getReport().getEnv(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(!StringUtils.isEmpty(domain))&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(!hasDomainContainEnv(domain,&nbsp;env))&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sendStopReportErrorMsg(scriptDTO,&nbsp;domain,&nbsp;http.getName(),&nbsp;env); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">return</span>&nbsp; <span style="color: #c678dd;line-height: 26px;">true</span>; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">return</span>&nbsp; <span style="color: #c678dd;line-height: 26px;">false</span>; <br>&nbsp;&nbsp;&nbsp;&nbsp;} <br>} <br> </httpsamplerproxy> </httpsamplerproxy> </configtestelement> </configtestelement></code></pre> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>3.2.4 插件管理<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Jmeter的插件管理需要包括了主流的协议如MQTT,gRpc的扩展测试,也有公司内部的自定义协议的支持,包括GUI部分和采样器的支持,需要打好包后下载到本地支持Jmeter的脚本编写,也需要添加到压测机的依赖包进行管理。</p> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100021692" data-ratio="0.6650197628458498" data-s="300,640" src="/upload/78bcf6c016754e4ae93b327b8b0fbb83.png" data-type="png" data-w="1012" style=""></p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>3.3 管理后台<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">压测平台的主要功能和Web界面操作都是和管理后台直接进行通讯和交互,核心功能主要与压测操作业务相关,包括脚本、场景、压测机管理,其中变化较大的是与压测机的通讯方式。除了核心的压测功能,管理后台也支持如监控数据收集、脚本批量操作、自动化配置等一些效率功能。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>3.3.1 脚本管理<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">上传jmeter脚本,在压测平台进行预处理后,可自动生成压测平台的脚本,以脚本维度进行管理与压测,通常单业务的性能测试通常以脚本为单位测试即可。</p> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100021693" data-ratio="0.3416666666666667" data-s="300,640" src="/upload/1fd1ff4916bca5781a0a25b4c80f7a69.png" data-type="png" data-w="1080" style=""></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>3.3.2 场景管理<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在需要多个脚本配合的测试场景中,可提前组合对应的压测场景,并对压测场景的并发压力进行配置和调整,大规模测试如全链路压测需要以场景维度进行测试。</p> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100021694" data-ratio="0.3712962962962963" data-s="300,640" src="/upload/a11bdab09309385c3d6f897fd9afbede.png" data-type="png" data-w="1080" style=""></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>3.3.3 通信协议<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在平台开发初期因主要考虑各环境的网络防火墙的策略,通讯协议采用长链接的WebSocket协议,随着公司网络策略的变化有了专用的测试区,并且随着压测规模的增大,WebSocket协议需要一个专用服务来管理Session链接,管理复杂程度增加,不利于压测平台的水平扩容,所以与压测机的通信方式增加了http通讯方式,原WebSocket只用于压测机的心跳及状态更新及调试日志的上传。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">WebSocket服务端点</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #61aeee;line-height: 26px;">@ServerEndpoint</span>(<span style="color: #98c379;line-height: 26px;">"/ws/{cid}/route/{rid}"</span>)<br><span style="color: #61aeee;line-height: 26px;">@Component</span><br><span style="color: #61aeee;line-height: 26px;">@Slf</span>4j<br><span style="color: #61aeee;line-height: 26px;">@Data</span><br><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">class</span>&nbsp;<span style="color: #e6c07b;line-height: 26px;">WebSocketServer</span>&nbsp;</span>{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #c678dd;line-height: 26px;">private</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;Map <string,&nbsp;websocketservice>&nbsp;webSocketServiceMap; <br> <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #5c6370;font-style: italic;line-height: 26px;">/**<br>*&nbsp;连接建立成功调用的方法<br>*/</span> <br> <span style="color: #61aeee;line-height: 26px;">@OnOpen</span> <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">onOpen</span><span style="line-height: 26px;">(Session&nbsp;session,&nbsp;@PathParam(<span style="color: #98c379;line-height: 26px;">"cid"</span>)</span>&nbsp;String&nbsp;cid,&nbsp;@<span style="color: #61aeee;line-height: 26px;">PathParam</span><span style="line-height: 26px;">(<span style="color: #98c379;line-height: 26px;">"rid"</span>)</span>&nbsp;String&nbsp;rid)&nbsp;</span>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WsSessionManager.add(cid,&nbsp;session); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info( <span style="color: #98c379;line-height: 26px;">"有新client连接,clientId:{},routeId:{}"</span>,&nbsp;cid,&nbsp;rid); <br>&nbsp;&nbsp;&nbsp;&nbsp;} <br> <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #5c6370;font-style: italic;line-height: 26px;">/**<br>*&nbsp;连接关闭调用的方法<br>*/</span> <br> <span style="color: #61aeee;line-height: 26px;">@OnClose</span> <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">onClose</span><span style="line-height: 26px;">(@PathParam(<span style="color: #98c379;line-height: 26px;">"cid"</span>)</span>&nbsp;String&nbsp;cid,&nbsp;@<span style="color: #61aeee;line-height: 26px;">PathParam</span><span style="line-height: 26px;">(<span style="color: #98c379;line-height: 26px;">"rid"</span>)</span>&nbsp;String&nbsp;rid)&nbsp;</span>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WsSessionManager.removeAndClose(cid); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WsSessionManager.removeAndClose(rid); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AgentServiceImpl&nbsp;agentService&nbsp;=&nbsp;SpringContextUtils.getBean(AgentServiceImpl <span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>)</span>; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(!cid.startsWith(WsSessionManager.WEB_CLIENT))&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;agentService.setOffOnline(cid); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;} <br> <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #5c6370;font-style: italic;line-height: 26px;">/**<br>*&nbsp;收到客户端消息后调用的方法<br>*<br>*&nbsp;<span style="color: #c678dd;line-height: 26px;">@param</span>&nbsp;message&nbsp;客户端发送过来的消息<br>*/</span> <br> <span style="color: #61aeee;line-height: 26px;">@OnMessage</span> <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">onMessage</span><span style="line-height: 26px;">(@PathParam(<span style="color: #98c379;line-height: 26px;">"cid"</span>)</span>&nbsp;String&nbsp;cid,&nbsp;String&nbsp;message)&nbsp;</span>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;( <span style="color: #c678dd;line-height: 26px;">null</span>&nbsp;==&nbsp;webSocketServiceMap)&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;webSocketServiceMap&nbsp;=&nbsp;SpringContextUtils.getBeans(WebSocketService <span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>)</span>; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.debug( <span style="color: #98c379;line-height: 26px;">"session:{},&nbsp;message:{}"</span>,&nbsp;cid,&nbsp;message); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WsMsg&nbsp;msg; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #5c6370;font-style: italic;line-height: 26px;">//解析消息</span> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">try</span>&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;msg&nbsp;=&nbsp;JSON.parseObject(message).toJavaObject(WsMsg <span style="line-height: 26px;">.<span style="color: #c678dd;line-height: 26px;">class</span>)</span>; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;uuid&nbsp;=&nbsp;msg.getUuid(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(WsSessionManager.futureCache.asMap().containsKey(uuid))&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SyncFuture&nbsp;syncFuture&nbsp;=&nbsp;WsSessionManager.futureCache.get(uuid); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;syncFuture.setResponse(message); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <span style="color: #c678dd;line-height: 26px;">catch</span>&nbsp;(JSONException&nbsp;e)&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.error(e.toString()); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">return</span>; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <span style="color: #c678dd;line-height: 26px;">catch</span>&nbsp;(ExecutionException&nbsp;e)&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">throw</span>&nbsp; <span style="color: #c678dd;line-height: 26px;">new</span>&nbsp;RuntimeException(e); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #5c6370;font-style: italic;line-height: 26px;">//执行消息动作</span> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">try</span>&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">if</span>&nbsp;(webSocketServiceMap.containsKey(msg.getAction()))&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;webSocketServiceMap.get(msg.getAction()).execute(msg,&nbsp;cid); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <span style="color: #c678dd;line-height: 26px;">else</span>&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.error( <span style="color: #98c379;line-height: 26px;">"this&nbsp;is&nbsp;no&nbsp;handler&nbsp;for&nbsp;this&nbsp;msg's&nbsp;action:{}"</span>,&nbsp;msg.getAction()); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <span style="color: #c678dd;line-height: 26px;">catch</span>&nbsp;(Exception&nbsp;e)&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.error( <span style="color: #98c379;line-height: 26px;">"this&nbsp;&nbsp;handler&nbsp;Exception&nbsp;and&nbsp;the&nbsp;msg's&nbsp;action:{}"</span>,&nbsp;msg.getAction()); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;} <br> <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #61aeee;line-height: 26px;">@OnError</span> <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">onError</span><span style="line-height: 26px;">(@PathParam(<span style="color: #98c379;line-height: 26px;">"cid"</span>)</span>&nbsp;String&nbsp;cid,&nbsp;@<span style="color: #61aeee;line-height: 26px;">PathParam</span><span style="line-height: 26px;">(<span style="color: #98c379;line-height: 26px;">"rid"</span>)</span>&nbsp;String&nbsp;rid,&nbsp;Throwable&nbsp;e)&nbsp;</span>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WsSessionManager.removeAndClose(cid); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WsSessionManager.removeAndClose(rid); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.error( <span style="color: #98c379;line-height: 26px;">"webSocket&nbsp;client&nbsp;is&nbsp;error,cid&nbsp;is&nbsp;:{}&nbsp;and&nbsp;rid&nbsp;is&nbsp;:{},the&nbsp;reason&nbsp;is&nbsp;:{}"</span>,&nbsp;cid,&nbsp;rid,&nbsp;e.getMessage()); <br>&nbsp;&nbsp;&nbsp;&nbsp;} <br> <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">sendMessage</span><span style="line-height: 26px;">(String&nbsp;message,&nbsp;String&nbsp;cid)</span>&nbsp;</span>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info( <span style="color: #98c379;line-height: 26px;">"send&nbsp;msg&nbsp;to&nbsp;cid:{},and&nbsp;msg&nbsp;is&nbsp;{}"</span>,&nbsp;cid,&nbsp;message); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">try</span>&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WsSessionManager.get(cid).getBasicRemote().sendText(message); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <span style="color: #c678dd;line-height: 26px;">catch</span>&nbsp;(IOException&nbsp;e)&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.error( <span style="color: #98c379;line-height: 26px;">"send&nbsp;msg&nbsp;to&nbsp;cid:{},but&nbsp;can't&nbsp;find&nbsp;the&nbsp;cid&nbsp;session,the&nbsp;message&nbsp;is:{}"</span>,&nbsp;cid,&nbsp;message); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br> <br>&nbsp;&nbsp;&nbsp;&nbsp;} <br> <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;String&nbsp;<span style="color: #61aeee;line-height: 26px;">sendSyncMsg</span><span style="line-height: 26px;">(WsMsg&nbsp;wsMsg,&nbsp;String&nbsp;cid)</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">throws</span>&nbsp;InterruptedException&nbsp;</span>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SyncFuture <string>&nbsp;syncFuture&nbsp;=&nbsp; <span style="color: #c678dd;line-height: 26px;">new</span>&nbsp;SyncFuture&lt;&gt;(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #5c6370;font-style: italic;line-height: 26px;">//&nbsp;放入缓存中</span> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;dataId&nbsp;=&nbsp;wsMsg.getUuid(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WsSessionManager.futureCache.put(dataId,&nbsp;syncFuture); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #5c6370;font-style: italic;line-height: 26px;">//&nbsp;封装数据</span> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sendMessage(JSON.toJSONString(wsMsg),&nbsp;cid); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #5c6370;font-style: italic;line-height: 26px;">//&nbsp;发送同步消息</span> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">return</span>&nbsp;syncFuture.get( <span style="color: #d19a66;line-height: 26px;">1</span>,&nbsp;TimeUnit.SECONDS); <br>&nbsp;&nbsp;&nbsp;&nbsp;} <br> <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #5c6370;font-style: italic;line-height: 26px;">/**<br>*&nbsp;指定cid发送消息<br>*/</span> <br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">sendMessageToCid</span><span style="line-height: 26px;">(String&nbsp;message,&nbsp;String&nbsp;cid)</span>&nbsp;</span>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sendMessage(message,&nbsp;cid); <br>&nbsp;&nbsp;&nbsp;&nbsp;} <br> <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #5c6370;font-style: italic;line-height: 26px;">/**<br>*&nbsp;指定cids发送消息<br>*/</span> <br> <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">sendMessageToCids</span><span style="line-height: 26px;">(String&nbsp;message,&nbsp;ConcurrentHashSet <string> &nbsp;cids) </string></span>&nbsp;</span>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.debug( <span style="color: #98c379;line-height: 26px;">"push&nbsp;message&nbsp;to&nbsp;cids:"</span>&nbsp;+&nbsp;cids&nbsp;+&nbsp; <span style="color: #98c379;line-height: 26px;">",推送内容:"</span>&nbsp;+&nbsp;message); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cids.forEach(cid&nbsp;-&gt;&nbsp;sendMessage(message,&nbsp;cid)); <br>&nbsp;&nbsp;&nbsp;&nbsp;} <br> <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">boolean</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">checkAgentOnline</span><span style="line-height: 26px;">(String&nbsp;cid)</span>&nbsp;</span>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">return</span>&nbsp;WsSessionManager.existSession(cid); <br>&nbsp;&nbsp;&nbsp;&nbsp;} <br> <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #5c6370;font-style: italic;line-height: 26px;">//清理失效的CID</span> <br>&nbsp;&nbsp;&nbsp;&nbsp; <span style="line-height: 26px;"><span style="color: #c678dd;line-height: 26px;">public</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">static</span>&nbsp;<span style="color: #c678dd;line-height: 26px;">void</span>&nbsp;<span style="color: #61aeee;line-height: 26px;">cleanLoseContactSocket</span><span style="line-height: 26px;">()</span>&nbsp;</span>{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WsMsg&nbsp;wsMsg&nbsp;=&nbsp; <span style="color: #c678dd;line-height: 26px;">new</span>&nbsp;WsMsg(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WsSessionManager.SESSION_POOL_AGENT.forEachKey( <span style="color: #d19a66;line-height: 26px;">10</span>,&nbsp;cid&nbsp;-&gt;&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: #c678dd;line-height: 26px;">try</span>&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sendSyncMsg(wsMsg,&nbsp;cid); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info( <span style="color: #98c379;line-height: 26px;">"check&nbsp;agent:{}&nbsp;websocket&nbsp;online&nbsp;&nbsp;"</span>,&nbsp;cid); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp; <span style="color: #c678dd;line-height: 26px;">catch</span>&nbsp;(InterruptedException&nbsp;e)&nbsp;{ <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WsSessionManager.remove(cid); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.warn( <span style="color: #98c379;line-height: 26px;">"check&nbsp;agent:{}&nbsp;websocket&nbsp;lose&nbsp;and&nbsp;remove&nbsp;the&nbsp;web&nbsp;socket&nbsp;info&nbsp;"</span>,&nbsp;cid); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace(); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); <br>&nbsp;&nbsp;&nbsp;&nbsp;} <br> <br>} <br> </string> </string,&nbsp;websocketservice></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>3.4 收集器<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在全链路压测进行过程中,需要实时关注压测相关指标,及时进行收集和汇总,给压测任务提供数据指标及风险参考,各压测机把自身的压测数据通过监听器实时发送到 Kafka,再由收集服务进行统一汇总,在汇总数据后进行展示或结合其它策略进一步利用。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>3.4.1 压测机单机数据<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">如果把每一条压测数据都发送给到收集器,很容易达到到kafka的消息发送40万~100万QPS的性能瓶颈,压测机把自身单机的数据先收集汇总并每秒发送一次,可以极大减少发送消息的QPS,提高压测平台消息汇总的性能。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>//压测机初步收集汇总本机数据,并发送到kafka</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(97, 174, 238);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>@Slf</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>4j</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>public</span><span style="line-height: 26px;color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;">class</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">HllBackendListenerClient</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">extends</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">AbstractBackendListenerClient</span>&nbsp;</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>{</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(97, 174, 238);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>@Override</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="line-height: 26px;color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">void</span>&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">setupTest</span><span style="line-height: 26px;">(BackendListenerContext&nbsp;backendListenerContext)</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">throws</span>&nbsp;Exception&nbsp;</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>{</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>//压测设置项</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;}</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(97, 174, 238);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>@Override</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="line-height: 26px;color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">void</span>&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">handleSampleResults</span><span style="line-height: 26px;">(List <sampleresult>&nbsp;list,&nbsp;BackendListenerContext&nbsp;backendListenerContext) </sampleresult></span>&nbsp;</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>{</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>//压测数据处理并发送</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;}</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(97, 174, 238);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>@Override</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="line-height: 26px;color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">void</span>&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">teardownTest</span><span style="line-height: 26px;">(BackendListenerContext&nbsp;backendListenerContext)</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">throws</span>&nbsp;Exception&nbsp;</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>{</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;analysis();</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;schedule.shutdown();</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;}</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="line-height: 26px;color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;">private</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">void</span>&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">analysis</span><span style="line-height: 26px;">()</span>&nbsp;</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>{</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>//压测机初步数据统计</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Collector <yisample,&nbsp;samplestate,&nbsp;samplestate>&nbsp;c&nbsp;=&nbsp;Collector.of( </yisample,&nbsp;samplestate,&nbsp;samplestate></span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SampleState::</span><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>new</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>,</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SampleState::accumulator,</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SampleState::combiner,</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SampleState::finisher</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Map <string,&nbsp;samplestate>&nbsp;sampleStateMap&nbsp;=&nbsp;temp.stream() </string,&nbsp;samplestate></span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.collect(Collectors.groupingBy(YiSample::getLabel,&nbsp;c));</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;}</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>}</span></code></pre> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>3.4.2 汇总整体数据<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">收集器收集到各压测机的压测数据后,收集服务的收集器采用每 3 秒收集汇总一次,尽可能保证的数据实时性并减少指标图表的曲率的变化频率,以报告ID的维度把相关压测数据收集汇总,并持久化到数据库中。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;background: #282c34;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>//收集服务消费KAFKA并统一汇总数据</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(97, 174, 238);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>@Slf</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>4j</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>public</span><span style="line-height: 26px;color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;">class</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">AnalysisProcessor</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">implements</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">Processor</span>&lt;<span style="color: rgb(230, 192, 123);line-height: 26px;">String</span>,&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">String</span>&gt;&nbsp;</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>{</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>private</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;ProcessorContext&nbsp;context;</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>private</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;AtomicInteger&nbsp;processorNumber&nbsp;=&nbsp;</span><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>new</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;AtomicInteger();</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;PerformanceRecordRepository&nbsp;performanceRecordRepository&nbsp;=&nbsp;SpringContextUtils.getBean(PerformanceRecordRepository</span><span style="line-height: 26px;color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>.<span style="color: rgb(198, 120, 221);line-height: 26px;">class</span>)</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>;</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;ReportRepository&nbsp;reportRepository&nbsp;=&nbsp;SpringContextUtils.getBean(ReportRepository</span><span style="line-height: 26px;color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>.<span style="color: rgb(198, 120, 221);line-height: 26px;">class</span>)</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>;</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>private</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;ConcurrentHashMap <string,&nbsp;list> <samplestate>&gt;&nbsp;sampleMap&nbsp;=&nbsp; </samplestate> </string,&nbsp;list></span><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>new</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;ConcurrentHashMap&lt;&gt;();</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(97, 174, 238);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>@Override</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="line-height: 26px;color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">void</span>&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">init</span><span style="line-height: 26px;">(ProcessorContext&nbsp;context)</span>&nbsp;</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>{</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>//1.初始化</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>this</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>.context&nbsp;=&nbsp;context;</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;processorNumber.getAndIncrement();</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>if</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;(processorNumber.get()&nbsp;&lt;=&nbsp;</span><span style="color: rgb(209, 154, 102);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>1</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>)&nbsp;{</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>this</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>.context.schedule(Report.REPORT_INTERVAL,&nbsp;PunctuationType.WALL_CLOCK_TIME,&nbsp;(timeStamp)&nbsp;-&gt;&nbsp;analysis());</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(</span><span style="color: rgb(152, 195, 121);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>"init&nbsp;AnalysisProcessor"</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>);</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;}</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(97, 174, 238);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>@Override</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="line-height: 26px;color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">void</span>&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">process</span><span style="line-height: 26px;">(String&nbsp;key,&nbsp;String&nbsp;message)</span>&nbsp;</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>{</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>//2.压测数据处理</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SampleState&nbsp;sampleState&nbsp;=&nbsp;JSON.parseObject(message,&nbsp;SampleState</span><span style="line-height: 26px;color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>.<span style="color: rgb(198, 120, 221);line-height: 26px;">class</span>)</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>;</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>if</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;(!sampleMap.containsKey(key))&nbsp;{</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List <samplestate>&nbsp;list&nbsp;=&nbsp; </samplestate></span><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>new</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;ArrayList&lt;&gt;();</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sampleMap.put(key,&nbsp;list);</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sampleMap.get(key).add(sampleState);</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;}</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(97, 174, 238);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>@Override</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="line-height: 26px;color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">void</span>&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">close</span><span style="line-height: 26px;">()</span>&nbsp;</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>{</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;}</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="line-height: 26px;color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;">private</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">void</span>&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">analysis</span><span style="line-height: 26px;">()</span>&nbsp;</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>{</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sampleMap.forEach((reportId,&nbsp;sampleStates)&nbsp;-&gt;&nbsp;{</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>if</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;(sampleStates.size()&nbsp;==&nbsp;</span><span style="color: rgb(209, 154, 102);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>0</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>)&nbsp;{</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sampleMap.remove(reportId);</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>long</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;start&nbsp;=&nbsp;System.currentTimeMillis();</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Collector <samplestate,&nbsp;performancerecordstate,&nbsp;performancerecord>&nbsp;c&nbsp;=&nbsp;Collector.of( </samplestate,&nbsp;performancerecordstate,&nbsp;performancerecord></span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerformanceRecordState::</span><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>new</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>,</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerformanceRecordState::accumulator,</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerformanceRecordState::combiner,</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerformanceRecordState::finisher</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;);</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>//汇总性能数据</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Map <string,&nbsp;performancerecord>&nbsp;reportRecord&nbsp;=&nbsp;sampleStates.stream() </string,&nbsp;performancerecord></span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.collect(Collectors.groupingBy(SampleState::getLabel,&nbsp;c));</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AtomicInteger&nbsp;i&nbsp;=&nbsp;</span><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>new</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;AtomicInteger();</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reportRecord.forEach((label,&nbsp;record)&nbsp;-&gt;&nbsp;{</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerformanceRecord&nbsp;saveRecord&nbsp;=&nbsp;performanceRecordRepository.save(record);</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;i.getAndAdd((</span><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>int</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>)&nbsp;saveRecord.getN());</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(</span><span style="color: rgb(152, 195, 121);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>"analysis&nbsp;report:{}&nbsp;once,it&nbsp;has&nbsp;{}&nbsp;record&nbsp;,and&nbsp;{}&nbsp;samples&nbsp;,used:{}ms&nbsp;"</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>,&nbsp;reportId,&nbsp;sampleStates.size(),&nbsp;i.get(),&nbsp;(System.currentTimeMillis()&nbsp;-&nbsp;start));</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(92, 99, 112);font-style: italic;line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>//清空此批数据</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(198, 120, 221);line-height: 26px;font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;>if</span><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;(sampleMap.containsKey(reportId))&nbsp;{</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sampleMap.get(reportId).clear();</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;});</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>&nbsp;&nbsp;&nbsp;&nbsp;}</span><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><br style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;><span style="color: rgb(171, 178, 191);font-family: " operator mono, consolas, monaco, menlo, monospace;font-size: 12px;letter-spacing: normal;text-align: left;white-space-collapse: preserve;background-color: rgb(40, 44, 52);>}</span></code></pre> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>3.4.3 展示报告数据<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">对汇总的报告数据通过不同维度进行展示,达到实时观察需要或做为其它功能的前置数据。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>报告汇总:</strong></p> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100021695" data-ratio="0.05740740740740741" data-s="300,640" src="/upload/4298faef8b73a47a9a9860919b6cf88a.png" data-type="png" data-w="1080" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>接口数据:</strong></p> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100021696" data-ratio="0.16296296296296298" data-s="300,640" src="/upload/e509c54cf470c61bf81e2748356c8304.png" data-type="png" data-w="1080" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>性能曲线:</strong></p> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100021697" data-ratio="0.23796296296296296" data-s="300,640" src="/upload/c7ffb63c4f45d022630fd3609809fedd.png" data-type="png" data-w="1080" style=""></p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>四、未来展望</h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">最初平台大部分组件及功能均是独立不依赖于公司其它组件,包括权限系统,文件管理系统等,随着公司相关配套组件的发展,压测平台也逐步接入了统一权限、飞书消息、分布式缓存等组件,功能也从最初的设计的单纯压测到后期自动化压测平台(可参阅《<a target="_blank" href="https://mp.weixin.qq.com/s?__biz=MzI0MjIxNjE0OQ==&amp;mid=2247489855&amp;idx=1&amp;sn=9427c472b7024c441895ac55c1a4b6ff&amp;scene=21#wechat_redirect" textvalue="全链路压测自动化的探索与实践" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="2">全链路压测自动化的探索与实践</a>》)。目前压测平台支撑货拉拉核心业务的性能测试及全链路测试,每月产生压测数据2000份以上,期间也过较多的迭代改造和升级,后续会继续根据业务的发展并结合公司的业务情况进行优化升级。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>4.1 文件分发升级<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">目前平台使用的文件分发系统是通过mongo数据库分布式文件进行存储及分发的,其数据库的数量和吞吐即为文件分发的瓶颈,不能通过简单的扩容管理服务进行效率提升,在启动500台+压测测试时,分发文件会有一定的分发迟滞,在压测规模再进一步增长后计划优化为基于mongo+OSS双负载方式。</p> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100021698" data-ratio="0.4074074074074074" data-s="300,640" src="/upload/7680656aa730a9d3ddeb86bb2d7e317e.png" data-type="png" data-w="1080" style=""></p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>4.2 进一步的AI探索<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">目前压测平台在压测模型建模及压测问题发现方面已经进行AI算法上的一些探索,可提高压测模型的精度及主动发现压测过程的性能问题,下一步会结合AIGC在压测问题定位及压测报告生成上继续探索。</p> <p style="text-align: center;"><img class="rich_pages wxw-img js_insertlocalimg" data-imgfileid="100021699" data-ratio="0.3101851851851852" data-s="300,640" src="/upload/60907f9f933a3f3d94a7350af238c4f3.png" data-type="png" data-w="1080" style=""></p> </section> <p><br></p> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>