{
    "version": "https://jsonfeed.org/version/1",
    "title": "vv",
    "home_page_url": "https://devvv.cn/blog",
    "description": "feedId:42215011978385457+userId:41840353283325416",
    "items": [
        {
            "id": "https://devvv.cn/blog/color-alpha-contrast-table",
            "content_html": "<table><thead><tr><th>不透明度</th><th>十六进制值</th></tr></thead><tbody><tr><td>100%</td><td>FF</td></tr><tr><td>95%</td><td>F2</td></tr><tr><td>90%</td><td>E5</td></tr><tr><td>85%</td><td>D8</td></tr><tr><td>80%</td><td>CC</td></tr><tr><td>75%</td><td>BF</td></tr><tr><td>70%</td><td>B2</td></tr><tr><td>65%</td><td>A5</td></tr><tr><td>60%</td><td>99</td></tr><tr><td>55%</td><td>8C</td></tr><tr><td>50%</td><td>7F</td></tr><tr><td>45%</td><td>72</td></tr><tr><td>40%</td><td>66</td></tr><tr><td>35%</td><td>59</td></tr><tr><td>30%</td><td>4C</td></tr><tr><td>25%</td><td>3F</td></tr><tr><td>20%</td><td>33</td></tr><tr><td>15%</td><td>21</td></tr><tr><td>10%</td><td>19</td></tr><tr><td>5%</td><td>0C</td></tr><tr><td>0%</td><td>00</td></tr></tbody></table>\n<p>如果设计给出的是透明度，就用100-透明度， 就是不透明度。</p>",
            "url": "https://devvv.cn/blog/color-alpha-contrast-table",
            "title": "透明度对照表",
            "summary": "透明度对照表",
            "date_modified": "2026-04-01T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "透明度"
            ]
        },
        {
            "id": "https://devvv.cn/blog/for-dkplayer-16k-adaption-page-process",
            "content_html": "<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"前言\">前言<a href=\"https://devvv.cn/blog/for-dkplayer-16k-adaption-page-process#%E5%89%8D%E8%A8%80\" class=\"hash-link\" aria-label=\"前言的直接链接\" title=\"前言的直接链接\" translate=\"no\">​</a></h3>\n<p>最近需要集成视频播放功能，但是项目又已经集成了 <code>FFmpeg</code>，因此采用 <code>ExoPlayer</code> 播放器，而 <code>DKPlayer</code> 在 <code>ExoPlayer</code> 基础上做了一些封装，方便使用。但是 <code>DKPlayer</code> 没有适配 16k 页面，因此需要自己编译一个版本。</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"16k 页面未适配\" src=\"data:image/png;base64,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\" width=\"317\" height=\"205\" class=\"img_m9Pm\"></p>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"步骤\">步骤<a href=\"https://devvv.cn/blog/for-dkplayer-16k-adaption-page-process#%E6%AD%A5%E9%AA%A4\" class=\"hash-link\" aria-label=\"步骤的直接链接\" title=\"步骤的直接链接\" translate=\"no\">​</a></h3>\n<p>通过上述截图发现，没适配 16k Page Size 只有的 <code>librtmp-jni.so</code>。</p>\n<p>这个库位于：<a href=\"https://github.com/ant-media/LibRtmp-Client-for-Android\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://github.com/ant-media/LibRtmp-Client-for-Android</a></p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> clone https://github.com/ant-media/LibRtmp-Client-for-Android.git</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> LibRtmp-Client-for-Android</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>新建 <code>local.properties</code> 文件：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">touch</span><span class=\"token plain\"> local.properties</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 添加 sdk.dir</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">sdk.dir</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">/home/vv/android/SDK</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>执行编译：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">./gradlew assembleRelease</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"编译成功\" src=\"https://devvv.cn/assets/images/619857ba-9e12-466a-b48d-1d538fd68d31-a191cd0965f5fb78315fb9fa3bb12a08.png\" width=\"813\" height=\"574\" class=\"img_m9Pm\"></p>\n<p>编译后的 <code>.aar</code> 文件位于：</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">/home/vv/android/work/demo/LibRtmp-Client-for-Android/rtmp-client/build/outputs/aar</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">text</span></div></div></div>\n<p>进入这个目录，提取 <code>.aar</code>，<code>.so</code> 文件位于其下。</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"检查是否适配成功\">检查是否适配成功<a href=\"https://devvv.cn/blog/for-dkplayer-16k-adaption-page-process#%E6%A3%80%E6%9F%A5%E6%98%AF%E5%90%A6%E9%80%82%E9%85%8D%E6%88%90%E5%8A%9F\" class=\"hash-link\" aria-label=\"检查是否适配成功的直接链接\" title=\"检查是否适配成功的直接链接\" translate=\"no\">​</a></h3>\n<p>用下面的命令检查一下 .so 文件：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 使用NDK中的llvm-objdump工具检查（路径需替换为你自己的NDK路径）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">/home/vv/android/SDK/ndk/25.2.9519653/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-objdump </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-p</span><span class=\"token plain\"> librtmp-jni.so </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">grep</span><span class=\"token plain\"> LOAD</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>如何判断结果：</p>\n<ul>\n<li class=\"\">已适配 (ALIGNED)：如果输出中所有 LOAD 段的 align 值都是 <code>2**14</code> (即16384) 或更高，比如 <code>2**14</code> 或 <code>2**16</code>，说明这个 .so 文件本身已经支持 16KB 页大小。</li>\n<li class=\"\">未适配 (UNALIGNED)：如果任何一个 LOAD 段的 align 值是 <code>2**12</code> (4096) 或更低，说明这个 .so 文件确实没有适配。</li>\n</ul>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"检验结果\" src=\"https://devvv.cn/assets/images/ffc2763c-a48a-4052-8604-53cfb950e3a0-24c2641a01ad2fb7e714241be048439c.png\" width=\"1081\" height=\"367\" class=\"img_m9Pm\"></p>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"替换到自己项目\">替换到自己项目<a href=\"https://devvv.cn/blog/for-dkplayer-16k-adaption-page-process#%E6%9B%BF%E6%8D%A2%E5%88%B0%E8%87%AA%E5%B7%B1%E9%A1%B9%E7%9B%AE\" class=\"hash-link\" aria-label=\"替换到自己项目的直接链接\" title=\"替换到自己项目的直接链接\" translate=\"no\">​</a></h3>\n<p>把对应的 <code>.so</code> 文件复制到 <code>libs</code> 目录下：</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"libs 目录\" src=\"data:image/png;base64,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\" width=\"225\" height=\"293\" class=\"img_m9Pm\"></p>\n<p>在 <code>build.gradle.kts</code> 中添加：</p>\n<div class=\"language-kts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">android </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    defaultConfig </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        ndk </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            abiFilters </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">+=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">listOf</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"arm64-v8a\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"x86_64\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    sourceSets </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getByName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"main\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            jniLibs</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">srcDirs</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">arrayOf</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"libs\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    packaging </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        jniLibs </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            useLegacyPackaging </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        jniLibs</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">pickFirsts</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">addAll</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">arrayOf</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"lib/x86/libc++_shared.so\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"lib/x86_64/libc++_shared.so\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"lib/armeabi-v7a/libc++_shared.so\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"lib/arm64-v8a/libc++_shared.so\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// DKPlayer 16k page 适配需要</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"lib/arm64-v8a/librtmp-jni.so\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"lib/x86_64/librtmp-jni.so\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//                \"lib/armeabi-v7a/librtmp-jni.so\",</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">kts</span></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"常见报错\">常见报错<a href=\"https://devvv.cn/blog/for-dkplayer-16k-adaption-page-process#%E5%B8%B8%E8%A7%81%E6%8A%A5%E9%94%99\" class=\"hash-link\" aria-label=\"常见报错的直接链接\" title=\"常见报错的直接链接\" translate=\"no\">​</a></h3>\n<p>Java 版本太高报错，需要降级：</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"报错\" src=\"https://devvv.cn/assets/images/7d55e1ef-671e-4ad3-9456-7973b83b898f-1832e3fccba35c72fee581595a360e45.png\" width=\"806\" height=\"514\" class=\"img_m9Pm\"></p>\n<p>打开 <code>Android Studio</code> 中的 <code>Project Structure -&gt; SDK Location -&gt; Java Location 中 -&gt; Gradle Settings</code>：</p>\n<p>下载完 JDK11，修改 Java 环境变量：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">nano</span><span class=\"token plain\"> ~/.bashrc</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 把 JAVA_HOME 改为 JDK11 的路径</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">source</span><span class=\"token plain\"> ~/.bashrc</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">java</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-version</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 再次执行</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">./gradlew assembleRelease</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>",
            "url": "https://devvv.cn/blog/for-dkplayer-16k-adaption-page-process",
            "title": "为 DKPlayer 适配 16k 页面",
            "summary": "为 DKPlayer 适配 16k 页面",
            "date_modified": "2026-04-01T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "Android",
                "DKPlayer"
            ]
        },
        {
            "id": "https://devvv.cn/blog/docker-install-step-by-step",
            "content_html": "<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"完全清理-docker-配置\">完全清理 Docker 配置<a href=\"https://devvv.cn/blog/docker-install-step-by-step#%E5%AE%8C%E5%85%A8%E6%B8%85%E7%90%86-docker-%E9%85%8D%E7%BD%AE\" class=\"hash-link\" aria-label=\"完全清理 Docker 配置的直接链接\" title=\"完全清理 Docker 配置的直接链接\" translate=\"no\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 1. 删除所有 Docker 相关的源文件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">rm</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-f</span><span class=\"token plain\"> /etc/apt/sources.list.d/docker*.list</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 2. 清除残留的列表文件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">rm</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-f</span><span class=\"token plain\"> /var/lib/apt/lists/*docker*</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 3. 移除可能存在的旧 Docker 包</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">apt</span><span class=\"token plain\"> remove </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-y</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> docker-engine docker.io containerd runc</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"安装-docker\">安装 Docker<a href=\"https://devvv.cn/blog/docker-install-step-by-step#%E5%AE%89%E8%A3%85-docker\" class=\"hash-link\" aria-label=\"安装 Docker的直接链接\" title=\"安装 Docker的直接链接\" translate=\"no\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 更新系统并安装基础工具</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">apt</span><span class=\"token plain\"> update </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&amp;&amp;</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">apt</span><span class=\"token plain\"> upgrade </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-y</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">apt</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-y</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">curl</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">wget</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 安装Docker</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">apt</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-y</span><span class=\"token plain\"> apt-transport-https ca-certificates </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">curl</span><span class=\"token plain\"> software-properties-common</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">curl</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-fsSL</span><span class=\"token plain\"> https://download.docker.com/linux/ubuntu/gpg </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> gpg </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--dearmor</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-o</span><span class=\"token plain\"> /usr/share/keyrings/docker-archive-keyring.gpg</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"deb [arch=</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">dpkg --print-architecture</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">lsb_release </span><span class=\"token string variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-cs</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> stable\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">tee</span><span class=\"token plain\"> /etc/apt/sources.list.d/docker.list </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> /dev/null</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">apt</span><span class=\"token plain\"> update</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">apt</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-y</span><span class=\"token plain\"> docker-ce docker-ce-cli containerd.io docker-compose-plugin</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 添加当前用户到docker组（避免每次使用sudo）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">usermod</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-aG</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> </span><span class=\"token environment constant\" style=\"color:hsl(35, 99%, 36%)\">$USER</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">newgrp </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 立即生效或重新登录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 验证安装</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--version</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose version</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> systemctl </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">enable</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 开机自启</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">mkdir</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-p</span><span class=\"token plain\"> /etc/docker</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">tee</span><span class=\"token plain\"> /etc/docker/daemon.json </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;&lt;-</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'EOF'</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">{</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">  \"registry-mirrors\": [</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">    \"https://docker.m.daocloud.io\"</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">  ]</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">EOF</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> systemctl daemon-reload</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> systemctl restart </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>",
            "url": "https://devvv.cn/blog/docker-install-step-by-step",
            "title": "docker 安装",
            "summary": "docker 安装",
            "date_modified": "2026-04-01T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "docker"
            ]
        },
        {
            "id": "https://devvv.cn/blog/fast-look-system-info-by-fastfetch",
            "content_html": "<p>Ubuntu：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">apt</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> fastfetch</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>Windows：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">winget </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> fastfetch</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>启动：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">fastfetch</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">fastfetch </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-c</span><span class=\"token plain\"> all.jsonc</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>",
            "url": "https://devvv.cn/blog/fast-look-system-info-by-fastfetch",
            "title": "快速查看系统信息",
            "summary": "快速查看系统信息",
            "date_modified": "2026-03-31T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "fastfetch"
            ]
        },
        {
            "id": "https://devvv.cn/blog/build-ffmpegkit-for-android",
            "content_html": "<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"目标\">目标<a href=\"https://devvv.cn/blog/build-ffmpegkit-for-android#%E7%9B%AE%E6%A0%87\" class=\"hash-link\" aria-label=\"目标的直接链接\" title=\"目标的直接链接\" translate=\"no\">​</a></h3>\n<p>源码：<a href=\"https://github.com/arthenica/ffmpeg-kit\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://github.com/arthenica/ffmpeg-kit</a></p>\n<p>16k 适配版本（编译需要 java21）：<a href=\"https://gitee.com/weijun233/ffmpeg-kit-android-16KB\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://gitee.com/weijun233/ffmpeg-kit-android-16KB</a></p>\n<p>GNU Config：<a href=\"https://github.com/arthenica/gnu-config\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://github.com/arthenica/gnu-config</a></p>\n<p>直接下载最新源码：<a href=\"https://devvv.cn/assets/files/ffmpeg-kit-main-da54919a06610beeba082604bfa72f19.zip\" target=\"_blank\" class=\"\">ffmpeg-kit-main.zip</a></p>\n<p>下载 GNU Config：<a href=\"https://devvv.cn/assets/files/gnu-config-master-111745b716745623096a01df52de831a.zip\" target=\"_blank\" class=\"\">gnu-config-master.zip</a></p>\n<p>最终自己编译一份 <code>.aar</code> 文件。</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"整体流程概览\">整体流程概览<a href=\"https://devvv.cn/blog/build-ffmpegkit-for-android#%E6%95%B4%E4%BD%93%E6%B5%81%E7%A8%8B%E6%A6%82%E8%A7%88\" class=\"hash-link\" aria-label=\"整体流程概览的直接链接\" title=\"整体流程概览的直接链接\" translate=\"no\">​</a></h3>\n<ol>\n<li class=\"\"><strong>准备环境</strong>：安装必要工具，配置 Android SDK/NDK 环境变量。</li>\n<li class=\"\"><strong>执行构建</strong>：运行 <code>android.sh</code> 脚本。</li>\n<li class=\"\"><strong>获取产物</strong>：在 <code>prebuilt</code> 目录下找到生成的 <code>.aar</code> 文件。</li>\n<li class=\"\"><strong>集成项目</strong>：将 <code>.aar</code> 文件放入项目并添加依赖。</li>\n</ol>\n<hr>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"详细步骤\">详细步骤<a href=\"https://devvv.cn/blog/build-ffmpegkit-for-android#%E8%AF%A6%E7%BB%86%E6%AD%A5%E9%AA%A4\" class=\"hash-link\" aria-label=\"详细步骤的直接链接\" title=\"详细步骤的直接链接\" translate=\"no\">​</a></h3>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"第一步准备工作环境配置\">第一步：准备工作（环境配置）<a href=\"https://devvv.cn/blog/build-ffmpegkit-for-android#%E7%AC%AC%E4%B8%80%E6%AD%A5%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE\" class=\"hash-link\" aria-label=\"第一步：准备工作（环境配置）的直接链接\" title=\"第一步：准备工作（环境配置）的直接链接\" translate=\"no\">​</a></h4>\n<p>在开始编译前，需要确保开发环境满足条件。</p>\n<ol>\n<li class=\"\">\n<p><strong>安装必要工具</strong>：Ubuntu 24.04 LTS ：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">apt</span><span class=\"token plain\"> update</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">apt</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> autoconf automake libtool pkg-config </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">curl</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> doxygen nasm cmake gcc gperf texinfo yasm bison autogen </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">wget</span><span class=\"token plain\"> autopoint meson ninja-build ragel groff gtk-doc-tools </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'libtasn1*'</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p><em>注：这些工具是编译 FFmpeg 及其依赖库所必需的。</em></p>\n<p>打开 <code>Android Studio</code>，下载 NDK 和 CMake：</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">NDK (Side by side) 25.2.9519653</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">CMake 4.0.2</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">text</span></div></div></div>\n</li>\n<li class=\"\">\n<p><strong>设置环境变量</strong>：必须明确告诉构建脚本 Android SDK 和 NDK 在哪里。</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">nano</span><span class=\"token plain\"> ~/.bashrc</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 文件末尾添加 环境变量</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">export</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">ANDROID_SDK_ROOT</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">/home/vv/android/SDK</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">export</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">ANDROID_NDK_ROOT</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">/home/vv/android/SDK/ndk/25.2.9519653</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">source</span><span class=\"token plain\"> ~/.bashrc</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p><strong>注意</strong>：</p>\n<ul>\n<li class=\"\">官方要求 NDK 版本为 <strong>r22b 或更高版本</strong>。建议使用 Android Studio 下载最新的稳定版 NDK。</li>\n</ul>\n</li>\n</ol>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"第二步获取源码并执行编译\">第二步：获取源码并执行编译<a href=\"https://devvv.cn/blog/build-ffmpegkit-for-android#%E7%AC%AC%E4%BA%8C%E6%AD%A5%E8%8E%B7%E5%8F%96%E6%BA%90%E7%A0%81%E5%B9%B6%E6%89%A7%E8%A1%8C%E7%BC%96%E8%AF%91\" class=\"hash-link\" aria-label=\"第二步：获取源码并执行编译的直接链接\" title=\"第二步：获取源码并执行编译的直接链接\" translate=\"no\">​</a></h4>\n<ol>\n<li class=\"\">\n<p><strong>克隆仓库</strong>：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> clone https://github.com/arthenica/ffmpeg-kit.git</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> ffmpeg-kit</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n</li>\n<li class=\"\">\n<p><strong>运行构建脚本</strong>：这是核心步骤。直接运行 <code>android.sh</code> 将开始为所有支持的架构（arm-v7a, arm64-v8a等）进行编译。</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 强制 CMake 3.5 适配，仅当前窗口有效</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">export</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">CMAKE_POLICY_VERSION_MINIMUM</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3.5</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">./android.sh --disable-arm-v7a --disable-arm-v7a-neon --disable-x86</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 或者 </span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">./android.sh </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--full</span><span class=\"token plain\"> --enable-gpl --disable-openssl --disable-arm-v7a --disable-arm-v7a-neon --disable-x86</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># --disable-openssl 和 --disable-lib-gnutls 二选一</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>这个初次编译过程可能会<strong>非常耗时</strong>（可能需要半小时甚至更久，取决于电脑性能），因为它会从 GitHub 下载 FFmpeg 及其他几十个外部库的源码并逐个编译。</p>\n<p>如果是直接下载的 <code>zip</code>，需要修改 <code>android.sh</code> 脚本：</p>\n<div class=\"language-shell codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-shell codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># BUILD_VERSION=$(git describe --tags --always 2&gt;&gt;\"${BASEDIR}\"/build.log)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">BUILD_VERSION</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"6.0.2\"</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">shell</span></div></div></div>\n</li>\n<li class=\"\">\n<p><strong>查看实时日志</strong>：打开一个新窗口，进入根目录下：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">tail</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-f</span><span class=\"token plain\"> build.log</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n</li>\n</ol>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"第三步定制构建可选\">第三步：定制构建（可选）<a href=\"https://devvv.cn/blog/build-ffmpegkit-for-android#%E7%AC%AC%E4%B8%89%E6%AD%A5%E5%AE%9A%E5%88%B6%E6%9E%84%E5%BB%BA%E5%8F%AF%E9%80%89\" class=\"hash-link\" aria-label=\"第三步：定制构建（可选）的直接链接\" title=\"第三步：定制构建（可选）的直接链接\" translate=\"no\">​</a></h4>\n<p>这是自己编译的最大优势。可以通过添加参数来精确控制要编译哪些功能，从而有效控制最终 <code>.aar</code> 文件的大小。</p>\n<ul>\n<li class=\"\">\n<p><strong>排除不需要的架构</strong>：如果应用只打算支持 64 位设备，可以排除 32 位架构以减小包体积。</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">./android.sh --disable-arm-v7a --disable-arm-v7a-neon --disable-x86</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n</li>\n<li class=\"\">\n<p><strong>启用特定功能</strong>：如果需要 HTTPS 支持或特定的编解码器，可以用 <code>--enable-</code> 开头。</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 例如：编译一个支持 HTTPS 且包含常用音视频库的版本</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">./android.sh --enable-openssl --enable-libvpx --enable-libmp3lame</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n</li>\n<li class=\"\">\n<p><strong>选择包类型</strong>：脚本提供了便捷的参数来组合常用功能。</p>\n<ul>\n<li class=\"\"><code>--full</code>：启用绝大多数外部库，功能最全，体积最大。</li>\n<li class=\"\"><code>--enable-gpl</code>：启用 x264, x265 等使用 GPL 许可证的库。请注意，加上此参数后，生成的库将遵循 <strong>GPLv3</strong> 协议。</li>\n</ul>\n</li>\n<li class=\"\">\n<p><strong>编译 LTS 版本</strong>：如果应用需要支持 Android API Level 16+ 的旧设备，请加上此参数。</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">./android.sh </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--lts</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n</li>\n</ul>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"下载 Gradle\" src=\"https://devvv.cn/assets/images/17577b29b9f242c1a0f7ede84aebdf6b-9bc740a529f5957c738d9fb2507243c1.png\" width=\"1384\" height=\"667\" class=\"img_m9Pm\"></p>\n<p>如果遇到类似报错：</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">Please correct and use only one way to inject the SDK location.</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  ANDROID_HOME: /home/vv/Android/Sdk</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  ANDROID_SDK_ROOT: /home/vv/android/SDK</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">text</span></div></div></div>\n<p>解决方法：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">nano</span><span class=\"token plain\"> ~/.bashrc</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 只保留 ANDROID_SDK_ROOT，把 ANDROID_HOME 注释掉</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">source</span><span class=\"token plain\"> ~/.bashrc</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">./android.sh </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--full</span><span class=\"token plain\"> --enable-gpl --disable-openssl --disable-arm-v7a --disable-arm-v7a-neon --disable-x86</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"编译成功\" src=\"https://devvv.cn/assets/images/4a90b29996914aa4be5f3c93735f971c-3b90587cbe4801f35ba2db621539bbf7.png\" width=\"1527\" height=\"672\" class=\"img_m9Pm\"></p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"位置\" src=\"https://devvv.cn/assets/images/aade1587944b413cbace2d340b37345e-ef4c818f7b1019ca92bffac2f7206403.png\" width=\"964\" height=\"335\" class=\"img_m9Pm\"></p>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"第四步获取并使用生成的-aar-文件\">第四步：获取并使用生成的 .aar 文件<a href=\"https://devvv.cn/blog/build-ffmpegkit-for-android#%E7%AC%AC%E5%9B%9B%E6%AD%A5%E8%8E%B7%E5%8F%96%E5%B9%B6%E4%BD%BF%E7%94%A8%E7%94%9F%E6%88%90%E7%9A%84-aar-%E6%96%87%E4%BB%B6\" class=\"hash-link\" aria-label=\"第四步：获取并使用生成的 .aar 文件的直接链接\" title=\"第四步：获取并使用生成的 .aar 文件的直接链接\" translate=\"no\">​</a></h4>\n<ol>\n<li class=\"\">\n<p><strong>找到 aar 文件</strong>：编译成功后，根据选择的构建类型，在以下路径找到生成的 <code>.aar</code> 文件：</p>\n<ul>\n<li class=\"\"><strong>Main 构建</strong>：<code>./prebuilt/bundle-android-aar/</code></li>\n<li class=\"\"><strong>LTS 构建</strong>：<code>./prebuilt/bundle-android-aar-lts/</code>\n文件通常命名为 <code>ffmpeg-kit.aar</code>，如果通过参数定制了功能，文件名会相应变化（如 <code>ffmpeg-kit-full-gpl.aar</code>）。</li>\n</ul>\n</li>\n<li class=\"\">\n<p><strong>集成到项目</strong>：</p>\n<ul>\n<li class=\"\">将 <code>.aar</code> 文件复制到 Android 项目模块的 <strong><code>libs/</code></strong> 文件夹下。</li>\n<li class=\"\">在模块的 <code>build.gradle</code> 文件中添加以下配置：<!-- -->\n<div class=\"language-kts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">dependencies </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 引用本地 libs 文件夹下的 aar 文件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">implementation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">files</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"libs/编译出来的文件名.aar\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">kts</span></div></div></div>\n</li>\n<li class=\"\">（可选）如果项目中有多个模块需要使用，也可以在项目根目录的 <code>build.gradle</code> 中配置 flatDir 仓库。</li>\n</ul>\n</li>\n</ol>\n<hr>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"总结\">总结<a href=\"https://devvv.cn/blog/build-ffmpegkit-for-android#%E6%80%BB%E7%BB%93\" class=\"hash-link\" aria-label=\"总结的直接链接\" title=\"总结的直接链接\" translate=\"no\">​</a></h3>\n<table><thead><tr><th style=\"text-align:left\">类别</th><th style=\"text-align:left\">包含的库/功能</th><th style=\"text-align:left\">作用说明</th></tr></thead><tbody><tr><td style=\"text-align:left\"><strong>音频编解码</strong></td><td style=\"text-align:left\"><code>lame</code><br><code>libilbc</code><br><code>libvorbis</code><br><code>opencore-amr</code><br><code>opus</code><br><code>shine</code><br><code>soxr</code><br><code>speex</code><br><code>twolame</code><br><code>vo-amrwbenc</code></td><td style=\"text-align:left\">MP3 编码<br>iLBC 语音编码<br>Vorbis 音频编码<br>AMR 语音编码<br>Opus 音频编解码<br>MP3 编码（固定点）<br>高质量重采样<br>Speex 语音编解码<br>MP2 音频编码<br>AMR-WB 语音编码</td></tr><tr><td style=\"text-align:left\"><strong>视频编解码（非GPL）</strong></td><td style=\"text-align:left\"><code>dav1d</code><br><code>kvazaar</code><br><code>libtheora</code><br><code>libvpx</code></td><td style=\"text-align:left\">AV1 解码器<br>HEVC/H.265 编码器（非GPL）<br>Theora 视频编码<br>VP8/VP9 编解码</td></tr><tr><td style=\"text-align:left\"><strong>视频编解码（GPL）</strong></td><td style=\"text-align:left\"><code>x264</code><br><code>x265</code><br><code>xvidcore</code></td><td style=\"text-align:left\">H.264/AVC 编码器<br>HEVC/H.265 编码器（GPL 版本）<br>MPEG-4 编码器</td></tr><tr><td style=\"text-align:left\"><strong>视频稳定</strong></td><td style=\"text-align:left\"><code>vid.stab</code></td><td style=\"text-align:left\">视频防抖滤镜（GPL）</td></tr><tr><td style=\"text-align:left\"><strong>字幕/字体/文字</strong></td><td style=\"text-align:left\"><code>fontconfig</code><br><code>freetype</code><br><code>fribidi</code><br><code>libass</code></td><td style=\"text-align:left\">字体配置<br>字体渲染<br>双向文本布局<br>字幕渲染（ASS/SSA）</td></tr><tr><td style=\"text-align:left\"><strong>网络/加密</strong></td><td style=\"text-align:left\"><code>gmp</code><br><code>gnutls</code><br><code>libxml2</code></td><td style=\"text-align:left\">加密数学库<br>HTTPS/TLS 支持<br>XML 解析</td></tr><tr><td style=\"text-align:left\"><strong>图像/像素处理</strong></td><td style=\"text-align:left\"><code>libwebp</code><br><code>zimg</code><br><code>snappy</code></td><td style=\"text-align:left\">WebP 图像编解码<br>高保真图像缩放<br>快速压缩</td></tr><tr><td style=\"text-align:left\"><strong>字符集转换</strong></td><td style=\"text-align:left\"><code>libiconv</code></td><td style=\"text-align:left\">字符编码转换</td></tr><tr><td style=\"text-align:left\"><strong>Android 系统库</strong></td><td style=\"text-align:left\"><code>zlib</code><br><code>MediaCodec</code></td><td style=\"text-align:left\">压缩/解压<br>硬件加速编解码</td></tr></tbody></table>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"重要说明\">重要说明<a href=\"https://devvv.cn/blog/build-ffmpegkit-for-android#%E9%87%8D%E8%A6%81%E8%AF%B4%E6%98%8E\" class=\"hash-link\" aria-label=\"重要说明的直接链接\" title=\"重要说明的直接链接\" translate=\"no\">​</a></h3>\n<ul>\n<li class=\"\"><strong><code>full-gpl</code> 包含 <code>full</code> 的所有功能</strong>，并额外增加了 GPL 库（x264, x265, xvidcore, vid.stab）。</li>\n<li class=\"\"><strong>许可证影响</strong>：由于包含了 GPL 库，整个生成的 <code>.aar</code> 必须遵循 <strong>GPLv3 许可证</strong>，这意味着如果应用分发该库，也需要开源并遵守 GPL 协议。</li>\n<li class=\"\"><strong>功能优势</strong>：支持 H.264/H.265 的高质量软件编码（x264/x265），以及 Xvid 编码和视频防抖功能。</li>\n<li class=\"\"><strong>仍然不包含视频播放器</strong>，仍然是命令行工具库，用于媒体处理而非播放。</li>\n</ul>",
            "url": "https://devvv.cn/blog/build-ffmpegkit-for-android",
            "title": "编译 ffmpegkit",
            "summary": "编译 ffmpegkit",
            "date_modified": "2026-03-31T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "Android",
                "ffmpegkit"
            ]
        },
        {
            "id": "https://devvv.cn/blog/local-deploy-ai-model-doc",
            "content_html": "<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"环境准备\">环境准备<a href=\"https://devvv.cn/blog/local-deploy-ai-model-doc#%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87\" class=\"hash-link\" aria-label=\"环境准备的直接链接\" title=\"环境准备的直接链接\" translate=\"no\">​</a></h3>\n<table><thead><tr><th>名称</th><th>详情</th></tr></thead><tbody><tr><td>系统</td><td>Win11 企业版 LTSC 64位 0103b OOBE</td></tr><tr><td>CPU</td><td>i7 14700KF</td></tr><tr><td>内存</td><td>64G</td></tr><tr><td>显卡</td><td>RTX 5060T 16G</td></tr><tr><td>系统盘（C盘）</td><td>至少 500 G</td></tr></tbody></table>\n<div class=\"theme-admonition theme-admonition-warning admonition_xGDO alert alert--warning\"><div class=\"admonitionHeading_WNFr\"><span class=\"admonitionIcon_FtpR\"><svg viewBox=\"0 0 16 16\"><path fill-rule=\"evenodd\" d=\"M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z\"></path></svg></span>注意</div><div class=\"admonitionContent_hiHs\"><p>安装 Windows 系统必须选择 OOBE 模式</p></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"安装-ollama\">安装 Ollama<a href=\"https://devvv.cn/blog/local-deploy-ai-model-doc#%E5%AE%89%E8%A3%85-ollama\" class=\"hash-link\" aria-label=\"安装 Ollama的直接链接\" title=\"安装 Ollama的直接链接\" translate=\"no\">​</a></h3>\n<p>下载地址：<a href=\"https://ollama.com/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://ollama.com/</a></p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"安装 Ollama\" src=\"data:image/png;base64,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\" width=\"835\" height=\"638\" class=\"img_m9Pm\"></p>\n<p>安装完成会有一个 UI 界面，直接关掉：</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Ollama UI 界面\" src=\"data:image/png;base64,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\" width=\"816\" height=\"639\" class=\"img_m9Pm\"></p>\n<p>打开 <code>命令提示符</code> 或 <code>PowerShell</code>，检查是否安装成功：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ollama </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--version</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ollama list</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"Ollama 检查\" src=\"data:image/png;base64,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\" width=\"333\" height=\"199\" class=\"img_m9Pm\"></p>\n<p>Ollama 安装路径为：</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">C:\\Users\\weijun\\AppData\\Local\\Programs\\Ollama</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">text</span></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"下载模型\">下载模型<a href=\"https://devvv.cn/blog/local-deploy-ai-model-doc#%E4%B8%8B%E8%BD%BD%E6%A8%A1%E5%9E%8B\" class=\"hash-link\" aria-label=\"下载模型的直接链接\" title=\"下载模型的直接链接\" translate=\"no\">​</a></h3>\n<p>编程模型：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ollama pull deepseek-coder-v2:16b</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"deepseek 编程模型下载\" src=\"data:image/png;base64,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\" width=\"761\" height=\"382\" class=\"img_m9Pm\"></p>\n<p>模型不不保存路径：</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">C:\\Users\\weijun\\.ollama\\models</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">text</span></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"运行模型\">运行模型<a href=\"https://devvv.cn/blog/local-deploy-ai-model-doc#%E8%BF%90%E8%A1%8C%E6%A8%A1%E5%9E%8B\" class=\"hash-link\" aria-label=\"运行模型的直接链接\" title=\"运行模型的直接链接\" translate=\"no\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ollama run deepseek-coder-v2:16b</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>启动后，会看到 <code>&gt;&gt;&gt;</code> 提示符。输入一个问题，比如：“用 kotlin写一个快速排序”，然后回车。如果模型正常回复，说明部署成功。</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"运行第一个模型\" src=\"data:image/png;base64,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\" width=\"821\" height=\"586\" class=\"img_m9Pm\"></p>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"退出模型\">退出模型<a href=\"https://devvv.cn/blog/local-deploy-ai-model-doc#%E9%80%80%E5%87%BA%E6%A8%A1%E5%9E%8B\" class=\"hash-link\" aria-label=\"退出模型的直接链接\" title=\"退出模型的直接链接\" translate=\"no\">​</a></h3>\n<p>在 <code>ollama run</code> 的对话界面中，直接输入：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">/bye</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>然后按回车，即可退出模型会话，回到命令行提示符。模型会从显存中卸载。</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"退出模型\" src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAWMAAABiAgMAAAD4h1pjAAAACVBMVEUMDAzMzMw+Pj4tXSEIAAADG0lEQVRo3u2XXY7bMAyEOcDoXQGi+9CA+64A4n1aoAfokSuSdtqm3Sd70T9rN/qh5U+DMa0o8lHeqVzki/w7yLXuXY267pV6k6161focULTqMxY1ZZ/8M7mYmd8DWJdqA8KcPGzEHVW0mEqzHuSM5Wo7Gb8i5xU8VUjMRpWmSviqFbusID9jpgJ5k6xmeUWDDA9+mFpJESdLlkmb+kD50M1jbdJ9frEyigWZr+QZNE3yLKyb5xVJhvViNnxJAGy9pmubu8Qkotkkv4j+tAgnQZ0jZRL8ejqjbfqMXCU0UpZww2OwOXPGkhya9YW8QnZyc38Xs6aLYCLSnZuEfroDjyB7DGBNzUrQV7q9+PxZdzLEYYjxTe6iBUFmkqsn443y6JE738ikrL7a/YX8RZe6k71lkDPr0M3Q9jwwd4WYmj0GS3IxUCp/mRsLn+RFak3NQebqUTrIUCXI93CDCM0frBNvkhcwcoPMbNvc+Y5M18xmWmx/gmSQ18mEcLZJ7i9khOZKlciT1B4poTZ2n2to3vOZ4m6AG3kJMsAfyCsQb4rGvRLkNcjRpzBjU/P+DtLJkCfZtaH8RFZI8pSo2Yv2lezrtv4D2X0qJowZveLFjXhaVIGAxcyfXrSikdtuJiQ1ty4rJzliN9SJ7QSq3w8p9pobnDXEZUQgxrvm2YQFqTkdz70O9Ee8b7f4V75T9s5FvsgX+SJf5D+TjLPJn4VC7/Bs8idByuX9bDfipOxknk2uUvMEezqZm9GVvZVlnEjGZrQWEsQ7aFYCJM73OcnFzs8NCCGd75DPkMJJxunvoNddFOP8fWP/xf8+e12Zn79qF73IF/kiX+SL/B+R+d2Y550KTATSim5jZK1yP7rOZ2ynmF+ScTY5y8FzwheRLkq8warHyTCM1mCi98cypu3jXu5DeIgsTvY/LIRoreushUSB4CC5EhQCQu/fuJFny+NkjGIQjNl/FHuS67HccIqAkmnClfIk6wEypScl3PB/bm4UAkfewe7k6cXAaL0MJ2NE+7CyHt2RntK+9clszyeX/mfvolEu8kW+yG+Xr14ArNpP94BhAAAAAElFTkSuQmCC\" width=\"355\" height=\"98\" class=\"img_m9Pm\"></p>\n<p>如果界面卡死，按 <code>Ctrl + C</code> 一次或多次，可以中断正在运行的进程。如果无效，可以关闭整个命令行窗口。</p>\n<p>或者打开另一个命令行窗口，运行：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ollama stop deepseek-coder-v2:16b</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ollama stop </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--all</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"安装-docker\">安装 docker<a href=\"https://devvv.cn/blog/local-deploy-ai-model-doc#%E5%AE%89%E8%A3%85-docker\" class=\"hash-link\" aria-label=\"安装 docker的直接链接\" title=\"安装 docker的直接链接\" translate=\"no\">​</a></h3>\n<p>下载并安装 <code>Docker Desktop for Windows</code>：<a href=\"https://www.docker.com/products/docker-desktop/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://www.docker.com/products/docker-desktop/</a>。</p>\n<p>选择 <code>Download for Windows – AMD64</code>。</p>\n<p>安装完成后，重启 Windows 系统：</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"重启Windows系统\" src=\"data:image/png;base64,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\" width=\"695\" height=\"482\" class=\"img_m9Pm\"></p>\n<p>Windows 系统重启后，安装 WSL2：</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"安装 WSL2\" src=\"https://devvv.cn/assets/images/873289db-e3d5-4025-9983-d0a80d2db3d5-c8713b6a7d9a17f7b2358f6957f0b4ac.png\" width=\"1908\" height=\"746\" class=\"img_m9Pm\"></p>\n<p>启动 <code>Docker Desktop</code>，在 <code>Windows</code> 系统托盘中看到它的鲸鱼图标为止。</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"鲸鱼图标\" src=\"data:image/png;base64,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\" width=\"184\" height=\"85\" class=\"img_m9Pm\"></p>\n<p>查看 Docker 总共占用了多少磁盘空间：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> system </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">df</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>如果 C 盘空间紧张，可以在 <code>Docker Desktop</code> 的设置里，把存储位置改到其他容量更大的盘符。</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"部署-open-webui\">部署 Open WebUI<a href=\"https://devvv.cn/blog/local-deploy-ai-model-doc#%E9%83%A8%E7%BD%B2-open-webui\" class=\"hash-link\" aria-label=\"部署 Open WebUI的直接链接\" title=\"部署 Open WebUI的直接链接\" translate=\"no\">​</a></h3>\n<p>打开 <code>命令提示符 (CMD)</code> 或 <code>PowerShell</code>，执行：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> run </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-d</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-p</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3000</span><span class=\"token plain\">:8080 --add-host</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">host.docker.internal:host-gateway </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-v</span><span class=\"token plain\"> open-webui:/app/backend/data </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--name</span><span class=\"token plain\"> open-webui </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--restart</span><span class=\"token plain\"> always ghcr.io/open-webui/open-webui:main</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>这个命令会自动从网上下载 <code>Open WebUI</code> 的镜像，并以后台服务的形式运行在 <code>3000</code> 端口上。</p>\n<blockquote>\n<p>请注意：这条命令中 <code>-v open-webui:/app/backend/data</code> 这部分会将聊天记录和数据保存在 <code>Docker</code> 的存储卷中，即使容器更新或重启，数据也不会丢失</p>\n</blockquote>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"下载 Open WebUI 镜像\" src=\"data:image/png;base64,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\" width=\"959\" height=\"509\" class=\"img_m9Pm\"></p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"下载 Open WebUI 镜像完成\" src=\"data:image/png;base64,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\" width=\"973\" height=\"494\" class=\"img_m9Pm\"></p>\n<p>当 Docker 成功拉取并运行容器后（可能需要等待一两分钟），打开浏览器，访问地址：</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">http://localhost:3000</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">text</span></div></div></div>\n<p>首次访问时，系统会提示注册一个账号（这是本地 WebUI 的管理员账号，信息只保存在自己的电脑里，非常安全）。注册完成后登录，就能看到之前在 Ollama 中下载好的所有模型了。</p>\n<p>在界面左上角的模型下拉菜单中，可以选择不同的模型进行对话、管理所有聊天记录。</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"下载 Open WebUI 镜像完成\" src=\"https://devvv.cn/assets/images/d3a9b37f-0061-4333-8aa5-9b5a874c2cd3-43ab2e1a80ce144ef66aad65188e85a2.png\" width=\"1959\" height=\"1226\" class=\"img_m9Pm\"></p>\n<p>部署成功后，可以探索更多功能：</p>\n<ul>\n<li class=\"\">上传文件：在输入框左侧点击 # 号图标上传文档（如 PDF、TXT），然后基于文档内容提问，实现本地知识库问答。</li>\n<li class=\"\">自定义系统提示词：在“工作空间”中可以创建自定义模型，为 AI 设定特定的人设或角色。</li>\n<li class=\"\">连接其他 API：在设置 -&gt; 外部连接中，可以填入 OpenAI、Gemini 等在线服务的 API Key，让 Open WebUI 成为一个聚合所有模型的统一界面</li>\n</ul>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"常用命令\">常用命令<a href=\"https://devvv.cn/blog/local-deploy-ai-model-doc#%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4\" class=\"hash-link\" aria-label=\"常用命令的直接链接\" title=\"常用命令的直接链接\" translate=\"no\">​</a></h3>\n<table><thead><tr><th style=\"text-align:left\">命令</th><th style=\"text-align:left\">作用</th></tr></thead><tbody><tr><td style=\"text-align:left\"><code>ollama list</code></td><td style=\"text-align:left\">列出已下载到本地的所有模型</td></tr><tr><td style=\"text-align:left\"><code>ollama run &lt;model&gt;</code></td><td style=\"text-align:left\">启动并进入模型对话界面</td></tr><tr><td style=\"text-align:left\"><code>ollama stop &lt;model&gt;</code></td><td style=\"text-align:left\">停止正在运行的指定模型</td></tr><tr><td style=\"text-align:left\"><code>ollama stop --all</code></td><td style=\"text-align:left\">停止所有正在运行的模型</td></tr><tr><td style=\"text-align:left\"><code>ollama ps</code></td><td style=\"text-align:left\">查看当前正在运行的模型列表</td></tr><tr><td style=\"text-align:left\"><code>ollama pull &lt;model&gt;</code></td><td style=\"text-align:left\">下载模型（如果已存在则更新）</td></tr><tr><td style=\"text-align:left\"><code>ollama rm &lt;model&gt;</code></td><td style=\"text-align:left\">删除本地模型</td></tr><tr><td style=\"text-align:left\"><code>ollama cp &lt;source&gt; &lt;dest&gt;</code></td><td style=\"text-align:left\">复制模型并创建别名</td></tr><tr><td style=\"text-align:left\"><code>ollama serve</code></td><td style=\"text-align:left\">以服务模式启动 Ollama（通常后台运行）</td></tr><tr><td style=\"text-align:left\"><code>ollama --help</code></td><td style=\"text-align:left\">查看全部命令帮助</td></tr></tbody></table>\n<blockquote>\n<p>提示：在 <code>ollama run</code> 对话中，除了 <code>/bye</code> 外，还可以使用 <code>/help</code> 查看其他内置命令（如 <code>/clear</code> 清空上下文）。</p>\n</blockquote>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"安装的模型记录\">安装的模型记录<a href=\"https://devvv.cn/blog/local-deploy-ai-model-doc#%E5%AE%89%E8%A3%85%E7%9A%84%E6%A8%A1%E5%9E%8B%E8%AE%B0%E5%BD%95\" class=\"hash-link\" aria-label=\"安装的模型记录的直接链接\" title=\"安装的模型记录的直接链接\" translate=\"no\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ollama pull deepseek-coder-v2:16b   </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 10GB</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ollama pull qwen3:14b   </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 9GB</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ollama pull qwen3:8b    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 5GB</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>",
            "url": "https://devvv.cn/blog/local-deploy-ai-model-doc",
            "title": "本地部署 ai 模型",
            "summary": "本地部署 ai 模型",
            "date_modified": "2026-03-29T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "AI"
            ]
        },
        {
            "id": "https://devvv.cn/blog/synology-web-station-add-second-site-setup",
            "content_html": "<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"创建共享文件夹\">创建共享文件夹<a href=\"https://devvv.cn/blog/synology-web-station-add-second-site-setup#%E5%88%9B%E5%BB%BA%E5%85%B1%E4%BA%AB%E6%96%87%E4%BB%B6%E5%A4%B9\" class=\"hash-link\" aria-label=\"创建共享文件夹的直接链接\" title=\"创建共享文件夹的直接链接\" translate=\"no\">​</a></h3>\n<p>在群晖的 <code>File Station</code> 中，为第二个站点创建一个独立的文件夹（例如：<code>/web_tools</code>），并将所有文件上传至此：</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"创建共享文件夹第一步\" src=\"https://devvv.cn/assets/images/build_shared_dir_step1-21f0227ad70dd6730f431a033f5d434c.png\" width=\"1128\" height=\"700\" class=\"img_m9Pm\"></p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"创建共享文件夹第二步\" src=\"data:image/png;base64,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\" width=\"801\" height=\"587\" class=\"img_m9Pm\"></p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"创建共享文件夹第三步\" src=\"https://devvv.cn/assets/images/build_shared_dir_step3-2e7e2cb1ae43de203277938a052b059b.png\" width=\"782\" height=\"586\" class=\"img_m9Pm\"></p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"创建共享文件夹第四步\" src=\"data:image/png;base64,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\" width=\"799\" height=\"580\" class=\"img_m9Pm\"></p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"所有文件上传至此\" src=\"https://devvv.cn/assets/images/all_file_upload_to_web_tools-9ff38186a11448dd834da46094fe07c2.png\" width=\"649\" height=\"577\" class=\"img_m9Pm\"></p>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"添加虚拟主机\">添加虚拟主机<a href=\"https://devvv.cn/blog/synology-web-station-add-second-site-setup#%E6%B7%BB%E5%8A%A0%E8%99%9A%E6%8B%9F%E4%B8%BB%E6%9C%BA\" class=\"hash-link\" aria-label=\"添加虚拟主机的直接链接\" title=\"添加虚拟主机的直接链接\" translate=\"no\">​</a></h3>\n<p>打开 <code>Web Station</code>，进入 <code>Web Station</code> &gt; 网络门户 或 虚拟主机，点击 <code>新增</code>，选择 <code>网页门户服务</code>：</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"网页门户服务\" src=\"https://devvv.cn/assets/images/web_station_all_web_config_select_1-2b03426369cd7d74a5d85317cda02571.png\" width=\"1048\" height=\"698\" class=\"img_m9Pm\"></p>\n<p>在 <code>服务</code> 项点击展开下拉列表，选择 <code>新增服务</code>：</p>\n<ul>\n<li class=\"\">文档根目录：选择刚刚为第二个站点创建的文件夹（如 <code>/web_tools</code>）。</li>\n<li class=\"\"><code>HTTP</code> 后端服务器：保持默认的 <code>Nginx</code> 即可。</li>\n</ul>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"新增服务\" src=\"https://devvv.cn/assets/images/2d8c2a4e-bc30-48e7-8b5b-73e8520519bf-ea677dad9e829326d0331995a7068942.png\" width=\"1257\" height=\"515\" class=\"img_m9Pm\"></p>\n<p><code>门户类型</code> 选择 <code>基于端口</code> 的标签页下进行配置：</p>\n<ul>\n<li class=\"\">端口：输入一个未被占用的端口号，如 <code>8081</code>。</li>\n</ul>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"基于端口\" src=\"data:image/png;base64,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\" width=\"594\" height=\"477\" class=\"img_m9Pm\"></p>\n<p>然后进行局域网访问测试：</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">http://192.168.3.7:8081</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">text</span></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"添加映射\">添加映射<a href=\"https://devvv.cn/blog/synology-web-station-add-second-site-setup#%E6%B7%BB%E5%8A%A0%E6%98%A0%E5%B0%84\" class=\"hash-link\" aria-label=\"添加映射的直接链接\" title=\"添加映射的直接链接\" translate=\"no\">​</a></h3>\n<p>接下来，需要让花生壳将这个新的内网地址和端口映射到公网。</p>\n<p>先添加一个子域名，开启花生壳状态开关，解析模式切换为 <code>内网穿透</code>：</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"子域名内网穿透\" src=\"https://devvv.cn/assets/images/06ecd7d1-5068-4e5d-b1d0-b6b4d156c9cd-fe30a31cb396fae9493753d8e061be87.png\" width=\"1954\" height=\"361\" class=\"img_m9Pm\"></p>\n<p>在 <code>内网穿透</code> 页面，点击 <code>添加映射</code>：</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"子域名内网穿透\" src=\"data:image/png;base64,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\" width=\"747\" height=\"404\" class=\"img_m9Pm\"></p>\n<p>然后去 <code>套间中心</code> 先 <code>停用</code> 或 <code>停止</code> 花生壳，最后再 <code>启动</code> 即可正常访问。</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">http://tool.devvv.cn</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">text</span></div></div></div>",
            "url": "https://devvv.cn/blog/synology-web-station-add-second-site-setup",
            "title": "群晖 Web Station 中部署第二个站点",
            "summary": "群晖 Web Station 中部署第二个站点",
            "date_modified": "2026-03-29T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "群晖"
            ]
        },
        {
            "id": "https://devvv.cn/blog/mysql-ofential-commands-usage",
            "content_html": "<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"查看表结构\">查看表结构<a href=\"https://devvv.cn/blog/mysql-ofential-commands-usage#%E6%9F%A5%E7%9C%8B%E8%A1%A8%E7%BB%93%E6%9E%84\" class=\"hash-link\" aria-label=\"查看表结构的直接链接\" title=\"查看表结构的直接链接\" translate=\"no\">​</a></h3>\n<div class=\"language-sql codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-sql codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- 查看表结构</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DESC</span><span class=\"token plain\"> 表名</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- 或</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">SHOW</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">FULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COLUMNS</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">FROM</span><span class=\"token plain\"> 表名</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">sql</span></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"删除表\">删除表<a href=\"https://devvv.cn/blog/mysql-ofential-commands-usage#%E5%88%A0%E9%99%A4%E8%A1%A8\" class=\"hash-link\" aria-label=\"删除表的直接链接\" title=\"删除表的直接链接\" translate=\"no\">​</a></h3>\n<div class=\"language-sql codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-sql codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- 方法1：删除表结构和数据（最常用）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DROP</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">TABLE</span><span class=\"token plain\"> 表名</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- 方法2：删除前先检查表是否存在</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DROP</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">TABLE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">IF</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">EXISTS</span><span class=\"token plain\"> 表名</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- 方法3：清空表数据但保留表结构（如果需要保留表结构）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">TRUNCATE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">TABLE</span><span class=\"token plain\"> 表名</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">sql</span></div></div></div>\n<p><strong>说明：</strong></p>\n<ul>\n<li class=\"\"><code>DROP TABLE</code>：彻底删除表结构和所有数据，不可恢复</li>\n<li class=\"\"><code>DROP TABLE IF EXISTS</code>：安全删除，表不存在时不会报错</li>\n<li class=\"\"><code>TRUNCATE TABLE</code>：只清空数据，保留表结构，速度更快，但无法回滚</li>\n</ul>\n<p>请将 <code>表名</code> 替换为实际的表名。</p>",
            "url": "https://devvv.cn/blog/mysql-ofential-commands-usage",
            "title": "mysql 常用命令",
            "summary": "mysql 常用命令",
            "date_modified": "2026-03-27T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "MySQL"
            ]
        },
        {
            "id": "https://devvv.cn/blog/docker-delete-container",
            "content_html": "<p>要清空所有 Docker 容器，可以使用以下命令：</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"1-删除所有已停止的容器\">1. 删除所有已停止的容器<a href=\"https://devvv.cn/blog/docker-delete-container#1-%E5%88%A0%E9%99%A4%E6%89%80%E6%9C%89%E5%B7%B2%E5%81%9C%E6%AD%A2%E7%9A%84%E5%AE%B9%E5%99%A8\" class=\"hash-link\" aria-label=\"1. 删除所有已停止的容器的直接链接\" title=\"1. 删除所有已停止的容器的直接链接\" translate=\"no\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> container prune</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>系统会提示确认，输入 <code>y</code> 即可删除所有已停止的容器。</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"docker删除容器后\" src=\"https://devvv.cn/assets/images/docker_delete_after-86921d35535297d320d9c0e6288a3345.png\" width=\"1577\" height=\"775\" class=\"img_m9Pm\"></p>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"2-强制删除所有容器包括运行中的\">2. 强制删除所有容器（包括运行中的）<a href=\"https://devvv.cn/blog/docker-delete-container#2-%E5%BC%BA%E5%88%B6%E5%88%A0%E9%99%A4%E6%89%80%E6%9C%89%E5%AE%B9%E5%99%A8%E5%8C%85%E6%8B%AC%E8%BF%90%E8%A1%8C%E4%B8%AD%E7%9A%84\" class=\"hash-link\" aria-label=\"2. 强制删除所有容器（包括运行中的）的直接链接\" title=\"2. 强制删除所有容器（包括运行中的）的直接链接\" translate=\"no\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">rm</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-f</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">ps</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-aq</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>这个命令会：</p>\n<ul>\n<li class=\"\"><code>docker ps -aq</code>：列出所有容器的 ID</li>\n<li class=\"\"><code>docker rm -f</code>：强制删除容器（即使正在运行）</li>\n</ul>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"3-更安全的方式---先停止再删除\">3. 更安全的方式 - 先停止再删除<a href=\"https://devvv.cn/blog/docker-delete-container#3-%E6%9B%B4%E5%AE%89%E5%85%A8%E7%9A%84%E6%96%B9%E5%BC%8F---%E5%85%88%E5%81%9C%E6%AD%A2%E5%86%8D%E5%88%A0%E9%99%A4\" class=\"hash-link\" aria-label=\"3. 更安全的方式 - 先停止再删除的直接链接\" title=\"3. 更安全的方式 - 先停止再删除的直接链接\" translate=\"no\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 停止所有运行中的容器</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> stop </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">ps</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-q</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 删除所有容器</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">rm</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">ps</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-aq</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"执行后的效果\">执行后的效果<a href=\"https://devvv.cn/blog/docker-delete-container#%E6%89%A7%E8%A1%8C%E5%90%8E%E7%9A%84%E6%95%88%E6%9E%9C\" class=\"hash-link\" aria-label=\"执行后的效果的直接链接\" title=\"执行后的效果的直接链接\" translate=\"no\">​</a></h3>\n<p>根据你提供的列表，这些容器都会被删除：</p>\n<ul>\n<li class=\"\">friendly-server-d</li>\n<li class=\"\">friendly-redis</li>\n<li class=\"\">astrowind</li>\n<li class=\"\">blog-dev</li>\n<li class=\"\">friendly-prod</li>\n<li class=\"\">friendlyserver-v</li>\n<li class=\"\">friendlyserver-my</li>\n<li class=\"\">reverent_ganguly</li>\n</ul>\n<hr>\n<p><strong>建议</strong>：如果你还想清理未使用的镜像、卷等资源，可以执行：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> system prune </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-a</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>这个命令会清理所有未使用的容器、镜像、网络和构建缓存。</p>",
            "url": "https://devvv.cn/blog/docker-delete-container",
            "title": "docker 删除容器",
            "summary": "docker 删除容器",
            "date_modified": "2026-03-25T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "docker"
            ]
        },
        {
            "id": "https://devvv.cn/blog/service-from-cpp-to-springboot-nice",
            "content_html": "<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"创建项目\">创建项目<a href=\"https://devvv.cn/blog/service-from-cpp-to-springboot-nice#%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE\" class=\"hash-link\" aria-label=\"创建项目的直接链接\" title=\"创建项目的直接链接\" translate=\"no\">​</a></h3>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"SpringBoot新建项目第一步\" src=\"https://devvv.cn/assets/images/SpringBoot_project_setup_first_step-0b79e3b5f421a5af7961c70553694d49.png\" width=\"967\" height=\"769\" class=\"img_m9Pm\"></p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"SpringBoot新建项目勾选依赖\" src=\"https://devvv.cn/assets/images/SpringBoot_project_setup_check_dependency-fc59ee06a8a2c9dd0cf655a195490797.png\" width=\"961\" height=\"760\" class=\"img_m9Pm\"></p>\n<p>完整的 <code>build.gradle.kts</code> 文件如下：</p>\n<div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">build.gradle.kts<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">plugins </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">kotlin</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"jvm\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> version </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"2.2.21\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">kotlin</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"plugin.spring\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> version </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"2.2.21\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"org.springframework.boot\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> version </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"4.0.4\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"io.spring.dependency-management\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> version </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"1.1.7\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">kotlin</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"plugin.jpa\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> version </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"2.2.21\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">group </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"com.vv\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">version </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"0.0.1-SNAPSHOT\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">description </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"FriendlyServerV2\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">java </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    toolchain </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        languageVersion </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> JavaLanguageVersion</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">of</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">17</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">repositories </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">mavenCentral</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">dependencies </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">implementation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"org.springframework.boot:spring-boot-starter-data-jpa\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">implementation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"org.springframework.boot:spring-boot-starter-data-redis\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">implementation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"org.springframework.boot:spring-boot-starter-webmvc\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">implementation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"org.jetbrains.kotlin:kotlin-reflect\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">implementation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"tools.jackson.module:jackson-module-kotlin\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">developmentOnly</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"org.springframework.boot:spring-boot-devtools\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">runtimeOnly</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"com.mysql:mysql-connector-j\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">testImplementation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"org.springframework.boot:spring-boot-starter-data-jpa-test\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">testImplementation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"org.springframework.boot:spring-boot-starter-data-redis-test\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">testImplementation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"org.springframework.boot:spring-boot-starter-webmvc-test\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">testImplementation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"org.jetbrains.kotlin:kotlin-test-junit5\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">testRuntimeOnly</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"org.junit.platform:junit-platform-launcher\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">implementation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"org.springframework.boot:spring-boot-starter-security\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">implementation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"io.netty:netty-all:4.2.5.Final\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\">   </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 包含所有 Netty 组件，也可按需拆分</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">implementation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"io.jsonwebtoken:jjwt-api:0.12.6\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">runtimeOnly</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"io.jsonwebtoken:jjwt-impl:0.12.6\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">runtimeOnly</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"io.jsonwebtoken:jjwt-jackson:0.12.6\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">kotlin </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    compilerOptions </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        freeCompilerArgs</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">addAll</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"-Xjsr305=strict\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"-Xannotation-default-target=param-property\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">allOpen </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"jakarta.persistence.Entity\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"jakarta.persistence.MappedSuperclass\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"jakarta.persistence.Embeddable\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">tasks</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">withType</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Test</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">useJUnitPlatform</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"docker-容器化\">Docker 容器化<a href=\"https://devvv.cn/blog/service-from-cpp-to-springboot-nice#docker-%E5%AE%B9%E5%99%A8%E5%8C%96\" class=\"hash-link\" aria-label=\"Docker 容器化的直接链接\" title=\"Docker 容器化的直接链接\" translate=\"no\">​</a></h3>\n<div class=\"theme-tabs-container tabs-container tabList_D8NW\"><ul role=\"tablist\" aria-orientation=\"horizontal\" class=\"tabs\"><li role=\"tab\" tabindex=\"0\" aria-selected=\"true\" class=\"tabs__item tabItem_OkUL tabs__item--active\">Dockerfile.dev</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">Dockerfile.prod</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">docker-compose.yml</li></ul><div class=\"margin-top--md\"><div role=\"tabpanel\" class=\"tabItem_fvDV\"><div class=\"language-Dockerfile language-dockerfile codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">Dockerfile.dev<span style=\"flex:1;text-align:right\">dockerfile</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-dockerfile codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 使用 Ubuntu 24.04 作为基础镜像</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">FROM ubuntu:24.04 AS dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 设置时区，避免交互式安装</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ENV DEBIAN_FRONTEND=noninteractive</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ENV TZ=Asia/Shanghai</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 更新系统并安装必要工具：wget、unzip、curl（健康检查）、OpenJDK 17</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">RUN apt-get update &amp;&amp; \\</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    apt-get install -y --no-install-recommends \\</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        wget \\</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        unzip \\</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        curl \\</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        openjdk-17-jdk \\</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        &amp;&amp; \\</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    rm -rf /var/lib/apt/lists/*</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 安装 Gradle 9.4.0</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ENV GRADLE_VERSION=9.4.0</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ENV GRADLE_HOME=/opt/gradle</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">RUN wget -q https://mirrors.cloud.tencent.com/gradle/gradle-${GRADLE_VERSION}-bin.zip -O /tmp/gradle.zip &amp;&amp; \\</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    unzip /tmp/gradle.zip -d /opt &amp;&amp; \\</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    rm /tmp/gradle.zip &amp;&amp; \\</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    mv /opt/gradle-${GRADLE_VERSION} ${GRADLE_HOME} &amp;&amp; \\</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    ln -s ${GRADLE_HOME}/bin/gradle /usr/local/bin/gradle</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 设置工作目录（与 docker-compose 中的卷挂载路径一致）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">WORKDIR /workspace</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 暴露端口（HTTP 端口 8080，自定义 Netty 端口 8081）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">EXPOSE 8080 8081</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 使用 gradle bootRun 启动，开启 Spring Boot DevTools 热重启</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 添加 --no-daemon 避免守护进程残留</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">CMD [\"./gradlew\", \"bootRun\", \"--no-daemon\"]</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-Dockerfile language-dockerfile codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">Dockerfile.prod<span style=\"flex:1;text-align:right\">dockerfile</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-dockerfile codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 阶段一：构建（使用 JDK 17 基础镜像 + Gradle）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">FROM eclipse-temurin:17-jdk AS builder</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 安装 Gradle 9.4.0</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ENV GRADLE_VERSION=9.4.0</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ENV GRADLE_HOME=/opt/gradle</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">RUN apt-get update &amp;&amp; apt-get install -y wget unzip &amp;&amp; \\</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    wget -q https://mirrors.cloud.tencent.com/gradle/gradle-${GRADLE_VERSION}-bin.zip -O /tmp/gradle.zip &amp;&amp; \\</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    unzip /tmp/gradle.zip -d /opt &amp;&amp; \\</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    rm /tmp/gradle.zip &amp;&amp; \\</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    mv /opt/gradle-${GRADLE_VERSION} ${GRADLE_HOME} &amp;&amp; \\</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    ln -s ${GRADLE_HOME}/bin/gradle /usr/local/bin/gradle</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">WORKDIR /build</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 先复制构建脚本和 Gradle Wrapper，利用 Docker 缓存</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">COPY build.gradle.kts settings.gradle.kts gradle.properties ./</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">COPY gradle gradle</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">RUN gradle dependencies --no-daemon</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 复制源码并构建可执行 jar</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">COPY src src</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">RUN gradle bootJar --no-daemon</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 阶段二：运行（使用精简 JRE 镜像）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">FROM eclipse-temurin:17-jre-alpine</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 创建非 root 用户运行应用</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">RUN addgroup -S appgroup &amp;&amp; adduser -S appuser -G appgroup</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">USER appuser</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">WORKDIR /app</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 从构建阶段复制 jar 包</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">COPY --from=builder /build/build/libs/*.jar app.jar</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 暴露端口（HTTP 端口 8080，自定义 Netty 端口 8081）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 注意：与 docker-compose 中映射的端口保持一致</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">EXPOSE 8080 8081</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 启动应用，支持通过环境变量覆盖配置</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ENTRYPOINT [\"java\", \"-jar\", \"app.jar\"]</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-yaml codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-yaml codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">#version: '3.8'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">services</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">mysql</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">image</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> mysql</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">8.0</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">container_name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> friendly</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">mysql</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">restart</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> unless</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">stopped</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"999:999\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">environment</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">MYSQL_ROOT_PASSWORD</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> root</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">MYSQL_DATABASE</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> db_friendly</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">MYSQL_USER</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> vv</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">MYSQL_PASSWORD</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> vvpwd123</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">MYSQL_CHARSET</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> utf8mb4</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">MYSQL_COLLATION</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> utf8mb4_unicode_ci</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">ports</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"3306:3306\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">volumes</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> mysql_data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/var/lib/mysql</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./src/main/resources/db/init.sql</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/docker</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">entrypoint</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">initdb.d/init.sql</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">command</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">default</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">authentication</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">plugin=mysql_native_password</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">character</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">set</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">server=utf8mb4</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">collation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">server=utf8mb4_unicode_ci</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">healthcheck</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">test</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"CMD\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"mysqladmin\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"ping\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"-h\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"localhost\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">interval</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> 10s</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">timeout</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> 5s</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">retries</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">5</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">networks</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> friendly</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">network</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">redis</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">image</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> redis</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">7</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">alpine</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">container_name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> friendly</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">redis</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">ports</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"6379:6379\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">healthcheck</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">test</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"CMD\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"redis-cli\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"ping\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">interval</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> 10s</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">timeout</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> 5s</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">retries</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">5</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">networks</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> friendly</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">network</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">dev</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">profiles</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"dev\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">build</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">context</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> .</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">dockerfile</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> docker/Dockerfile.dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">container_name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">volumes</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> .</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/workspace</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> build_cache</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/workspace/build</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">ports</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"8080:8080\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"8081:8081\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">depends_on</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">mysql</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">condition</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> service_healthy</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">redis</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">condition</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> service_healthy</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">environment</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">SPRING_DATASOURCE_URL</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> jdbc</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">mysql</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">//mysql</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">3306/db_friendly</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">?</span><span class=\"token plain\">useSSL=false</span><span class=\"token important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">&amp;serverTimezone=UTC</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">SPRING_DATASOURCE_USERNAME</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> vv</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">SPRING_DATASOURCE_PASSWORD</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> vvpwd123</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">SPRING_DATA_REDIS_HOST</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> redis</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">SPRING_DATA_REDIS_PORT</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">6379</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">networks</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> friendly</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">network</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">stdin_open</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">true</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">tty</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">true</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">prod</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">profiles</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"prod\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">build</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">context</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> .</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">dockerfile</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> docker/Dockerfile.prod</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">container_name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> prod</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">ports</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"8080:8080\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"8081:8081\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">environment</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">SPRING_DATASOURCE_URL</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> jdbc</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">mysql</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">//mysql</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">3306/db_friendly</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">?</span><span class=\"token plain\">useSSL=false</span><span class=\"token important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">&amp;serverTimezone=UTC</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">SPRING_DATASOURCE_USERNAME</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> vv</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">SPRING_DATASOURCE_PASSWORD</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> vvpwd123</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">SPRING_DATA_REDIS_HOST</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> redis</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">SPRING_DATA_REDIS_PORT</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">6379</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">#      SPRING_CONFIG_LOCATION: /etc/friendlyserver/application.yml</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">volumes</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./config</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/etc/friendlyserver</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">ro</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> logs</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/var/log/friendlyserver</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">depends_on</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">mysql</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">condition</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> service_healthy</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">redis</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">condition</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> service_healthy</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">networks</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> friendly</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">network</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">restart</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> unless</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">stopped</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">volumes</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">mysql_data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">build_cache</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">logs</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">networks</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">friendly-network</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">driver</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> bridge</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">yaml</span></div></div></div></div></div></div>\n<p>相关命令：</p>\n<div class=\"theme-tabs-container tabs-container tabList_D8NW\"><ul role=\"tablist\" aria-orientation=\"horizontal\" class=\"tabs\"><li role=\"tab\" tabindex=\"0\" aria-selected=\"true\" class=\"tabs__item tabItem_OkUL tabs__item--active\">开发环境</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">生产环境</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">停止服务</li></ul><div class=\"margin-top--md\"><div role=\"tabpanel\" class=\"tabItem_fvDV\"><div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 每次修改代码后，先停止服务再启动</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> stop dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--profile</span><span class=\"token plain\"> dev up </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-d</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--profile</span><span class=\"token plain\"> dev up</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 日志查看</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose logs </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-f</span><span class=\"token plain\"> dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 重新构建（代码修改后）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--profile</span><span class=\"token plain\"> dev up </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-d</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--build</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--profile</span><span class=\"token plain\"> prod up </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-d</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 日志查看</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose logs </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-f</span><span class=\"token plain\"> prod</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose down</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div></div></div></div>\n<p>新增测试接口：</p>\n<div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">TestController.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">controller</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">web</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bind</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">GetMapping</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">web</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bind</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">RestController</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RestController</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> TestController </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@GetMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/test\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">test</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Map</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">mapOf</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"message\"</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">to</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"Hello from FriendlyServer\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<p>如果端口被占用：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查看占用的进程</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">lsof</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-i</span><span class=\"token plain\"> :6379</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 停止本地Redis进程</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> systemctl stop redis-server</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 禁止开机自启</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> systemctl disable redis-server</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> systemctl disable mysql</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 重启开发环境</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--profile</span><span class=\"token plain\"> dev up </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-d</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>多等一会儿，就能成功启动了。</p>\n<p>然后访问 <a href=\"http://localhost:8080/test\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">http://localhost:8080/test</a> 测试接口。</p>\n<p><strong>开发环境下，大部分代码变更不需要重启 Docker 容器</strong>，因为：</p>\n<ol>\n<li class=\"\"><strong>卷挂载</strong>：<code>- .:/workspace</code> 将宿主机源码目录同步到容器内。</li>\n<li class=\"\"><strong>热重载</strong>：Spring Boot DevTools 已启用（日志中出现 <code>Devtools property defaults active</code>），它会监听类路径变化，自动重启应用上下文。</li>\n<li class=\"\"><strong>Gradle 持续运行</strong>：<code>./gradlew bootRun</code> 会检测源码变化并重新编译、重新加载。</li>\n</ol>\n<p><strong>少数情况需要重启容器</strong>：</p>\n<ul>\n<li class=\"\">修改了 <code>build.gradle.kts</code>（依赖变更）或 <code>application.yml</code> 等配置文件。</li>\n<li class=\"\">新增了实体类或需要重新生成数据库表（如果使用 <code>ddl-auto</code> 且变更较大）。</li>\n<li class=\"\">新增了 Netty 自定义协议服务且需要在启动时初始化（<code>@PostConstruct</code> 可能不会重新执行？实际 DevTools 重启会重新初始化，通常没问题）。</li>\n</ul>\n<p><strong>建议做法</strong>：</p>\n<ul>\n<li class=\"\">修改代码后，等待几秒，控制台应出现 <code>Restarted main</code> 日志，说明热重载完成。</li>\n<li class=\"\">如果看不到重启或报错，执行 <code>docker compose restart dev</code> 重启容器即可。</li>\n</ul>\n<p><strong>生产环境</strong>：代码变更必须重新构建镜像并重启容器。</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"mysql-初始化\">mysql 初始化<a href=\"https://devvv.cn/blog/service-from-cpp-to-springboot-nice#mysql-%E5%88%9D%E5%A7%8B%E5%8C%96\" class=\"hash-link\" aria-label=\"mysql 初始化的直接链接\" title=\"mysql 初始化的直接链接\" translate=\"no\">​</a></h3>\n<p>将 <code>init.sql</code> 放到 <code>src/main/resources/db/init.sql</code>（如果目录不存在则创建）：</p>\n<div class=\"language-sql codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">init.sql<span style=\"flex:1;text-align:right\">sql</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-sql codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- 用户基本信息表( KEY idx_username (username)  -- 添加索引提升登录查询速度)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CREATE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">TABLE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">IF</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">EXISTS</span><span class=\"token plain\"> platform_user</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    id            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">INT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">PRIMARY</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">AUTO_INCREMENT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'用户唯一ID'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    username      </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">50</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">UNIQUE</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'用户名，用于登录和显示'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    password_hash </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'密码哈希值'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    nickname      </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">50</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'用户昵称'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    avatar_url    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'头像URL'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    email         </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'绑定的邮箱'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    phone         </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">50</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'绑定的手机号'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    bio           </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">TEXT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'个人简介'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    last_login_at </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DATETIME</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'最后登录时间'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    created_at    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DATETIME</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CURRENT_TIMESTAMP</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'创建时间'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    updated_at    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DATETIME</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CURRENT_TIMESTAMP</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">ON</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">UPDATE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CURRENT_TIMESTAMP</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'更新时间'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    is_deleted    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">TINYINT</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'软删除标记(0:正常 1:删除)'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> idx_username </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">username</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> idx_is_deleted </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">is_deleted</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> idx_created_at </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">created_at</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">ENGINE</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">InnoDB</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CHARSET</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">utf8mb4 </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'用户基本信息表'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- 平台信息表</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CREATE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">TABLE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">IF</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">EXISTS</span><span class=\"token plain\"> platform_info</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    id            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">INT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">PRIMARY</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">AUTO_INCREMENT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'平台ID'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    name          </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">100</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">UNIQUE</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'平台名称/标识，例如：码云、QQ、GitHub'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    url           </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'平台网址'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    icon_url      </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'平台图标URL，可选'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    description   </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'平台描述'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    owner_user_id </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">INT</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'所属用户ID，关联platform_user表'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    created_at    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DATETIME</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CURRENT_TIMESTAMP</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'创建时间'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    updated_at    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DATETIME</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CURRENT_TIMESTAMP</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">ON</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">UPDATE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CURRENT_TIMESTAMP</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'更新时间'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">FOREIGN</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">owner_user_id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">REFERENCES</span><span class=\"token plain\"> platform_user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">ON</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DELETE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">RESTRICT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">ON</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">UPDATE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CASCADE</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> idx_owner_user_id </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">owner_user_id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">ENGINE</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">InnoDB</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CHARSET</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">utf8mb4 </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'平台信息表'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- 账号密码表（关联平台）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- UNIQUE KEY uk_user_platform_account (owner_user_id, platform_id, account_name): 防止同一用户在同一平台重复添加同一个账号</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CREATE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">TABLE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">IF</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">EXISTS</span><span class=\"token plain\"> platform_account</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    id            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">INT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">PRIMARY</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">AUTO_INCREMENT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'主键ID'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    platform_id   </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">INT</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'平台ID，关联platform_info表'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    account_name  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">100</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'登录账号/用户名'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    password_hash </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'密码（加密存储）'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    bound_email   </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'绑定的邮箱'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    bound_phone   </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">50</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'绑定的手机号'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    owner_user_id </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">INT</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'所属用户ID，关联platform_user表'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    remark        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">TEXT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'备注信息'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    created_at    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DATETIME</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CURRENT_TIMESTAMP</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'创建时间'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    updated_at    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DATETIME</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CURRENT_TIMESTAMP</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">ON</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">UPDATE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CURRENT_TIMESTAMP</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'更新时间'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">FOREIGN</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">platform_id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">REFERENCES</span><span class=\"token plain\"> platform_info</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">ON</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DELETE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CASCADE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">ON</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">UPDATE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CASCADE</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">FOREIGN</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">owner_user_id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">REFERENCES</span><span class=\"token plain\"> platform_user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">ON</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DELETE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">RESTRICT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">ON</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">UPDATE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CASCADE</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">UNIQUE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> uk_user_platform_account </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">owner_user_id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> platform_id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> account_name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> idx_platform_id </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">platform_id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> idx_account_name </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">account_name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> idx_bound_email </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">bound_email</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> idx_bound_phone </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">bound_phone</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> idx_owner_user_id </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">owner_user_id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> idx_user_platform </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">owner_user_id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> platform_id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">ENGINE</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">InnoDB</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CHARSET</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">utf8mb4 </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'平台账号表（含绑定信息）'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- 插入用户</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- INSERT INTO platforms_users (username, password_hash, nickname)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- VALUES ('zhangsan', 'hashed_password_here', '张三');</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- -- 插入平台</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- INSERT INTO platforms_info (name, url)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- VALUES ('码云', 'https://gitee.com'), ('GitHub', 'https://github.com');</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- -- 插入账号密码记录（owner_user_id 用 INT 类型）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- INSERT INTO platforms_account_passwords</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- (platform_id, account_name, password_hash, owner_user_id, bound_email, bound_phone)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- VALUES(1, 'zhangsan_gitee', 'pwd_hash', 1, 'zhang@email.com', '13800138000');</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">-- web 站点首页埋点</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CREATE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">TABLE</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">IF</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">EXISTS</span><span class=\"token plain\"> web_page_track_home</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    id                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">BIGINT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">PRIMARY</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">AUTO_INCREMENT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'访问记录唯一ID'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    visit_timestamp   </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">BIGINT</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'访问时间戳(毫秒)'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    visit_date        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DATETIME</span><span class=\"token plain\"> GENERATED ALWAYS </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">AS</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">FROM_UNIXTIME</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">visit_timestamp</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">/</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1000</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> STORED </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'访问日期(方便查询)'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    url               </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">500</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'访问的完整URL'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    referrer          </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">500</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'来源页面'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    referrer_domain   </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> GENERATED ALWAYS </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">AS</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">SUBSTRING_INDEX</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">SUBSTRING_INDEX</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">referrer</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'/'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'://'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">-</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> STORED </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'来源域名'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    user_agent        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">TEXT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'用户浏览器信息'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    browser           </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">50</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> GENERATED ALWAYS </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">AS</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CASE</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">WHEN</span><span class=\"token plain\"> user_agent </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">LIKE</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'%Chrome%'</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">AND</span><span class=\"token plain\"> user_agent </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">LIKE</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'%Edg%'</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">THEN</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Chrome'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">WHEN</span><span class=\"token plain\"> user_agent </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">LIKE</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'%Edg%'</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">THEN</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Edge'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">WHEN</span><span class=\"token plain\"> user_agent </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">LIKE</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'%Firefox%'</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">THEN</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Firefox'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">WHEN</span><span class=\"token plain\"> user_agent </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">LIKE</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'%Safari%'</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">AND</span><span class=\"token plain\"> user_agent </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">NOT</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">LIKE</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'%Chrome%'</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">THEN</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Safari'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">ELSE</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Other'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">END</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> STORED </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'浏览器类型'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    os                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">50</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> GENERATED ALWAYS </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">AS</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CASE</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">WHEN</span><span class=\"token plain\"> user_agent </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">LIKE</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'%Windows%'</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">THEN</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Windows'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">WHEN</span><span class=\"token plain\"> user_agent </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">LIKE</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'%Mac OS%'</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">THEN</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'macOS'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">WHEN</span><span class=\"token plain\"> user_agent </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">LIKE</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'%Linux%'</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">THEN</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Linux'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">WHEN</span><span class=\"token plain\"> user_agent </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">LIKE</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'%Android%'</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">THEN</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Android'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">WHEN</span><span class=\"token plain\"> user_agent </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">LIKE</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'%iPhone%'</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">OR</span><span class=\"token plain\"> user_agent </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">LIKE</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'%iPad%'</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">THEN</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'iOS'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">ELSE</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Other'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">END</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> STORED </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'操作系统'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    device_type       </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">20</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> GENERATED ALWAYS </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">AS</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CASE</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">WHEN</span><span class=\"token plain\"> user_agent </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">LIKE</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'%Mobile%'</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">THEN</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Mobile'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">WHEN</span><span class=\"token plain\"> user_agent </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">LIKE</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'%Tablet%'</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">THEN</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Tablet'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">ELSE</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'Desktop'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">END</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> STORED </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'设备类型'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">language</span><span class=\"token plain\">          </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">20</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'浏览器语言'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    screen_resolution </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">20</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'屏幕分辨率'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    ip_address        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">VARCHAR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">45</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">NULL</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'访问者IP地址'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    created_at        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DATETIME</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CURRENT_TIMESTAMP</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'记录创建时间'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> idx_visit_date </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">visit_date</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> idx_referrer_domain </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">referrer_domain</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> idx_browser </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">browser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> idx_os </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">os</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> idx_device_type </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">device_type</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">KEY</span><span class=\"token plain\"> idx_created_at </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">created_at</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">ENGINE</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">InnoDB</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">DEFAULT</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">CHARSET</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">utf8mb4 </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">COMMENT</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'web首页访问统计表'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<p>由于容器已存在数据卷 mysql_data，首次启动后数据库已初始化，再次启动不会重新执行脚本。因此需要删除现有数据卷，让 MySQL 重新初始化：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--profile</span><span class=\"token plain\"> dev down </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-v</span><span class=\"token plain\">   </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 删除容器和数据卷</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--profile</span><span class=\"token plain\"> dev up </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-d</span><span class=\"token plain\">     </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 重新启动，此时会执行 init.sql</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>完成后，<code>MySQL</code> 会按 <code>init.sql</code> 建表。</p>\n<p>执行以下命令进入 MySQL 容器并查看表：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exec</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-it</span><span class=\"token plain\"> friendly-mysql mysql </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-uroot</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-proot</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>进入 MySQL 后，执行：</p>\n<div class=\"language-sql codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-sql codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">SHOW</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">databases</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">USE</span><span class=\"token plain\"> db_friendly</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">SHOW</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">TABLES</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">sql</span></div></div></div>\n<p>如果看到 <code>platform_user</code>、<code>platform_info</code>、<code>platform_account</code>、<code>web_page_track_home</code> 四张表，则表示建表成功。</p>\n<p>退出 MySQL：输入 <code>exit</code> 或按 <code>Ctrl+D</code>。</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"验证Mysql表是否初始化成功\" src=\"https://devvv.cn/assets/images/verify_mysql_table_is_init_success-9cc7cbb6c1f2b53b67793c14c7a58cea.png\" width=\"999\" height=\"804\" class=\"img_m9Pm\"></p>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"创建-jpa-实体类\">创建 JPA 实体类<a href=\"https://devvv.cn/blog/service-from-cpp-to-springboot-nice#%E5%88%9B%E5%BB%BA-jpa-%E5%AE%9E%E4%BD%93%E7%B1%BB\" class=\"hash-link\" aria-label=\"创建 JPA 实体类的直接链接\" title=\"创建 JPA 实体类的直接链接\" translate=\"no\">​</a></h3>\n<p>在项目根目录下创建以下路径和文件：</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">src/main/kotlin/com/vv/friendlyserverv2/entity/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── PlatformUser.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── PlatformInfo.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── PlatformAccount.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">└── WebPageTrackHome.kt</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">text</span></div></div></div>\n<div class=\"theme-tabs-container tabs-container tabList_D8NW\"><ul role=\"tablist\" aria-orientation=\"horizontal\" class=\"tabs\"><li role=\"tab\" tabindex=\"0\" aria-selected=\"true\" class=\"tabs__item tabItem_OkUL tabs__item--active\">PlatformUser.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">PlatformInfo.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">PlatformAccount.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">WebPageTrackHome.kt</li></ul><div class=\"margin-top--md\"><div role=\"tabpanel\" class=\"tabItem_fvDV\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">PlatformUser.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">entity</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> jakarta</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">persistence</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">*</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">hibernate</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotations</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">CreationTimestamp</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">hibernate</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotations</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">UpdateTimestamp</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> java</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">time</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">LocalDateTime</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Entity</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Table</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"platform_user\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">PlatformUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Id</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@GeneratedValue</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">strategy </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> GenerationType</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">IDENTITY</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">unique </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> nullable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">50</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> username</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"password_hash\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> nullable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> passwordHash</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">50</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> nickname</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"avatar_url\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> avatarUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> email</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">50</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> phone</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">columnDefinition </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"TEXT\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> bio</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"last_login_at\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> lastLoginAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@CreationTimestamp</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"created_at\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> updatable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> createdAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">now</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@UpdateTimestamp</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"updated_at\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> updatedAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">now</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"is_deleted\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> isDeleted</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Boolean </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">PlatformInfo.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">entity</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> jakarta</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">persistence</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">*</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">hibernate</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotations</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">CreationTimestamp</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">hibernate</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotations</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">UpdateTimestamp</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> java</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">time</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">LocalDateTime</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Entity</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Table</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"platform_info\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">PlatformInfo</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Id</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@GeneratedValue</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">strategy </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> GenerationType</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">IDENTITY</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">unique </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> nullable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">100</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> url</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"icon_url\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> iconUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> description</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"owner_user_id\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> nullable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> ownerUserId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@CreationTimestamp</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"created_at\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> updatable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> createdAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">now</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@UpdateTimestamp</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"updated_at\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> updatedAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">now</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@ManyToOne</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">fetch </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> FetchType</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">LAZY</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@JoinColumn</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"owner_user_id\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> insertable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> updatable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> ownerUser</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PlatformUser</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">PlatformAccount.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">entity</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> jakarta</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">persistence</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">*</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">hibernate</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotations</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">CreationTimestamp</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">hibernate</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotations</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">UpdateTimestamp</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> java</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">time</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">LocalDateTime</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Entity</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Table</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"platform_account\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    uniqueConstraints </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">UniqueConstraint</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"uk_user_platform_account\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            columnNames </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"owner_user_id\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"platform_id\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"account_name\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">PlatformAccount</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Id</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@GeneratedValue</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">strategy </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> GenerationType</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">IDENTITY</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"platform_id\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> nullable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> platformId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"account_name\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> nullable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">100</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> accountName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"password_hash\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> nullable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> passwordHash</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"bound_email\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> boundEmail</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"bound_phone\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">50</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> boundPhone</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"owner_user_id\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> nullable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> ownerUserId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">columnDefinition </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"TEXT\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> remark</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@CreationTimestamp</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"created_at\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> updatable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> createdAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">now</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@UpdateTimestamp</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"updated_at\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> updatedAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">now</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@ManyToOne</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">fetch </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> FetchType</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">LAZY</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@JoinColumn</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"platform_id\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> insertable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> updatable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> platformInfo</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PlatformInfo</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@ManyToOne</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">fetch </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> FetchType</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">LAZY</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@JoinColumn</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"owner_user_id\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> insertable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> updatable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> ownerUser</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PlatformUser</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">WebPageTrackHome.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">entity</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> jakarta</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">persistence</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">*</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">hibernate</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotations</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">CreationTimestamp</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> java</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">time</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">LocalDateTime</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Entity</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Table</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"web_page_track_home\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">WebPageTrackHome</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Id</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@GeneratedValue</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">strategy </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> GenerationType</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">IDENTITY</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"visit_timestamp\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> nullable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> visitTimestamp</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Long</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">nullable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">500</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> url</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">500</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> referrer</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"user_agent\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> columnDefinition </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"TEXT\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> userAgent</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">20</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> language</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"screen_resolution\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">20</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> screenResolution</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"ip_address\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">45</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> ipAddress</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@CreationTimestamp</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Column</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"created_at\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> updatable </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> createdAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">now</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div></div></div>\n<hr>\n<p>创建完成后，运行以下命令确认实体类能被 JPA 扫描到：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--profile</span><span class=\"token plain\"> dev restart dev</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>查看日志，没报错就行：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose logs </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-f</span><span class=\"token plain\"> dev</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"创建-repository\">创建 Repository<a href=\"https://devvv.cn/blog/service-from-cpp-to-springboot-nice#%E5%88%9B%E5%BB%BA-repository\" class=\"hash-link\" aria-label=\"创建 Repository的直接链接\" title=\"创建 Repository的直接链接\" translate=\"no\">​</a></h3>\n<p>在项目根目录下创建以下路径和文件：</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">src/main/kotlin/com/vv/friendlyserverv2/repository/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── PlatformUserRepository.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── PlatformInfoRepository.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── PlatformAccountRepository.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">└── WebPageTrackHomeRepository.kt</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">text</span></div></div></div>\n<div class=\"theme-tabs-container tabs-container tabList_D8NW\"><ul role=\"tablist\" aria-orientation=\"horizontal\" class=\"tabs\"><li role=\"tab\" tabindex=\"0\" aria-selected=\"true\" class=\"tabs__item tabItem_OkUL tabs__item--active\">PlatformUserRepository.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">PlatformInfoRepository.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">PlatformAccountRepository.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">WebPageTrackHomeRepository.kt</li></ul><div class=\"margin-top--md\"><div role=\"tabpanel\" class=\"tabItem_fvDV\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">PlatformUserRepository.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">entity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">PlatformUser</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jpa</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">JpaRepository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jpa</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Modifying</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jpa</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Query</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Param</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">stereotype</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Repository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> java</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">util</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">*</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Repository</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">interface</span><span class=\"token plain\"> PlatformUserRepository </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> JpaRepository</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">PlatformUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> Int</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 根据用户名查询未删除的用户</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findByUsernameAndIsDeletedFalse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">username</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Optional</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">PlatformUser</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 根据用户ID查询未删除的用户</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findByIdAndIsDeletedFalse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Optional</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">PlatformUser</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 检查用户名是否已存在（排除已删除的用户）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">existsByUsernameAndIsDeletedFalse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">username</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Boolean</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 更新最后登录时间</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Modifying</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"UPDATE PlatformUser u SET u.lastLoginAt = CURRENT_TIMESTAMP WHERE u.id = :userId AND u.isDeleted = false\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">updateLastLoginTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"userId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">PlatformInfoRepository.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">entity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">PlatformInfo</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jpa</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">JpaRepository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jpa</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Modifying</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jpa</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Query</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Param</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">stereotype</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Repository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Repository</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">interface</span><span class=\"token plain\"> PlatformInfoRepository </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> JpaRepository</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">PlatformInfo</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> Int</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 查询用户的所有平台（按创建时间排序）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"SELECT p FROM PlatformInfo p WHERE p.ownerUserId = :userId AND p.id IN (SELECT DISTINCT pi.id FROM PlatformInfo pi WHERE pi.ownerUserId = :userId) ORDER BY p.createdAt DESC\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findByOwnerUserIdOrderByCreatedAtDesc</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"userId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> List</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">PlatformInfo</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 检查平台名称是否已被当前用户使用</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"SELECT COUNT(p) &gt; 0 FROM PlatformInfo p WHERE p.ownerUserId = :userId AND p.name = :name\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">existsByOwnerUserIdAndName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"userId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"name\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Boolean</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 查询用户的所有平台（简化版，用于列表展示）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"SELECT p FROM PlatformInfo p WHERE p.ownerUserId = :userId ORDER BY p.createdAt DESC\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findAllByOwnerUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"userId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> List</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">PlatformInfo</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 删除指定用户的平台（同时检查所有权）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Modifying</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"DELETE FROM PlatformInfo p WHERE p.id = :platformId AND p.ownerUserId = :userId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">deleteByIdAndOwnerUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"platformId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> platformId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"userId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 批量删除指定用户的平台</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Modifying</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"DELETE FROM PlatformInfo p WHERE p.id IN :platformIds AND p.ownerUserId = :userId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">deleteAllByIdInAndOwnerUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"platformIds\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> platformIds</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> List</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Int</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"userId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">PlatformAccountRepository.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">entity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">PlatformAccount</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jpa</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">JpaRepository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jpa</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Modifying</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jpa</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Query</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Param</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">stereotype</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Repository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Repository</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">interface</span><span class=\"token plain\"> PlatformAccountRepository </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> JpaRepository</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">PlatformAccount</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> Int</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 查询用户的所有账号（带平台信息）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal multiline string\" style=\"color:hsl(119, 34%, 47%)\">\"\"\"</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token string-literal multiline string\" style=\"color:hsl(119, 34%, 47%)\">        SELECT a FROM PlatformAccount a </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token string-literal multiline string\" style=\"color:hsl(119, 34%, 47%)\">        JOIN FETCH a.platformInfo p </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token string-literal multiline string\" style=\"color:hsl(119, 34%, 47%)\">        WHERE a.ownerUserId = :userId </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token string-literal multiline string\" style=\"color:hsl(119, 34%, 47%)\">        ORDER BY p.id, a.id</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token string-literal multiline string\" style=\"color:hsl(119, 34%, 47%)\">    \"\"\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findAllWithPlatformByOwnerUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"userId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> List</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">PlatformAccount</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 检查同一用户在同一平台是否已存在相同账号名</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"SELECT COUNT(a) &gt; 0 FROM PlatformAccount a WHERE a.ownerUserId = :userId AND a.platformId = :platformId AND a.accountName = :accountName\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">existsByOwnerUserIdAndPlatformIdAndAccountName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"userId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"platformId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> platformId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"accountName\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> accountName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Boolean</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 删除指定用户的账号（同时检查所有权）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Modifying</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"DELETE FROM PlatformAccount a WHERE a.id = :accountId AND a.ownerUserId = :userId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">deleteByIdAndOwnerUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"accountId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> accountId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"userId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 批量删除指定用户的账号</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Modifying</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"DELETE FROM PlatformAccount a WHERE a.id IN :accountIds AND a.ownerUserId = :userId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">deleteAllByIdInAndOwnerUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"accountIds\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> accountIds</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> List</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Int</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"userId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 查询用户的所有账号ID（用于批量操作前验证）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"SELECT a.id FROM PlatformAccount a WHERE a.ownerUserId = :userId AND a.id IN :accountIds\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findExistingAccountIdsByOwnerUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"userId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"accountIds\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> accountIds</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> List</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Int</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> List</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Int</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">WebPageTrackHomeRepository.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">entity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">WebPageTrackHome</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jpa</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">JpaRepository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jpa</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Query</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Param</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">stereotype</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Repository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> java</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">time</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">LocalDateTime</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Repository</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">interface</span><span class=\"token plain\"> WebPageTrackHomeRepository </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> JpaRepository</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">WebPageTrackHome</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> Int</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 统计指定时间范围内的访问量</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"SELECT COUNT(t) FROM WebPageTrackHome t WHERE t.createdAt BETWEEN :startDate AND :endDate\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">countByCreatedAtBetween</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"startDate\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> startDate</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"endDate\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> endDate</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Long</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 按日期统计访问量（用于趋势图）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal multiline string\" style=\"color:hsl(119, 34%, 47%)\">\"\"\"</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token string-literal multiline string\" style=\"color:hsl(119, 34%, 47%)\">        SELECT DATE(t.createdAt) as date, COUNT(t) as count </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token string-literal multiline string\" style=\"color:hsl(119, 34%, 47%)\">        FROM WebPageTrackHome t </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token string-literal multiline string\" style=\"color:hsl(119, 34%, 47%)\">        WHERE t.createdAt BETWEEN :startDate AND :endDate </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token string-literal multiline string\" style=\"color:hsl(119, 34%, 47%)\">        GROUP BY DATE(t.createdAt) </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token string-literal multiline string\" style=\"color:hsl(119, 34%, 47%)\">        ORDER BY date</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token string-literal multiline string\" style=\"color:hsl(119, 34%, 47%)\">    \"\"\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">countGroupByDate</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"startDate\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> startDate</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"endDate\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> endDate</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> List</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Map</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> Any</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 统计最近N天的访问量</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"SELECT COUNT(t) FROM WebPageTrackHome t WHERE t.createdAt &gt;= :since\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">countSince</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"since\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> since</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 根据IP地址查询访问记录（用于防刷）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Query</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"SELECT COUNT(t) FROM WebPageTrackHome t WHERE t.ipAddress = :ip AND t.createdAt &gt;= :since\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">countByIpAddressSince</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"ip\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> ip</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Param</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"since\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> since</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div></div></div>\n<p>创建完成后，重启开发环境验证：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--profile</span><span class=\"token plain\"> dev restart dev</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>查看日志，没报错就行：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose logs </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-f</span><span class=\"token plain\"> dev</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"创建-dto-类\">创建 DTO 类<a href=\"https://devvv.cn/blog/service-from-cpp-to-springboot-nice#%E5%88%9B%E5%BB%BA-dto-%E7%B1%BB\" class=\"hash-link\" aria-label=\"创建 DTO 类的直接链接\" title=\"创建 DTO 类的直接链接\" translate=\"no\">​</a></h3>\n<p>在项目根目录下创建以下路径和文件：</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">src/main/kotlin/com/vv/friendlyserverv2/dto/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── ApiResponse.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── LoginResponse.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── RefreshTokenResponse.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── RegisterResponse.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── UserInfoResponse.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── UserUpdateRequest.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── AccountQueryResponse.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── AccountAddRequest.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── AccountDeleteRequest.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── PlatformQueryResponse.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── PlatformAddRequest.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── PlatformDeleteRequest.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── PlatformBatchDeleteRequest.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">└── HomeTrackRequest.kt</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">text</span></div></div></div>\n<div class=\"theme-tabs-container tabs-container tabList_D8NW\"><ul role=\"tablist\" aria-orientation=\"horizontal\" class=\"tabs\"><li role=\"tab\" tabindex=\"0\" aria-selected=\"true\" class=\"tabs__item tabItem_OkUL tabs__item--active\">ApiResponse.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">LoginResponse.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">RefreshTokenResponse.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">RegisterResponse.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">UserInfoResponse.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">UserUpdateRequest.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">AccountQueryResponse.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">AccountRequest.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">PlatformQueryResponse.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">PlatformRequest.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">TrackRequest.kt</li></ul><div class=\"margin-top--md\"><div role=\"tabpanel\" class=\"tabItem_fvDV\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">ApiResponse.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">fasterxml</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jackson</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">JsonInclude</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> java</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">time</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Instant</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 统一 API 响应格式</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 参考旧 C++ 项目 HttpResponse::ResponseModel</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@JsonInclude</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">JsonInclude</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Include</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">NON_NULL</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">T</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> code</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">           </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 业务状态码，0 表示成功</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">     </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 响应消息</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> T</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">            </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 响应数据（可选）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> timestamp</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Long </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> Instant</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">now</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">toEpochMilli</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 时间戳</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">companion</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">object</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 成功响应（带数据）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">T</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> T</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"请求成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">T</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 成功响应（无数据）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"请求成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 错误响应</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">error</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">code</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">code</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 400 错误</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">badRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"请求参数错误\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">400</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 401 未授权</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">unauthorized</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"未授权访问\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">401</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 403 禁止访问</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">forbidden</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"禁止访问\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">403</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 404 资源不存在</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">notFound</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"资源不存在\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">404</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 500 服务器内部错误</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">internalError</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"服务器内部错误\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">500</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">LoginResponse.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">fasterxml</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jackson</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">JsonFormat</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> java</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">time</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">LocalDateTime</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 登录响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 参考旧项目 LoginResponseModel</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">LoginResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> username</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> nickname</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> token</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> avatarUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> email</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> phone</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> bio</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@JsonFormat</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">pattern </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"yyyy-MM-dd HH:mm:ss\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> lastLoginAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@JsonFormat</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">pattern </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"yyyy-MM-dd HH:mm:ss\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> createdAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">RefreshTokenResponse.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 刷新 Token 响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 参考旧项目 RefreshTokenModel</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">RefreshTokenResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> token</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">RegisterResponse.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 注册响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 参考旧项目 RegisterResponseModel</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">RegisterResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> username</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> avatarUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> bio</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">UserInfoResponse.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">fasterxml</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jackson</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">JsonFormat</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> java</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">time</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">LocalDateTime</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 用户信息响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">UserInfoResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> username</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> nickname</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> avatarUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> email</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> phone</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> bio</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@JsonFormat</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">pattern </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"yyyy-MM-dd HH:mm:ss\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> lastLoginAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@JsonFormat</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">pattern </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"yyyy-MM-dd HH:mm:ss\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> createdAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">UserUpdateRequest.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 更新用户信息请求</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">UserUpdateRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> nickname</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> avatarUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> email</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> phone</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> bio</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">AccountQueryResponse.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">fasterxml</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jackson</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">JsonFormat</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> java</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">time</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">LocalDateTime</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 账号列表查询响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 参考旧项目 AccountQueryModel</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">AccountQueryResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> accountId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platformId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platformName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platformUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platformIconUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platformDescription</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@JsonFormat</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">pattern </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"yyyy-MM-dd HH:mm:ss\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platformCreatedAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@JsonFormat</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">pattern </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"yyyy-MM-dd HH:mm:ss\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platformUpdatedAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> accountName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> accountPassword</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> accountBoundEmail</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> accountBoundPhone</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> accountRemark</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@JsonFormat</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">pattern </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"yyyy-MM-dd HH:mm:ss\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> accountCreatedAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@JsonFormat</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">pattern </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"yyyy-MM-dd HH:mm:ss\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> accountUpdatedAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">AccountRequest.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 添加账号请求</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">AccountAddRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platformId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> accountName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> accountPassword</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> boundEmail</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> boundPhone</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> remark</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 删除账号请求</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">AccountDeleteRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> accountId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">PlatformQueryResponse.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">fasterxml</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jackson</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">JsonFormat</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> java</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">time</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">LocalDateTime</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 平台列表查询响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 参考旧项目 PlatformQueryModel</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">PlatformQueryResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> url</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> iconUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> description</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@JsonFormat</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">pattern </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"yyyy-MM-dd HH:mm:ss\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> createdAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@JsonFormat</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">pattern </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"yyyy-MM-dd HH:mm:ss\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> updatedAt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LocalDateTime</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">PlatformRequest.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 添加平台请求</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">PlatformAddRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platformName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platformUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platformIconUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platformDescription</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 删除平台请求</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">PlatformDeleteRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platformId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 批量删除平台请求</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">PlatformBatchDeleteRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platformIds</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> List</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Int</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">TrackRequest.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 首页埋点请求</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * 参考旧项目 WebTrackHomeHandler</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">HomeTrackRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> language</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> referrer</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> screenResolution</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> timestamp</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Long</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> url</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> userAgent</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"创建-service-层业务逻辑\">创建 Service 层（业务逻辑）<a href=\"https://devvv.cn/blog/service-from-cpp-to-springboot-nice#%E5%88%9B%E5%BB%BA-service-%E5%B1%82%E4%B8%9A%E5%8A%A1%E9%80%BB%E8%BE%91\" class=\"hash-link\" aria-label=\"创建 Service 层（业务逻辑）的直接链接\" title=\"创建 Service 层（业务逻辑）的直接链接\" translate=\"no\">​</a></h3>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">src/main/kotlin/com/vv/friendlyserverv2/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── config/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   └── SecurityConfig.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">└── service/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    ├── BaseService.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    ├── JwtService.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    ├── PlatformUserService.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    ├── PlatformInfoService.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    ├── PlatformAccountService.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    └── WebTrackService.kt</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">text</span></div></div></div>\n<p>添加 <code>Spring Security</code> 依赖，在 <code>build.gradle.kts</code> 的 <code>dependencies</code> 块中添加：</p>\n<div class=\"language-kts codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">build.gradle.kts<span style=\"flex:1;text-align:right\">kts</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kts codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">implementation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"org.springframework.boot:spring-boot-starter-security\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<div class=\"theme-admonition theme-admonition-note admonition_xGDO alert alert--secondary\"><div class=\"admonitionHeading_WNFr\"><span class=\"admonitionIcon_FtpR\"><svg viewBox=\"0 0 14 16\"><path fill-rule=\"evenodd\" d=\"M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z\"></path></svg></span>备注</div><div class=\"admonitionContent_hiHs\"><p>注意：添加 <code>Spring Security</code> 后，默认会启用安全过滤器链，所有接口都需要认证。我们需要禁用它（因为我们自己实现 JWT 认证）。</p></div></div>\n<p>在 SecurityConfig.kt 中添加配置：</p>\n<div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">SecurityConfig.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">config</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">context</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Bean</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">context</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Configuration</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">security</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">config</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">web</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">builders</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">HttpSecurity</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">security</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">config</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">web</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">configuration</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">EnableWebSecurity</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">security</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">config</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">http</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">SessionCreationPolicy</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">security</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">crypto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bcrypt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">BCryptPasswordEncoder</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">security</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">crypto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">password</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">PasswordEncoder</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">security</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">web</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">SecurityFilterChain</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Configuration</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@EnableWebSecurity</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> SecurityConfig </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Bean</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">passwordEncoder</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PasswordEncoder </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">BCryptPasswordEncoder</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Bean</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">securityFilterChain</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">http</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> HttpSecurity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> SecurityFilterChain </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        http</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">csrf</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> it</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">disable</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">authorizeHttpRequests</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> auth </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">-&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                auth</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">anyRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">permitAll</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 允许所有请求，由我们自己处理认证</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sessionManagement</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> session </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">-&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                session</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sessionCreationPolicy</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">SessionCreationPolicy</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">STATELESS</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> http</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">build</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<div class=\"theme-tabs-container tabs-container tabList_D8NW\"><ul role=\"tablist\" aria-orientation=\"horizontal\" class=\"tabs\"><li role=\"tab\" tabindex=\"0\" aria-selected=\"true\" class=\"tabs__item tabItem_OkUL tabs__item--active\">BaseService.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">JwtService.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">PlatformUserService.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">PlatformInfoService.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">PlatformAccountService.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">WebTrackService.kt</li></ul><div class=\"margin-top--md\"><div role=\"tabpanel\" class=\"tabItem_fvDV\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">BaseService.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">service</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">ApiResponse</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * Service 层基类，提供通用的验证、转换方法</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">abstract</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> BaseService </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ============ 参数验证方法 ============</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证字符串不为空</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">requireNotBlank</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">value</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> fieldName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">value</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">isNullOrBlank</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string-literal singleline interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">$</span><span class=\"token string-literal singleline interpolation expression\">fieldName</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\"> 不能为空\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证字符串长度范围</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">value</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> fieldName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> min</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> max</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">MAX_VALUE</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">value </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">!=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">value</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\"> min</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string-literal singleline interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">$</span><span class=\"token string-literal singleline interpolation expression\">fieldName</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\"> 长度不能小于 </span><span class=\"token string-literal singleline interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">$</span><span class=\"token string-literal singleline interpolation expression\">min</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">value</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> max</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string-literal singleline interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">$</span><span class=\"token string-literal singleline interpolation expression\">fieldName</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\"> 长度不能超过 </span><span class=\"token string-literal singleline interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">$</span><span class=\"token string-literal singleline interpolation expression\">max</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证字符串非空且长度范围</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateRequiredLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">value</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> fieldName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> min</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> max</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">MAX_VALUE</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">requireNotBlank</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">value</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> fieldName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">value</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> fieldName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> min</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> max</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证 ID 大于 0</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> fieldName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"ID\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">id </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string-literal singleline interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">$</span><span class=\"token string-literal singleline interpolation expression\">fieldName</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\"> 不正确\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证 ID 列表不为空且所有 ID 大于 0</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateIds</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">ids</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> List</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Int</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> fieldName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"ID列表\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">ids</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">isEmpty</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string-literal singleline interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">$</span><span class=\"token string-literal singleline interpolation expression\">fieldName</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\"> 不能为空\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        ids</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">forEach</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">it</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> fieldName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证邮箱格式</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateEmail</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">email</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        email</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">let</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">it</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">100</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"邮箱地址不能超过 100 个字符\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 简单邮箱格式验证</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> emailRegex </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Regex</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\\\.[A-Za-z]{2,}$\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">!</span><span class=\"token plain\">emailRegex</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">matches</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">it</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"邮箱格式不正确\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证手机号格式（11 位数字）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validatePhone</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">phone</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        phone</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">let</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">it</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">length </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">!=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">11</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">||</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">!</span><span class=\"token plain\">it</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">all</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> char </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">-&gt;</span><span class=\"token plain\"> char</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">isDigit</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"手机号只能为 11 个数字\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证用户名格式（6-20 位字母或数字）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateUsername</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">username</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateRequiredLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">username</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"用户名\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">6</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">20</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> usernameRegex </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Regex</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"^[A-Za-z0-9]+$\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">!</span><span class=\"token plain\">usernameRegex</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">matches</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">username</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"用户名只能包含英文和数字\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证密码格式（6-20 位字母或数字）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validatePassword</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">password</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateRequiredLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">password</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"密码\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">6</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">20</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> passwordRegex </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Regex</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"^[A-Za-z0-9]+$\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">!</span><span class=\"token plain\">passwordRegex</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">matches</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">password</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"密码只能包含英文和数字\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证昵称（最大 50 字符）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateNickname</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">nickname</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">nickname</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"昵称\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> max </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">50</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证平台名称</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validatePlatformName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateRequiredLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"平台名\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">50</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证 URL 长度</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">url</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> fieldName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"URL\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> max</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">url</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> fieldName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> max </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> max</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证描述长度</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateDescription</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">description</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> max</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">description</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"描述\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> max </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> max</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证账号名</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateAccountName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateRequiredLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"账号名\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">50</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证账号密码</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateAccountPassword</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">password</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateRequiredLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">password</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"账号密码\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">50</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证备注长度</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateRemark</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">remark</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> max</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">255</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">remark</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"备注\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> max </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> max</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证个人简介长度</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateBio</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">bio</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> max</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">500</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">bio</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"个人简介\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> max </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> max</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ============ 成功/错误响应构建方法 ============</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 构建成功响应（带数据）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">T</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> T</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"请求成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">T</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 构建成功响应（无数据）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"请求成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 构建错误响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">error</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">code</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">400</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">error</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">code</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 构建 400 错误响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">badRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"请求参数错误\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">badRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 构建 401 错误响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">unauthorized</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"未授权访问\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">unauthorized</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 构建 403 错误响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">forbidden</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"禁止访问\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">forbidden</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 构建 404 错误响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">notFound</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"资源不存在\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">notFound</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 构建 500 错误响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">internalError</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"服务器内部错误\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">internalError</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">JwtService.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">service</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> io</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jsonwebtoken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Claims</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> io</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jsonwebtoken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Jwts</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> io</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">jsonwebtoken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">security</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Keys</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">beans</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">factory</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Value</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">stereotype</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Service</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> java</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">util</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Date</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Service</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">JwtService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Value</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"\\${jwt.secret}\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> secret</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Value</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"\\${jwt.expiration}\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> expirationMs</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Long</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> key </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> Keys</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">hmacShaKeyFor</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">secret</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">toByteArray</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 生成 Token</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">generateToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> username</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> nickname</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> claims </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">mapOf</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"userId\"</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">to</span><span class=\"token plain\"> userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">toString</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"username\"</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">to</span><span class=\"token plain\"> username</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"nickname\"</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">to</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">nickname </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?:</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> Jwts</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">builder</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">claims</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">claims</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">issuedAt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Date</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">expiration</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Date</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">System</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">currentTimeMillis</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">+</span><span class=\"token plain\"> expirationMs</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">signWith</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">key</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">compact</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证 Token</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">verifyToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Boolean </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">try</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            Jwts</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">parser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">verifyWith</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">key</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">build</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">parseSignedClaims</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">catch</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">e</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Exception</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 提取所有 Claims</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">extractClaims</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Claims </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> Jwts</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">parser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">verifyWith</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">key</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">build</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">parseSignedClaims</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">payload</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 提取用户 ID</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">extractUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">extractClaims</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"userId\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">as</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">toIntOrNull</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 提取用户名</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">extractUsername</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">extractClaims</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"username\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">as</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> String</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 刷新 Token</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">refreshToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">verifyToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> claims </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">extractClaims</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            Jwts</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">builder</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">claims</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">claims</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">issuedAt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Date</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">expiration</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">Date</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">System</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">currentTimeMillis</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">+</span><span class=\"token plain\"> expirationMs</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">signWith</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">key</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">compact</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">else</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">PlatformUserService.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">service</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">LoginResponse</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">RegisterResponse</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">UserInfoResponse</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">UserUpdateRequest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">entity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">PlatformUser</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">PlatformUserRepository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">security</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">crypto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">password</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">PasswordEncoder</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">stereotype</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Service</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">transaction</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Transactional</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Service</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">PlatformUserService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> userRepository</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PlatformUserRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> passwordEncoder</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PasswordEncoder</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> jwtService</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> JwtService</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">BaseService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 用户登录</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Transactional</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">login</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">username</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> rawPassword</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LoginResponse </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateUsername</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">username</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validatePassword</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">rawPassword</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> user </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> userRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findByUsernameAndIsDeletedFalse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">username</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">orElseThrow</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"用户不存在: </span><span class=\"token string-literal singleline interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">$</span><span class=\"token string-literal singleline interpolation expression\">username</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">!</span><span class=\"token plain\">passwordEncoder</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">matches</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">rawPassword</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">passwordHash</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"密码错误\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        userRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">updateLastLoginTime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> token </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> jwtService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">generateToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">username</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">nickname</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">LoginResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            id </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            username </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">username</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            nickname </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">nickname</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            token </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> token</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            avatarUrl </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">avatarUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            email </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">email</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            phone </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">phone</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            bio </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bio</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            lastLoginAt </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">lastLoginAt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            createdAt </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">createdAt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 用户注册</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Transactional</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">register</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">username</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> rawPassword</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> avatarUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> bio</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> RegisterResponse </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateUsername</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">username</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validatePassword</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">rawPassword</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">avatarUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"头像URL\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateBio</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">bio</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">existsByUsernameAndIsDeletedFalse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">username</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"用户名已存在: </span><span class=\"token string-literal singleline interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">$</span><span class=\"token string-literal singleline interpolation expression\">username</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> user </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">PlatformUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            username </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> username</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            passwordHash </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> passwordEncoder</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">encode</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">rawPassword</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?:</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            nickname </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            avatarUrl </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> avatarUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            email </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            phone </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            bio </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> bio</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> savedUser </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> userRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">save</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">RegisterResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            username </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> savedUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">username</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            avatarUrl </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> savedUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">avatarUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            bio </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> savedUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bio</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 查询用户信息</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Transactional</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">readOnly </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getUserInfo</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> UserInfoResponse </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"用户ID\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> user </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> userRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findByIdAndIsDeletedFalse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">orElseThrow</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"用户不存在: </span><span class=\"token string-literal singleline interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">$</span><span class=\"token string-literal singleline interpolation expression\">userId</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">UserInfoResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            id </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            username </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">username</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            nickname </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">nickname</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            avatarUrl </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">avatarUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            email </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">email</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            phone </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">phone</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            bio </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bio</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            lastLoginAt </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">lastLoginAt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            createdAt </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">createdAt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 更新用户信息</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Transactional</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">updateUserInfo</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> request</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> UserUpdateRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> UserInfoResponse </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"用户ID\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateNickname</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">nickname</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">avatarUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"头像URL\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateEmail</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">email</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validatePhone</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">phone</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateBio</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bio</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> user </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> userRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findByIdAndIsDeletedFalse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">orElseThrow</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"用户不存在: </span><span class=\"token string-literal singleline interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">$</span><span class=\"token string-literal singleline interpolation expression\">userId</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">nickname</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">let</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">it</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">isNotEmpty</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">nickname </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> it </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">avatarUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">let</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">avatarUrl </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> it </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">email</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">let</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">email </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> it </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">phone</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">let</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">phone </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> it </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bio</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">let</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bio </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> it </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> updatedUser </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> userRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">save</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">user</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">UserInfoResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            id </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> updatedUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            username </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> updatedUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">username</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            nickname </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> updatedUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">nickname</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            avatarUrl </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> updatedUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">avatarUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            email </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> updatedUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">email</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            phone </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> updatedUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">phone</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            bio </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> updatedUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bio</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            lastLoginAt </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> updatedUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">lastLoginAt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            createdAt </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> updatedUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">createdAt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 刷新 Token</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">refreshToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> jwtService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">refreshToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 从 Token 中提取用户 ID</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getUserIdFromToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">jwtService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">verifyToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            jwtService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">extractUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">else</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">PlatformInfoService.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">service</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">PlatformAddRequest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">PlatformQueryResponse</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">entity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">PlatformInfo</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">PlatformInfoRepository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">stereotype</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Service</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">transaction</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Transactional</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Service</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">PlatformInfoService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platformInfoRepository</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PlatformInfoRepository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">BaseService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 查询用户的所有平台</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Transactional</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">readOnly </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">listPlatforms</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> List</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">PlatformQueryResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"用户ID\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platforms </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> platformInfoRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findAllByOwnerUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> platforms</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">map</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">toResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">it</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 添加平台</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Transactional</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">addPlatform</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> request</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PlatformAddRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"用户ID\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validatePlatformName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"平台地址\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformIconUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"平台图标地址\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateDescription</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformDescription</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">platformInfoRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">existsByOwnerUserIdAndName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"平台名称已存在: </span><span class=\"token string-literal singleline interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">${</span><span class=\"token string-literal singleline interpolation expression\">request</span><span class=\"token string-literal singleline interpolation expression punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token string-literal singleline interpolation expression\">platformName</span><span class=\"token string-literal singleline interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platform </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">PlatformInfo</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            url </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            iconUrl </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformIconUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            description </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformDescription</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            ownerUserId </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> userId</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        platformInfoRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">save</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">platform</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 删除平台</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Transactional</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">deletePlatform</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> platformId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"用户ID\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">platformId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"平台ID\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> deletedCount </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> platformInfoRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">deleteByIdAndOwnerUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">platformId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">deletedCount </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">==</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"平台不存在或无权限删除\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 批量删除平台</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Transactional</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">batchDeletePlatforms</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> platformIds</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> List</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Int</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"用户ID\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateIds</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">platformIds</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"平台ID列表\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> deletedCount </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> platformInfoRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">deleteAllByIdInAndOwnerUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">platformIds</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">deletedCount </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">!=</span><span class=\"token plain\"> platformIds</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">size</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"部分平台不存在或无权限删除\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 转换为响应 DTO</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">toResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">platform</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PlatformInfo</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PlatformQueryResponse </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">PlatformQueryResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            id </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> platform</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> platform</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            url </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> platform</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">url</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            iconUrl </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> platform</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">iconUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            description </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> platform</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">description</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            createdAt </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> platform</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">createdAt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            updatedAt </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> platform</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">updatedAt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">PlatformAccountService.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">service</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">AccountAddRequest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">AccountQueryResponse</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">entity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">PlatformAccount</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">PlatformAccountRepository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">stereotype</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Service</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">transaction</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Transactional</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Service</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">PlatformAccountService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> accountRepository</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PlatformAccountRepository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">BaseService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 查询用户的所有账号</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Transactional</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">readOnly </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">listAccounts</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> List</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">AccountQueryResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"用户ID\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> accounts </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> accountRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">findAllWithPlatformByOwnerUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> accounts</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">map</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">toResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">it</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 添加账号</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Transactional</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">addAccount</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> request</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> AccountAddRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"用户ID\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"所属平台ID\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateAccountName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">accountName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateAccountPassword</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">accountPassword</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateEmail</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">boundEmail</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validatePhone</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">boundPhone</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateRemark</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">remark</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">accountRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">existsByOwnerUserIdAndPlatformIdAndAccountName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">accountName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"该平台下已存在相同账号名\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> account </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">PlatformAccount</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            platformId </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            accountName </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">accountName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            passwordHash </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">accountPassword</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// TODO: 实际生产环境应对密码加密</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            boundEmail </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">boundEmail</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            boundPhone </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">boundPhone</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            ownerUserId </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            remark </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">remark</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        accountRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">save</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 删除账号</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Transactional</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">deleteAccount</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> accountId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"用户ID\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">accountId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"账号ID\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> deletedCount </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> accountRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">deleteByIdAndOwnerUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">accountId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">deletedCount </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">==</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"账号不存在或无权限删除\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 转换为响应 DTO</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">toResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">account</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PlatformAccount</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> AccountQueryResponse </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">AccountQueryResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            accountId </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">id</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            platformId </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            platformName </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformInfo</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">name </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?:</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            platformUrl </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformInfo</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">url</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            platformIconUrl </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformInfo</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">iconUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            platformDescription </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformInfo</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">description</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            platformCreatedAt </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformInfo</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">createdAt </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?:</span><span class=\"token plain\"> account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">createdAt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            platformUpdatedAt </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformInfo</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">updatedAt </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?:</span><span class=\"token plain\"> account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">updatedAt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            accountName </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">accountName</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            accountPassword </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">passwordHash</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            accountBoundEmail </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">boundEmail</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            accountBoundPhone </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">boundPhone</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            accountRemark </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">remark</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            accountCreatedAt </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">createdAt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            accountUpdatedAt </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> account</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">updatedAt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">WebTrackService.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">service</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">HomeTrackRequest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">entity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">WebPageTrackHome</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">repository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">WebPageTrackHomeRepository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">stereotype</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Service</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">transaction</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Transactional</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Service</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">WebTrackService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> trackRepository</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> WebPageTrackHomeRepository</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">BaseService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 首页埋点</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Transactional</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">trackHome</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> HomeTrackRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> clientIp</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">requireNotBlank</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">language</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"language\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">requireNotBlank</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">referrer</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"referrer\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">requireNotBlank</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">screenResolution</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"screenResolution\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">requireNotBlank</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">url</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"url\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">requireNotBlank</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">userAgent</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"userAgent\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">timestamp </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"timestamp 错误\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">language</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"language\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> max </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">20</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">referrer</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"referrer\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> max </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">500</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">screenResolution</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"screenResolution\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> max </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">20</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">url</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"url\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> max </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">500</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateLength</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">userAgent</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"userAgent\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> max </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">65535</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> track </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">WebPageTrackHome</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            visitTimestamp </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">timestamp</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            url </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">url</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            referrer </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">referrer</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            userAgent </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">userAgent</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            language </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">language</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            screenResolution </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">screenResolution</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            ipAddress </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> clientIp</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        trackRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">save</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">track</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 统计总访问量</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Transactional</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">readOnly </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getTotalVisitCount</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Long </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> trackRepository</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">count</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"创建-controller-层\">创建 Controller 层<a href=\"https://devvv.cn/blog/service-from-cpp-to-springboot-nice#%E5%88%9B%E5%BB%BA-controller-%E5%B1%82\" class=\"hash-link\" aria-label=\"创建 Controller 层的直接链接\" title=\"创建 Controller 层的直接链接\" translate=\"no\">​</a></h3>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">src/main/kotlin/com/vv/friendlyserverv2/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── controller/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── BaseController.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── AuthController.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── UserController.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── AccountController.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── PlatformController.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── TrackController.kt</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   └── HealthController.kt</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">text</span></div></div></div>\n<div class=\"theme-tabs-container tabs-container tabList_D8NW\"><ul role=\"tablist\" aria-orientation=\"horizontal\" class=\"tabs\"><li role=\"tab\" tabindex=\"0\" aria-selected=\"true\" class=\"tabs__item tabItem_OkUL tabs__item--active\">BaseController.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">AuthController.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">UserController.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">AccountController.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">PlatformController.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">TrackController.kt</li><li role=\"tab\" tabindex=\"-1\" aria-selected=\"false\" class=\"tabs__item tabItem_OkUL\">HealthController.kt</li></ul><div class=\"margin-top--md\"><div role=\"tabpanel\" class=\"tabItem_fvDV\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">BaseController.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">controller</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">ApiResponse</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">service</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">JwtService</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">beans</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">factory</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Autowired</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">http</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">HttpStatus</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">http</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">ResponseEntity</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">web</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bind</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">ExceptionHandler</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * Controller 层基类，提供通用的 Token 提取和响应构建方法</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">abstract</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> BaseController </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@Autowired</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">lateinit</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">var</span><span class=\"token plain\"> jwtService</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> JwtService</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ============ Token 提取方法 ============</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 从 Authorization Header 提取 Token</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">extractToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">authHeader</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">authHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">isNullOrBlank</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> authHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">removePrefix</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"Bearer \"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">trim</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证 Token 并提取用户 ID</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getUserIdFromToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">authHeader</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> token </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">extractToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">authHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?:</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">jwtService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">verifyToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            jwtService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">extractUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">else</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 验证 Token 并提取用户信息</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateTokenAndGetUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">authHeader</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> userId </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getUserIdFromToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">authHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?:</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"未授权访问\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> userId</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ============ 成功响应构建方法 ============</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 构建成功响应（带数据）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">T</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> T</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"请求成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">T</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ok</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 构建成功响应（无数据）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"请求成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ok</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 构建成功响应（自定义状态码）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">T</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> T</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> status</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> HttpStatus</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"请求成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">T</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">status</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">status</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">body</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ============ 错误响应构建方法 ============</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 构建错误响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">T</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">error</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">code</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Int</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">badRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">body</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">error</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">code</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 构建 400 错误响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">badRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"请求参数错误\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">badRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">body</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">badRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 构建 401 错误响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">unauthorized</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"未授权访问\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">status</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">HttpStatus</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">UNAUTHORIZED</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">body</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">unauthorized</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 构建 403 错误响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">forbidden</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"禁止访问\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">status</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">HttpStatus</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">FORBIDDEN</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">body</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">forbidden</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 构建 404 错误响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">notFound</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"资源不存在\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">status</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">HttpStatus</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">NOT_FOUND</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">body</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">notFound</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 构建 500 错误响应</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">internalError</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"服务器内部错误\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">status</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">HttpStatus</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">INTERNAL_SERVER_ERROR</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">body</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">ApiResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">internalError</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">message</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ============ 全局异常处理 ============</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 处理 IllegalArgumentException（业务异常）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@ExceptionHandler</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">IllegalArgumentException</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">::</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">handleIllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">e</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">badRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">e</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">message </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?:</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"请求参数错误\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 处理 Exception（系统异常）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@ExceptionHandler</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">Exception</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">::</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">protected</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">handleException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">e</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Exception</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        e</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">printStackTrace</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">internalError</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">e</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">message </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?:</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"服务器内部错误\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">AuthController.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">controller</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">ApiResponse</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">LoginResponse</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">RefreshTokenResponse</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">RegisterResponse</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">service</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">PlatformUserService</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">http</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">ResponseEntity</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">web</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bind</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">*</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RestController</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/api\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">AuthController</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> userService</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PlatformUserService</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">BaseController</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">LoginRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> username</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> password</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">RegisterRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> username</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> password</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> avatarUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> bio</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">null</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 用户登录</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * POST /api/login</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@PostMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/login\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">login</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestBody</span><span class=\"token plain\"> request</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> LoginRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">LoginResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> result </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> userService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">login</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">username</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">password</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">result</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"登录成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 用户注册</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * POST /api/register</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@PostMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/register\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">register</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestBody</span><span class=\"token plain\"> request</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> RegisterRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">RegisterResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> result </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> userService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">register</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">username</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">password</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">avatarUrl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bio</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">result</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"注册成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 刷新 Token</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * GET /api/refreshToken</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@GetMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/refreshToken\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">refreshToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"Authorization\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> authHeader</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">RefreshTokenResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> token </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">extractToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">authHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?:</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"Token 不能为空\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> newToken </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> userService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">refreshToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">token</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?:</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">throw</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">IllegalArgumentException</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"Token 刷新失败\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">RefreshTokenResponse</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">newToken</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"Token 刷新成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">UserController.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">controller</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">ApiResponse</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">UserInfoResponse</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">UserUpdateRequest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">service</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">PlatformUserService</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">http</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">ResponseEntity</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">web</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bind</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">*</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RestController</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/api/user\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">UserController</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> userService</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PlatformUserService</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">BaseController</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 查询用户信息</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * GET /api/user/query</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@GetMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/query\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">queryUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"Authorization\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> authHeader</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">UserInfoResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> userId </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateTokenAndGetUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">authHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> result </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> userService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">getUserInfo</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">result</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"查询成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 更新用户信息</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * POST /api/user/update</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@PostMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/update\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">updateUser</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"Authorization\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> authHeader</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestBody</span><span class=\"token plain\"> request</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> UserUpdateRequest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">UserInfoResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> userId </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateTokenAndGetUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">authHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> result </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> userService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">updateUserInfo</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">result</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"更新成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">AccountController.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">controller</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">AccountAddRequest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">AccountDeleteRequest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">AccountQueryResponse</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">ApiResponse</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">service</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">PlatformAccountService</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">http</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">ResponseEntity</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">web</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bind</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">*</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RestController</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/api/account\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">AccountController</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> accountService</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PlatformAccountService</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">BaseController</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 查询账号列表</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * GET /api/account/list</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@GetMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/list\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">listAccounts</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"Authorization\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> authHeader</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">List</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">AccountQueryResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> userId </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateTokenAndGetUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">authHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> result </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> accountService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">listAccounts</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">result</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"查询成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 添加账号</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * POST /api/account/add</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@PostMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/add\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">addAccount</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"Authorization\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> authHeader</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestBody</span><span class=\"token plain\"> request</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> AccountAddRequest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> userId </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateTokenAndGetUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">authHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        accountService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">addAccount</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"添加成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 删除账号</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * POST /api/account/delete</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@PostMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/delete\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">deleteAccount</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"Authorization\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> authHeader</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestBody</span><span class=\"token plain\"> request</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> AccountDeleteRequest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> userId </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateTokenAndGetUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">authHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        accountService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">deleteAccount</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">accountId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"删除成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">PlatformController.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">controller</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">*</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">service</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">PlatformInfoService</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">http</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">ResponseEntity</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">web</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bind</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">*</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RestController</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/api/platform\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">PlatformController</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> platformService</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PlatformInfoService</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">BaseController</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 查询平台列表</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * GET /api/platform/list</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@GetMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/list\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">listPlatforms</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"Authorization\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> authHeader</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">List</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">PlatformQueryResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> userId </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateTokenAndGetUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">authHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> result </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> platformService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">listPlatforms</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">result</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"查询成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 添加平台</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * POST /api/platform/add</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@PostMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/add\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">addPlatform</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"Authorization\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> authHeader</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestBody</span><span class=\"token plain\"> request</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PlatformAddRequest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> userId </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateTokenAndGetUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">authHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        platformService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">addPlatform</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"添加成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 删除平台</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * POST /api/platform/delete</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@PostMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/delete\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">deletePlatform</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"Authorization\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> authHeader</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestBody</span><span class=\"token plain\"> request</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PlatformDeleteRequest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> userId </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateTokenAndGetUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">authHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        platformService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">deletePlatform</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"删除成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 批量删除平台</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * POST /api/platform/batchDelete</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@PostMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/batchDelete\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">batchDeletePlatforms</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"Authorization\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> authHeader</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestBody</span><span class=\"token plain\"> request</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> PlatformBatchDeleteRequest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> userId </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">validateTokenAndGetUserId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">authHeader</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        platformService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">batchDeletePlatforms</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">userId</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">platformIds</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"批量删除成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">TrackController.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">controller</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">ApiResponse</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">HomeTrackRequest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">service</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">WebTrackService</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">http</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">ResponseEntity</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">web</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bind</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">*</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> jakarta</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">servlet</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">http</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">HttpServletRequest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RestController</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/api/track\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">TrackController</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">private</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> trackService</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> WebTrackService</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">BaseController</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 首页埋点</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * POST /api/track/web/home</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@PostMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/web/home\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">trackHome</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestBody</span><span class=\"token plain\"> request</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> HomeTrackRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        httpRequest</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> HttpServletRequest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Unit</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> clientIp </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> httpRequest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">remoteAddr</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        trackService</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">trackHome</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">request</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> clientIp</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"埋点成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div><div role=\"tabpanel\" class=\"tabItem_fvDV\" hidden=\"\"><div class=\"language-kotlin codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">HealthController.kt<span style=\"flex:1;text-align:right\">kotlin</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-kotlin codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">package</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">controller</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> com</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">ApiResponse</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">http</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">ResponseEntity</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">web</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bind</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">GetMapping</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">web</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bind</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">RequestMapping</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> org</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">springframework</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">web</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">bind</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">annotation</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">RestController</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RestController</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@RequestMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/api\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">class</span><span class=\"token plain\"> HealthController </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">BaseController</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 健康检查</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * GET /api/health</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@GetMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/health\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">health</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Map</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">mapOf</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"status\"</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">to</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"UP\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"timestamp\"</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">to</span><span class=\"token plain\"> System</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">currentTimeMillis</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">toString</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"服务正常\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * 测试接口</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     * GET /api/test</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">     */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token annotation builtin\" style=\"color:hsl(119, 34%, 47%)\">@GetMapping</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"/test\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fun</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">test</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ResponseEntity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">ApiResponse</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">Map</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">String</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> String</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">val</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">mapOf</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"message\"</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">to</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"Hello from FriendlyServerV2\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">success</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string-literal singleline string\" style=\"color:hsl(119, 34%, 47%)\">\"测试成功\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"配置-applicationyml\">配置 application.yml<a href=\"https://devvv.cn/blog/service-from-cpp-to-springboot-nice#%E9%85%8D%E7%BD%AE-applicationyml\" class=\"hash-link\" aria-label=\"配置 application.yml的直接链接\" title=\"配置 application.yml的直接链接\" translate=\"no\">​</a></h3>\n<p>创建 <code>src/main/resources/application.yml</code> 文件，内容如下：</p>\n<div class=\"language-yaml codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">application.yml<span style=\"flex:1;text-align:right\">yaml</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-yaml codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># Spring Boot 基础配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">spring</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">application</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> FriendlyServerV2</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 数据源配置（MySQL）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">datasource</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">url</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> $</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">SPRING_DATASOURCE_URL</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">jdbc</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">mysql</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">//mysql</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">3306/db_friendly</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">?</span><span class=\"token plain\">useSSL=false</span><span class=\"token important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">&amp;serverTimezone=UTC&amp;characterEncoding=utf8&amp;allowPublicKeyRetrieval=true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">username</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> $</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">SPRING_DATASOURCE_USERNAME</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">vv</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">password</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> $</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">SPRING_DATASOURCE_PASSWORD</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">vvpwd123</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">driver-class-name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> com.mysql.cj.jdbc.Driver</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">hikari</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">minimum-idle</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">5</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">maximum-pool-size</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">20</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">idle-timeout</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">30000</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">connection-timeout</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">30000</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">max-lifetime</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1800000</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># JPA 配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">jpa</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">hibernate</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">ddl-auto</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> validate  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 验证表结构，不自动创建（使用 init.sql 建表）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">show-sql</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">false</span><span class=\"token plain\">       </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 开发环境可设为 true 查看 SQL</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">properties</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">hibernate</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">#        dialect: org.hibernate.dialect.MySQL8Dialect</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">format_sql</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">true</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">jdbc</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">batch_size</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">20</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">order_inserts</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">true</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">order_updates</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">true</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># Redis 配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">data</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">redis</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">host</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> $</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">SPRING_DATA_REDIS_HOST</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">redis</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">port</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> $</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">SPRING_DATA_REDIS_PORT</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">6379</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">password</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> $</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">SPRING_DATA_REDIS_PASSWORD</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">timeout</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> 5000ms</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">lettuce</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">pool</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">max-active</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">8</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">max-idle</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">8</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">min-idle</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">max-wait</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">1ms</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># Jackson 配置（JSON 序列化）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">jackson</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">date-format</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> yyyy</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">MM</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">dd HH</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">mm</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">ss</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">time-zone</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> Asia/Shanghai</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">deserialization</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">fail-on-unknown-properties</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">false</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 服务器配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">server</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">port</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> $</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">SERVER_PORT</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">8080</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">servlet</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">context-path</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> /</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">encoding</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">charset</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> UTF</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">8</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">enabled</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">true</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">force</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">true</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">compression</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">enabled</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">true</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">mime-types</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> application/json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">application/xml</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">text/html</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">text/plain</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># JWT 配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">jwt</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">secret</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> $</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">JWT_SECRET</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">lIXQJyQznJ+rQ0eafwSAD5tXqaKKJWh5VfZErNDUcSs</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">expiration</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> $</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">JWT_EXPIRATION</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">604800000</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 7天 = 7 * 24 * 3600 * 1000 = 604800000 毫秒</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 日志配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">logging</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">level</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">root</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> INFO</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">com.vv.friendlyserverv2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> DEBUG</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">org.springframework.web</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> INFO</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">org.hibernate.SQL</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> WARN</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">org.hibernate.type.descriptor.sql.BasicBinder</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> TRACE</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">pattern</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">console</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%n\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">file</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%thread] %logger{36} - %msg%n\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">file</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> logs/friendlyserver.log</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">max-size</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> 10MB</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">max-history</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">7</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 管理端点配置（可选，用于监控）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">management</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">endpoints</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">web</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">exposure</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">include</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> health</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">info</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">metrics</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">base-path</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> /actuator</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">endpoint</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">health</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">show-details</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> always</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 应用自定义配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">app</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 跨域配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">cors</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">allowed-origins</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> $</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">CORS_ALLOWED_ORIGINS</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">http</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">//localhost</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3000</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">http</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">//localhost</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">8080</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">allowed-methods</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> GET</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">POST</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">PUT</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">DELETE</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">OPTIONS</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">allowed-headers</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"*\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">allow-credentials</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">true</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">max-age</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3600</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<p>配置文件说明：</p>\n<ol>\n<li class=\"\">环境变量覆盖\n配置中使用 <code>${VAR:default}</code> 格式，可以通过环境变量覆盖默认值：</li>\n</ol>\n<table><thead><tr><th>环境变量</th><th>说明</th><th>默认值</th></tr></thead><tbody><tr><td><code>SPRING_DATASOURCE_URL</code></td><td>MySQL 连接地址</td><td><code>jdbc:mysql://mysql:3306/db_friendly?...</code></td></tr><tr><td><code>SPRING_DATASOURCE_USERNAME</code></td><td>MySQL 用户名</td><td><code>vv</code></td></tr><tr><td><code>SPRING_DATASOURCE_PASSWORD</code></td><td>MySQL 密码</td><td><code>vvpwd123</code></td></tr><tr><td><code>SPRING_DATA_REDIS_HOST</code></td><td>Redis 主机</td><td><code>redis</code></td></tr><tr><td><code>SPRING_DATA_REDIS_PORT</code></td><td>Redis 端口</td><td><code>6379</code></td></tr><tr><td><code>SERVER_PORT</code></td><td>服务端口</td><td><code>8080</code></td></tr><tr><td><code>JWT_SECRET</code></td><td>JWT 密钥</td><td>默认开发密钥（生产必须修改）</td></tr><tr><td><code>JWT_EXPIRATION</code></td><td>JWT 过期时间（毫秒）</td><td><code>3600000</code>（1小时）</td></tr></tbody></table>\n<ol start=\"2\">\n<li class=\"\">JPA 配置说明</li>\n</ol>\n<ul>\n<li class=\"\"><code>ddl-auto: validate</code> - 只验证表结构，不会自动创建或修改表。表已通过 <code>init.sql</code> 创建，使用 <code>validate</code> 可以确保实体类与数据库表结构一致。</li>\n<li class=\"\">开发时如需查看 SQL，可将 <code>show-sql</code> 设为 <code>true</code>。</li>\n</ul>\n<ol start=\"3\">\n<li class=\"\">日志配置</li>\n</ol>\n<ul>\n<li class=\"\">控制台日志：彩色输出，包含时间、级别、线程、类名、消息</li>\n<li class=\"\">文件日志：写入 <code>logs/friendlyserver.log</code>，单文件最大 10MB，保留 7 天</li>\n</ul>\n<hr>\n<p>验证配置文件</p>\n<p>创建完成后，停止容器服务并重新启动验证：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> stop dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--profile</span><span class=\"token plain\"> dev up </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-d</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 日志查看</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose logs </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-f</span><span class=\"token plain\"> dev</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>访问：</p>\n<p><a href=\"http://localhost:8080/api/test\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">http://localhost:8080/api/test</a></p>\n<p><a href=\"http://localhost:8080/api/health\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">http://localhost:8080/api/health</a></p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"FriendlyServerV2迁移测试成功\" src=\"data:image/png;base64,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\" width=\"555\" height=\"261\" class=\"img_m9Pm\"></p>\n<p>到这里全部迁移完成。</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"mysql-容器数据导入导出\">MySQL 容器数据导入导出<a href=\"https://devvv.cn/blog/service-from-cpp-to-springboot-nice#mysql-%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%AF%BC%E5%85%A5%E5%AF%BC%E5%87%BA\" class=\"hash-link\" aria-label=\"MySQL 容器数据导入导出的直接链接\" title=\"MySQL 容器数据导入导出的直接链接\" translate=\"no\">​</a></h3>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"导入数据\">导入数据<a href=\"https://devvv.cn/blog/service-from-cpp-to-springboot-nice#%E5%AF%BC%E5%85%A5%E6%95%B0%E6%8D%AE\" class=\"hash-link\" aria-label=\"导入数据的直接链接\" title=\"导入数据的直接链接\" translate=\"no\">​</a></h4>\n<p>sql 数据位置：<code>/home/vv/桌面/vv/idea/work/FriendlyServerV2/src/test/resources/db/insert.sql</code></p>\n<p><strong>方法一：通过文件导入</strong></p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 将 insert.sql 文件复制到容器内</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">cp</span><span class=\"token plain\"> /home/vv/桌面/vv/idea/work/FriendlyServerV2/src/test/resources/db/insert.sql friendly-mysql:/tmp/insert.sql</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 进入容器并执行</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exec</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-it</span><span class=\"token plain\"> friendly-mysql </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">bash</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">mysql </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-uroot</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-proot</span><span class=\"token plain\"> db_friendly </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\"> /tmp/insert.sql</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p><strong>方法二：直接执行（如果 insert.sql 在宿主机）</strong></p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exec</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-i</span><span class=\"token plain\"> friendly-mysql mysql </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-uroot</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-proot</span><span class=\"token plain\"> db_friendly </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\"> /path/insert.sql</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"导出数据\">导出数据<a href=\"https://devvv.cn/blog/service-from-cpp-to-springboot-nice#%E5%AF%BC%E5%87%BA%E6%95%B0%E6%8D%AE\" class=\"hash-link\" aria-label=\"导出数据的直接链接\" title=\"导出数据的直接链接\" translate=\"no\">​</a></h4>\n<p><strong>方法一：导出整个数据库</strong></p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exec</span><span class=\"token plain\"> friendly-mysql mysqldump </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-uroot</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-proot</span><span class=\"token plain\"> db_friendly </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> backup.sql</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p><strong>方法二：导出指定表</strong></p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exec</span><span class=\"token plain\"> friendly-mysql mysqldump </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-uroot</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-proot</span><span class=\"token plain\"> db_friendly platform_user </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> user_backup.sql</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p><strong>方法三：导出数据（不包含建表语句）</strong></p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exec</span><span class=\"token plain\"> friendly-mysql mysqldump </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-uroot</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-proot</span><span class=\"token plain\"> --no-create-info db_friendly </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> data_only.sql</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"直接在容器内操作\">直接在容器内操作<a href=\"https://devvv.cn/blog/service-from-cpp-to-springboot-nice#%E7%9B%B4%E6%8E%A5%E5%9C%A8%E5%AE%B9%E5%99%A8%E5%86%85%E6%93%8D%E4%BD%9C\" class=\"hash-link\" aria-label=\"直接在容器内操作的直接链接\" title=\"直接在容器内操作的直接链接\" translate=\"no\">​</a></h4>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 进入 MySQL 命令行</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exec</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-it</span><span class=\"token plain\"> friendly-mysql mysql </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-uroot</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-proot</span><span class=\"token plain\"> db_friendly</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 在 MySQL 中执行批量插入</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">mysql</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> INSERT INTO platform_user </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\">username, password_hash</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> VALUES </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'test'</span><span class=\"token plain\">, </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'hash'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">mysql</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">source</span><span class=\"token plain\"> /tmp/insert.sql</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 执行文件</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"常用导出选项\">常用导出选项<a href=\"https://devvv.cn/blog/service-from-cpp-to-springboot-nice#%E5%B8%B8%E7%94%A8%E5%AF%BC%E5%87%BA%E9%80%89%E9%A1%B9\" class=\"hash-link\" aria-label=\"常用导出选项的直接链接\" title=\"常用导出选项的直接链接\" translate=\"no\">​</a></h4>\n<table><thead><tr><th>参数</th><th>说明</th></tr></thead><tbody><tr><td><code>--no-create-info</code></td><td>不导出建表语句</td></tr><tr><td><code>--no-data</code></td><td>只导出表结构</td></tr><tr><td><code>--where=\"id&lt;100\"</code></td><td>条件导出</td></tr><tr><td><code>--single-transaction</code></td><td>保证一致性（InnoDB）</td></tr></tbody></table>\n<hr>\n<p>导出后，<code>backup.sql</code> 文件会保存在当前执行命令的目录下。</p>",
            "url": "https://devvv.cn/blog/service-from-cpp-to-springboot-nice",
            "title": "后端服务从 C++ 迁移到 SpringBoot",
            "summary": "后端服务从 C++ 迁移到 SpringBoot",
            "date_modified": "2026-03-24T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "SpringBoot",
                "Netty",
                "Kotlin",
                "MySQL",
                "Redis"
            ]
        },
        {
            "id": "https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles",
            "content_html": "<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"为什么会有这两个概念\">为什么会有这两个概念？<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BC%9A%E6%9C%89%E8%BF%99%E4%B8%A4%E4%B8%AA%E6%A6%82%E5%BF%B5\" class=\"hash-link\" aria-label=\"为什么会有这两个概念？的直接链接\" title=\"为什么会有这两个概念？的直接链接\" translate=\"no\">​</a></h2>\n<p>互联网的核心是<strong>设备之间相互发送数据包</strong>，每个设备需要唯一的 IP 地址。由于 IPv4 地址短缺，<strong>NAT（网络地址转换）</strong> 技术被广泛应用：你家路由器有一个公网 IP，而家里所有设备使用私有 IP（如 192.168.1.x）。<br>\n<!-- -->NAT 带来的限制是：<strong>内网设备可以主动访问外网，但外网很难主动访问内网设备</strong>。<br>\n<!-- -->为了解决这个问题，出现了两种技术：<strong>VPN</strong> 和<strong>内网穿透</strong>。它们的目标和实现方式完全不同。</p>\n<hr>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"1-先从互联网的本质说起\">1. 先从互联网的本质说起<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#1-%E5%85%88%E4%BB%8E%E4%BA%92%E8%81%94%E7%BD%91%E7%9A%84%E6%9C%AC%E8%B4%A8%E8%AF%B4%E8%B5%B7\" class=\"hash-link\" aria-label=\"1. 先从互联网的本质说起的直接链接\" title=\"1. 先从互联网的本质说起的直接链接\" translate=\"no\">​</a></h2>\n<p>互联网的本质是<strong>无数台设备（电脑、手机、服务器）之间相互发送数据包</strong>。<br>\n<!-- -->要让数据包正确送达，每台设备都需要一个唯一的地址，也就是 <strong>IP 地址</strong>。<br>\n<!-- -->在 IPv4 时代，地址不够用，所以有了 <strong>NAT（网络地址转换）</strong> 技术。<br>\n<!-- -->简单说，你家路由器有一个公网 IP（全球唯一），而你家所有设备（电脑、手机、电视）用的是私有 IP（如 192.168.1.x）。<br>\n<!-- -->当你家的电脑访问外网时，路由器会把数据包的源 IP 换成自己的公网 IP，并记住这个映射关系；收到回复时，再转换回私有 IP 发给你的电脑。</p>\n<p><strong>关键点</strong>：</p>\n<ul>\n<li class=\"\">你家电脑对外“说话”时，用的是路由器的公网 IP。</li>\n<li class=\"\">但是外网主动发数据包给你家电脑时，路由器不知道这个数据包应该发给内网的哪台设备，除非你提前在路由器上设置了 <strong>端口映射</strong>，告诉它“某个端口的流量转发给某台内网设备”。</li>\n</ul>\n<p>这个限制就是 NAT 的“墙”：<strong>内网设备可以主动访问外网，但外网很难主动访问内网设备</strong>。</p>\n<hr>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"2-vpn-的本质和工作原理\">2. VPN 的本质和工作原理<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#2-vpn-%E7%9A%84%E6%9C%AC%E8%B4%A8%E5%92%8C%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86\" class=\"hash-link\" aria-label=\"2. VPN 的本质和工作原理的直接链接\" title=\"2. VPN 的本质和工作原理的直接链接\" translate=\"no\">​</a></h2>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"21-本质\">2.1 本质<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#21-%E6%9C%AC%E8%B4%A8\" class=\"hash-link\" aria-label=\"2.1 本质的直接链接\" title=\"2.1 本质的直接链接\" translate=\"no\">​</a></h3>\n<p>VPN（虚拟专用网络）是在公共网络上<strong>模拟出一个私有的、加密的、逻辑上的“局域网”</strong>。</p>\n<p>它不是在物理上改变网络，而是通过软件，让你的设备与另一个网络之间建立一条<strong>加密隧道</strong>。</p>\n<p>目标：让远程设备<strong>融入</strong>目标内网，获得一个内网 IP，从而像本地设备一样访问内网中的所有资源（不仅限于某个应用）。</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"22-原理以最常见的远程访问-vpn-为例\">2.2 原理（以最常见的远程访问 VPN 为例）<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#22-%E5%8E%9F%E7%90%86%E4%BB%A5%E6%9C%80%E5%B8%B8%E8%A7%81%E7%9A%84%E8%BF%9C%E7%A8%8B%E8%AE%BF%E9%97%AE-vpn-%E4%B8%BA%E4%BE%8B\" class=\"hash-link\" aria-label=\"2.2 原理（以最常见的远程访问 VPN 为例）的直接链接\" title=\"2.2 原理（以最常见的远程访问 VPN 为例）的直接链接\" translate=\"no\">​</a></h3>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"221-场景设定\">2.2.1 场景设定<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#221-%E5%9C%BA%E6%99%AF%E8%AE%BE%E5%AE%9A\" class=\"hash-link\" aria-label=\"2.2.1 场景设定的直接链接\" title=\"2.2.1 场景设定的直接链接\" translate=\"no\">​</a></h4>\n<ul>\n<li class=\"\"><strong>公司内网网段</strong>：<code>192.168.10.0/24</code>（即 IP 范围 192.168.10.1～192.168.10.254）</li>\n<li class=\"\"><strong>公司内网的一台文件服务器</strong>：<code>192.168.10.5</code></li>\n<li class=\"\"><strong>公司的 VPN 服务器</strong>：<!-- -->\n<ul>\n<li class=\"\">在公司内网的 IP：<code>192.168.10.1</code>（通常也是网关）</li>\n<li class=\"\">拥有<strong>公网 IP</strong>：<code>203.0.113.5</code>（这样才能被互联网上的设备访问，用于对外接受连接）</li>\n</ul>\n</li>\n<li class=\"\"><strong>你家网络</strong>：<!-- -->\n<ul>\n<li class=\"\">路由器公网 IP：<code>198.51.100.10</code>（这是运营商分配给你的，但可能动态变化）</li>\n<li class=\"\">你家电脑物理网卡（以太网或 Wi-Fi）的私有 IP：<code>192.168.1.100</code>（由你家路由器分配，网段是 192.168.1.0/24，私有 IP）</li>\n</ul>\n</li>\n<li class=\"\"><strong>你家电脑操作系统</strong>：Windows/Linux/macOS，安装了 VPN 客户端软件（比如 OpenVPN、WireGuard 或公司专有客户端）</li>\n</ul>\n<p>现在，你想在家访问公司内网的文件服务器 <code>192.168.10.5</code>。</p>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"222-第一步建立-vpn-控制连接物理网卡\">2.2.2 第一步：建立 VPN 控制连接（物理网卡）<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#222-%E7%AC%AC%E4%B8%80%E6%AD%A5%E5%BB%BA%E7%AB%8B-vpn-%E6%8E%A7%E5%88%B6%E8%BF%9E%E6%8E%A5%E7%89%A9%E7%90%86%E7%BD%91%E5%8D%A1\" class=\"hash-link\" aria-label=\"2.2.2 第一步：建立 VPN 控制连接（物理网卡）的直接链接\" title=\"2.2.2 第一步：建立 VPN 控制连接（物理网卡）的直接链接\" translate=\"no\">​</a></h4>\n<p>你在家电脑上启动 VPN 客户端，输入公司 VPN 服务器的地址（公网 IP <code>203.0.113.5</code>）和认证信息（用户名/密码或证书）。</p>\n<p>你家电脑客户端会通过<strong>物理网卡</strong>（IP <code>192.168.1.100</code>）向 <code>203.0.113.5</code> 发起一个<strong>普通的网络连接</strong>。这个连接使用的是什么协议？通常是 TCP 或 UDP，比如 OpenVPN 默认用 UDP 1194 端口，或者 IKEv2 用 UDP 500 端口。</p>\n<p><strong>数据包的样子（从你家电脑物理网卡发出）</strong>：</p>\n<ul>\n<li class=\"\">源 IP：<code>192.168.1.100</code>（你家电脑物理网卡 IP）</li>\n<li class=\"\">目标 IP：<code>203.0.113.5</code>（VPN 服务器公网 IP）</li>\n<li class=\"\">源端口：随机高端口（如 54321）</li>\n<li class=\"\">目标端口：VPN 服务器监听端口（如 1194）</li>\n<li class=\"\">数据部分：包含 VPN 协议的控制信息（如认证、加密协商）</li>\n</ul>\n<p>这个包先到你家路由器（<code>192.168.1.1</code>），路由器做 NAT，把源 IP 换成自己的公网 IP <code>198.51.100.10</code>，并记住映射。然后包通过互联网到达 VPN 服务器 <code>203.0.113.5</code>。</p>\n<p>VPN 服务器收到后，验证身份，双方完成握手，建立了一个<strong>加密的隧道</strong>。此时，在操作系统层面，你家电脑和 VPN 服务器之间已经有一条逻辑上的连接了（基于 UDP 或 TCP）。但此时还不能访问公司内网，因为还没有虚拟网卡。</p>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"223-第二步创建虚拟网卡并分配-ip\">2.2.3 第二步：创建虚拟网卡并分配 IP<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#223-%E7%AC%AC%E4%BA%8C%E6%AD%A5%E5%88%9B%E5%BB%BA%E8%99%9A%E6%8B%9F%E7%BD%91%E5%8D%A1%E5%B9%B6%E5%88%86%E9%85%8D-ip\" class=\"hash-link\" aria-label=\"2.2.3 第二步：创建虚拟网卡并分配 IP的直接链接\" title=\"2.2.3 第二步：创建虚拟网卡并分配 IP的直接链接\" translate=\"no\">​</a></h4>\n<p>VPN 客户端软件会在你的电脑上创建一个<strong>虚拟网络接口</strong>（也叫虚拟网卡）。这个虚拟网卡在操作系统中看起来就像一个普通的网卡，但它没有物理实体，所有发给它的数据包都会被 VPN 客户端软件拦截并处理。</p>\n<p>创建好虚拟网卡后，VPN 服务器会通过刚才建立的隧道，给这个虚拟网卡分配一个<strong>公司内网的 IP 地址</strong>。比如服务器告诉客户端：“你的虚拟网卡 IP 是 <code>192.168.10.100</code>，子网掩码是 <code>255.255.255.0</code>。”</p>\n<p>客户端收到后，就在操作系统中配置这个虚拟网卡：</p>\n<ul>\n<li class=\"\">虚拟网卡 IP：<code>192.168.10.100</code></li>\n<li class=\"\">子网掩码：<code>255.255.255.0</code></li>\n</ul>\n<p>此时，你家电脑就有了两个 IP 地址：</p>\n<ul>\n<li class=\"\">物理网卡：<code>192.168.1.100</code>（你家局域网身份）</li>\n<li class=\"\">虚拟网卡：<code>192.168.10.100</code>（公司内网身份）</li>\n</ul>\n<p><strong>关键点</strong>：这个 <code>192.168.10.100</code> 是 VPN 服务器从公司内网地址池中分配的，它在公司内网是唯一的。其他公司内网的设备（如服务器 <code>192.168.10.5</code>）看到这个 IP，就会认为它是公司内网的一台设备。</p>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"224-第三步修改路由表\">2.2.4 第三步：修改路由表<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#224-%E7%AC%AC%E4%B8%89%E6%AD%A5%E4%BF%AE%E6%94%B9%E8%B7%AF%E7%94%B1%E8%A1%A8\" class=\"hash-link\" aria-label=\"2.2.4 第三步：修改路由表的直接链接\" title=\"2.2.4 第三步：修改路由表的直接链接\" translate=\"no\">​</a></h4>\n<p>操作系统依靠<strong>路由表</strong>来决定一个数据包应该从哪个网卡发送出去。VPN 客户端会自动添加一条或几条路由规则，让访问公司内网的流量走虚拟网卡。</p>\n<p>例如，添加一条路由：</p>\n<ul>\n<li class=\"\">目标网络：<code>192.168.10.0/24</code>（公司内网）</li>\n<li class=\"\">网关：<code>0.0.0.0</code>（或者虚拟网卡本身，表示直连网络）</li>\n<li class=\"\">接口：虚拟网卡</li>\n</ul>\n<p>这样一来，当你在家电脑上访问 <code>192.168.10.5</code> 时，操作系统检查路由表，发现目标 IP <code>192.168.10.5</code> 匹配 <code>192.168.10.0/24</code>，于是决定将数据包交给虚拟网卡处理。</p>\n<p>对于其他流量（比如访问百度 <code>1.2.3.4</code>），默认路由仍然指向物理网卡（默认路由），走你家宽带。</p>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"225-第四步访问公司内网服务器的完整数据包旅程\">2.2.5 第四步：访问公司内网服务器的完整数据包旅程<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#225-%E7%AC%AC%E5%9B%9B%E6%AD%A5%E8%AE%BF%E9%97%AE%E5%85%AC%E5%8F%B8%E5%86%85%E7%BD%91%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%E5%AE%8C%E6%95%B4%E6%95%B0%E6%8D%AE%E5%8C%85%E6%97%85%E7%A8%8B\" class=\"hash-link\" aria-label=\"2.2.5 第四步：访问公司内网服务器的完整数据包旅程的直接链接\" title=\"2.2.5 第四步：访问公司内网服务器的完整数据包旅程的直接链接\" translate=\"no\">​</a></h4>\n<p>现在，你在家电脑上打开浏览器，输入 <code>\\\\192.168.10.5\\share</code>（Windows 共享）或者直接 ping <code>192.168.10.5</code>，我们以 ping 为例（ICMP 协议），看看数据包怎么走。</p>\n<h5 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"2251-从应用程序到-ip-层\">2.2.5.1 从应用程序到 IP 层<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#2251-%E4%BB%8E%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E5%88%B0-ip-%E5%B1%82\" class=\"hash-link\" aria-label=\"2.2.5.1 从应用程序到 IP 层的直接链接\" title=\"2.2.5.1 从应用程序到 IP 层的直接链接\" translate=\"no\">​</a></h5>\n<p>你在命令行输入 <code>ping 192.168.10.5</code>。操作系统生成一个 ICMP 请求数据包，这个包的 IP 头部是：</p>\n<ul>\n<li class=\"\">源 IP：操作系统会选择源 IP。因为目标 <code>192.168.10.5</code> 属于公司内网，且虚拟网卡 IP <code>192.168.10.100</code> 也在同一网段，所以操作系统会自动用虚拟网卡的 IP 作为源 IP（除非有特殊绑定）。因此源 IP 为虚拟网卡 <code>192.168.10.100</code>（自动选择）。</li>\n<li class=\"\">目标 IP：<code>192.168.10.5</code></li>\n</ul>\n<p>此时，这个 IP 包（我们叫它<strong>原始包</strong>）刚刚在 IP 层生成，还没有交给任何网卡。操作系统查询路由表，发现目标 <code>192.168.10.5</code> 匹配 <code>192.168.10.0/24</code>，决定通过虚拟网卡发送。</p>\n<p>于是，原始包被交给虚拟网卡的驱动程序。</p>\n<h5 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"2252-虚拟网卡的处理加密与封装\">2.2.5.2 虚拟网卡的处理（加密与封装）<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#2252-%E8%99%9A%E6%8B%9F%E7%BD%91%E5%8D%A1%E7%9A%84%E5%A4%84%E7%90%86%E5%8A%A0%E5%AF%86%E4%B8%8E%E5%B0%81%E8%A3%85\" class=\"hash-link\" aria-label=\"2.2.5.2 虚拟网卡的处理（加密与封装）的直接链接\" title=\"2.2.5.2 虚拟网卡的处理（加密与封装）的直接链接\" translate=\"no\">​</a></h5>\n<p>虚拟网卡驱动程序收到这个原始包后，并不像物理网卡那样直接发送到网线上。相反，它把原始包（整个 IP 包，包括 IP 头和 ICMP 数据）交给 VPN 客户端软件。</p>\n<p>VPN 客户端软件对这个原始包进行<strong>加密</strong>和<strong>封装</strong>。封装的意思是：把整个原始包当作数据，再在外面套上一个新的 IP 头（也可能有 UDP 头）。这个新 IP 头的目标是 VPN 服务器的公网 IP。</p>\n<p>具体过程：</p>\n<ul>\n<li class=\"\">原始包（要发往 <code>192.168.10.5</code> 的 ICMP 请求）被加密，得到密文。</li>\n<li class=\"\">在密文前面加上新的 IP 头（也可能先加 UDP 头，再 IP 头）：<!-- -->\n<ul>\n<li class=\"\">新源 IP：物理网卡的 IP <code>192.168.1.100</code>（因为要从物理网卡发出去）</li>\n<li class=\"\">新目标 IP：VPN 服务器公网 IP <code>203.0.113.5</code></li>\n<li class=\"\">新协议字段：可能为 UDP（如果是基于 UDP 的 VPN）</li>\n<li class=\"\">UDP 端口：源端口随机，目标端口 1194 等（VPN 服务器监听端口）</li>\n</ul>\n</li>\n<li class=\"\">这个新包被称为<strong>外层包</strong>。</li>\n</ul>\n<h5 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"2253-外层包通过物理网卡发送\">2.2.5.3 外层包通过物理网卡发送<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#2253-%E5%A4%96%E5%B1%82%E5%8C%85%E9%80%9A%E8%BF%87%E7%89%A9%E7%90%86%E7%BD%91%E5%8D%A1%E5%8F%91%E9%80%81\" class=\"hash-link\" aria-label=\"2.2.5.3 外层包通过物理网卡发送的直接链接\" title=\"2.2.5.3 外层包通过物理网卡发送的直接链接\" translate=\"no\">​</a></h5>\n<p>VPN 客户端软件将外层包交给操作系统的 IP 层，此时目标 IP 是 <code>203.0.113.5</code>，操作系统再次查询路由表，这次发现目标 IP 不在公司内网，而是公网地址，于是走默认路由，通过物理网卡发送。</p>\n<p>物理网卡驱动程序把外层包变成电信号，发送到你家路由器。路由器做 NAT，将源 IP <code>192.168.1.100</code> 换成公网 IP <code>198.51.100.10</code>，然后发向互联网，最终到达 VPN 服务器 <code>203.0.113.5</code>。</p>\n<h5 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"2254-vpn-服务器解包和转发\">2.2.5.4 VPN 服务器解包和转发<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#2254-vpn-%E6%9C%8D%E5%8A%A1%E5%99%A8%E8%A7%A3%E5%8C%85%E5%92%8C%E8%BD%AC%E5%8F%91\" class=\"hash-link\" aria-label=\"2.2.5.4 VPN 服务器解包和转发的直接链接\" title=\"2.2.5.4 VPN 服务器解包和转发的直接链接\" translate=\"no\">​</a></h5>\n<p>VPN 服务器收到外层包，根据 UDP 端口和协议知道这是 VPN 流量。它用自己的 VPN 服务程序处理：</p>\n<ul>\n<li class=\"\">拆掉外层 IP 头和 UDP 头，得到密文。</li>\n<li class=\"\">解密得到原始包（源 IP <code>192.168.10.100</code>，目标 IP <code>192.168.10.5</code>）。</li>\n<li class=\"\">VPN 服务器查看这个原始包的目标 IP <code>192.168.10.5</code>，发现它在公司内网，于是将这个原始包直接<strong>扔进公司内网</strong>（通过服务器的物理网卡，它连着公司交换机）。</li>\n<li class=\"\">注意：此时原始包的源 IP 是 <code>192.168.10.100</code>，这正是 VPN 服务器之前分配给虚拟网卡的 IP，所以公司内网的其他设备（包括文件服务器 <code>192.168.10.5</code>）会认为这个包来自公司内网的一台合法设备。</li>\n</ul>\n<h5 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"2255-响应包返回\">2.2.5.5 响应包返回<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#2255-%E5%93%8D%E5%BA%94%E5%8C%85%E8%BF%94%E5%9B%9E\" class=\"hash-link\" aria-label=\"2.2.5.5 响应包返回的直接链接\" title=\"2.2.5.5 响应包返回的直接链接\" translate=\"no\">​</a></h5>\n<p>文件服务器 <code>192.168.10.5</code> 收到 ICMP 请求，生成一个 ICMP 响应，目标 IP 是 <code>192.168.10.100</code>（你家电脑的虚拟网卡 IP）。这个响应包在内网中传输，根据路由会到达 VPN 服务器（因为 VPN 服务器通常也是内网网关或知道路由）。</p>\n<p>VPN 服务器收到响应包（源 <code>192.168.10.5</code>，目标 <code>192.168.10.100</code>），它知道 <code>192.168.10.100</code> 对应的是哪个 VPN 客户端（通过维护的映射表）。于是它对这个响应包做同样的加密和封装：</p>\n<ul>\n<li class=\"\">原始包（响应包）加密</li>\n<li class=\"\">加上外层 IP 头：源 <code>203.0.113.5</code>，目标 <code>198.51.100.10</code>（你家路由器公网 IP）</li>\n<li class=\"\">通过互联网发送</li>\n</ul>\n<p>你家路由器收到后，根据 NAT 表，将外层包转发给内网的家电脑 <code>192.168.1.100</code>。家电脑物理网卡收到，交给操作系统，操作系统根据 UDP 端口识别是 VPN 流量，交给 VPN 客户端。VPN 客户端解包、解密，得到原始的 ICMP 响应包（源 <code>192.168.10.5</code>，目标 <code>192.168.10.100</code>）。然后 VPN 客户端把这个原始包交给虚拟网卡，虚拟网卡再把它向上传递到 IP 层，最终 ping 命令收到响应。</p>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"226-总结-ip-的来源与角色\">2.2.6 总结 IP 的来源与角色<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#226-%E6%80%BB%E7%BB%93-ip-%E7%9A%84%E6%9D%A5%E6%BA%90%E4%B8%8E%E8%A7%92%E8%89%B2\" class=\"hash-link\" aria-label=\"2.2.6 总结 IP 的来源与角色的直接链接\" title=\"2.2.6 总结 IP 的来源与角色的直接链接\" translate=\"no\">​</a></h4>\n<ul>\n<li class=\"\"><strong>物理网卡 IP（<code>192.168.1.100</code>）</strong>：由你家路由器 DHCP 分配，用于和互联网通信。它是你家电脑在<strong>物理网络</strong>中的身份。</li>\n<li class=\"\"><strong>虚拟网卡 IP（<code>192.168.10.100</code>）</strong>：由 VPN 服务器分配的，是你在<strong>公司虚拟网络</strong>中的身份，它在公司内网唯一标识你的设备。它只在 VPN 隧道内有意义，公司内网的其他设备看到这个 IP，就认为你是内部设备。</li>\n<li class=\"\"><strong>数据包封装</strong>：访问公司内网的原始包，源 IP 是虚拟网卡 IP，目标 IP 是公司内网 IP。但这个包不能直接在互联网上传输，必须用物理网卡的 IP 做外层封装，才能通过互联网到达 VPN 服务器。VPN 服务器剥离外层，取出原始包，再送入公司内网。（让原始包能在互联网上传输，VPN 服务器充当“网关”拆装包）</li>\n<li class=\"\"><strong>路由表的作用</strong>：决定哪些目标 IP 走物理网卡，哪些走虚拟网卡。路由表确保公司内网流量自动走虚拟网卡，从而实现“无缝接入”。</li>\n<li class=\"\"><strong>整个过程对应用程序透明</strong>：应用程序只需访问内网 IP，无需知道 VPN 的存在。</li>\n</ul>\n<p><strong>关键点</strong>：</p>\n<ul>\n<li class=\"\">VPN 工作在<strong>网络层（IP层）<strong>或</strong>数据链路层</strong>。</li>\n<li class=\"\">它让远程设备<strong>逻辑上“进入”了目标内网</strong>，拥有内网 IP，可以像本地设备一样访问内网所有资源（不仅限于某个应用）。</li>\n<li class=\"\">隧道内的数据是加密的，保证了私密性。</li>\n<li class=\"\">通常需要一端（VPN 服务器）有公网 IP，或者两端都能主动发起连接（如点对点 VPN 需要 NAT 穿透，但较复杂）。</li>\n</ul>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"23-应用场景\">2.3 应用场景<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#23-%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF\" class=\"hash-link\" aria-label=\"2.3 应用场景的直接链接\" title=\"2.3 应用场景的直接链接\" translate=\"no\">​</a></h3>\n<ul>\n<li class=\"\">公司员工远程办公，接入公司内网访问内部系统（ERP、OA、文件共享）。</li>\n<li class=\"\">分支机构通过 VPN 互联，组成一个大的虚拟局域网。</li>\n<li class=\"\">个人使用 VPN 翻墙（其实是把流量通过境外的 VPN 服务器转发，改变出口 IP）。</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"3-内网穿透的本质和工作原理\">3. 内网穿透的本质和工作原理<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#3-%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F%E7%9A%84%E6%9C%AC%E8%B4%A8%E5%92%8C%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86\" class=\"hash-link\" aria-label=\"3. 内网穿透的本质和工作原理的直接链接\" title=\"3. 内网穿透的本质和工作原理的直接链接\" translate=\"no\">​</a></h2>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"31-本质\">3.1 本质<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#31-%E6%9C%AC%E8%B4%A8\" class=\"hash-link\" aria-label=\"3.1 本质的直接链接\" title=\"3.1 本质的直接链接\" translate=\"no\">​</a></h3>\n<p>内网穿透解决的正是 NAT 带来的“外网无法主动访问内网设备”的问题。<br>\n<!-- -->它的目标不是让你设备“进入”另一个网络，而是<strong>把内网里的某个特定服务（比如远程桌面、Web 服务）“暴露”到公网上，让外网的人能访问到这个服务</strong>。</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"32-原理以向日葵todesk-为例\">3.2 原理（以向日葵/ToDesk 为例）<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#32-%E5%8E%9F%E7%90%86%E4%BB%A5%E5%90%91%E6%97%A5%E8%91%B5todesk-%E4%B8%BA%E4%BE%8B\" class=\"hash-link\" aria-label=\"3.2 原理（以向日葵/ToDesk 为例）的直接链接\" title=\"3.2 原理（以向日葵/ToDesk 为例）的直接链接\" translate=\"no\">​</a></h3>\n<ul>\n<li class=\"\">你家电脑上运行着向日葵客户端，它会主动连接向日葵的<strong>公网服务器</strong>，并保持一个<strong>长连接</strong>（比如 WebSocket 或自定义 TCP 长连）。</li>\n<li class=\"\">这个长连接相当于你家电脑与服务器之间的一条<strong>专用通道</strong>。服务器知道你家电脑在线，并且可以通过这条通道向你家电脑发送指令或数据。</li>\n<li class=\"\">当你在公司用手机或另一台电脑打开向日葵，想控制你家电脑时：<!-- -->\n<ol>\n<li class=\"\">你的公司端 App 告诉服务器：“我要控制设备 A（你家电脑）。”</li>\n<li class=\"\">服务器通过已经存在的长连接，通知你家电脑：“有人要控制你，准备好。”</li>\n<li class=\"\">接下来，服务器尝试帮双方建立<strong>直接的 P2P 连接</strong>（如果网络环境允许，数据不经过服务器，延迟更低）。</li>\n<li class=\"\">如果 P2P 失败，所有远程控制的画面、键盘鼠标数据都通过服务器<strong>中继转发</strong>。</li>\n</ol>\n</li>\n<li class=\"\">这个过程中，你家电脑并没有获得一个公网 IP，也没有融入公司网络，只是<strong>通过服务器中转数据，实现了特定应用（远程桌面）的通信</strong>。</li>\n</ul>\n<p><strong>关键点</strong>：</p>\n<ul>\n<li class=\"\">内网穿透工作在<strong>应用层</strong>（通常是基于 TCP/UDP 的上层协议）。</li>\n<li class=\"\">必须有一个<strong>公网服务器</strong>作为桥梁（或协调者），因为内网设备无法直接接收外来的连接，所以由它主动向外发起连接并维持。</li>\n<li class=\"\">它只针对<strong>特定的端口或服务</strong>进行转发，不会把整个设备接入目标网络，不改变设备的网络身份。</li>\n<li class=\"\"><strong>不涉及虚拟网卡</strong>，也不修改路由表。</li>\n<li class=\"\">数据是否加密取决于具体实现，但通常也会加密，不过加密层次一般只在应用层，不像 VPN 那样对整个 IP 包加密。</li>\n</ul>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"33-应用场景\">3.3 应用场景<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#33-%E5%BA%94%E7%94%A8%E5%9C%BA%E6%99%AF\" class=\"hash-link\" aria-label=\"3.3 应用场景的直接链接\" title=\"3.3 应用场景的直接链接\" translate=\"no\">​</a></h3>\n<ul>\n<li class=\"\">远程控制家中电脑（向日葵、TeamViewer）。</li>\n<li class=\"\">外网访问家里 NAS 上的文件。</li>\n<li class=\"\">开发者在外网调试自己电脑上的 Web 项目（如 ngrok）。</li>\n<li class=\"\">搭建游戏服务器，让朋友直连你的电脑（需要端口映射或内网穿透工具）。</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"4-从-osi-模型看区别\">4. 从 OSI 模型看区别<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#4-%E4%BB%8E-osi-%E6%A8%A1%E5%9E%8B%E7%9C%8B%E5%8C%BA%E5%88%AB\" class=\"hash-link\" aria-label=\"4. 从 OSI 模型看区别的直接链接\" title=\"4. 从 OSI 模型看区别的直接链接\" translate=\"no\">​</a></h2>\n<p>用 OSI 七层模型（或 TCP/IP 五层模型）来定位，会更清晰：</p>\n<table><thead><tr><th>层次</th><th>VPN</th><th>内网穿透</th></tr></thead><tbody><tr><td><strong>网络层（IP）</strong></td><td>VPN 在这里工作：它创建虚拟网络接口，修改路由表，对 IP 包进行封装（隧道）。</td><td>内网穿透一般不管 IP 层，它处理的是更上层的数据。</td></tr><tr><td><strong>传输层（TCP/UDP）</strong></td><td>VPN 隧道本身可能基于 UDP 或 TCP，但 VPN 传输的是完整的 IP 包，所以包含了传输层信息。</td><td>内网穿透工具通常直接转发 TCP 或 UDP 的数据流，但它不模拟网络层连接。</td></tr><tr><td><strong>应用层（HTTP、RDP 等）</strong></td><td>VPN 不关心具体应用，它只是透明地传递任何上层协议的数据。</td><td>内网穿透往往针对特定应用（如远程桌面协议），或者提供一个端口转发，把应用层数据原样传递。</td></tr></tbody></table>\n<hr>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"5-一个生动的比喻\">5. 一个生动的比喻<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#5-%E4%B8%80%E4%B8%AA%E7%94%9F%E5%8A%A8%E7%9A%84%E6%AF%94%E5%96%BB\" class=\"hash-link\" aria-label=\"5. 一个生动的比喻的直接链接\" title=\"5. 一个生动的比喻的直接链接\" translate=\"no\">​</a></h2>\n<ul>\n<li class=\"\"><strong>VPN</strong>：就像你在家和公司之间建了一条<strong>地下隧道</strong>，隧道两端各有一个门。你从家进入隧道，出来时已经在公司内部，可以自由使用公司的所有设施（打印机、会议室、咖啡机）。隧道本身是加密的，别人看不到你在里面做什么。</li>\n<li class=\"\"><strong>内网穿透</strong>：就像你家在闹市区有一间屋子，你想让朋友能来玩，但地址不公开。于是你雇了一个<strong>信使</strong>（公网服务器）站在街角。朋友先找到信使，信使通过一个<strong>专用的对讲机</strong>（长连接）告诉你“有人找你”，然后由你把门打开一条缝（P2P 连接），或者让信使帮你传话（中继）。朋友每次只能通过这个特定方式联系你，不能直接进你家到处逛。</li>\n</ul>\n<hr>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"6-总结本质区别\">6. 总结本质区别<a href=\"https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles#6-%E6%80%BB%E7%BB%93%E6%9C%AC%E8%B4%A8%E5%8C%BA%E5%88%AB\" class=\"hash-link\" aria-label=\"6. 总结本质区别的直接链接\" title=\"6. 总结本质区别的直接链接\" translate=\"no\">​</a></h2>\n<table><thead><tr><th>维度</th><th>VPN</th><th>内网穿透</th></tr></thead><tbody><tr><td><strong>核心目的</strong></td><td>让远程设备<strong>融入</strong>目标网络，获得内网身份，可访问所有资源。</td><td>让外网用户<strong>访问</strong>内网中的特定服务。</td></tr><tr><td><strong>网络层次</strong></td><td>网络层/数据链路层（虚拟网卡、路由表修改）。</td><td>应用层（端口转发/代理）。</td></tr><tr><td><strong>接入方式</strong></td><td>设备获得内网 IP，路由表修改，所有内网流量自动走隧道。</td><td>不改变设备 IP，只转发特定应用的通信。</td></tr><tr><td><strong>是否需要公网服务器</strong></td><td>通常需要 VPN 服务器有公网 IP（或双方都有公网 IP 直连）。</td><td>几乎一定需要公网服务器作为协调或中继。</td></tr><tr><td><strong>安全性</strong></td><td>加密整个 IP 包，隧道内所有通信都受保护。</td><td>加密取决于应用实现，通常只加密应用数据。</td></tr><tr><td><strong>典型产品</strong></td><td>OpenVPN, WireGuard, Cisco AnyConnect</td><td>向日葵, ngrok, frp</td></tr></tbody></table>\n<ul>\n<li class=\"\"><strong>VPN</strong>：让你“进入”另一个网络，成为其中的一员，可以访问该网络内的所有设备和服务。</li>\n<li class=\"\"><strong>内网穿透</strong>：让你“打开一扇窗”，将家里某个服务临时暴露给外网，但你的设备并未真正进入外网所在的网络。</li>\n</ul>",
            "url": "https://devvv.cn/blog/network-vpn-and-internet-tunneling-principles",
            "title": "VPN和内网穿透原理",
            "summary": "这是VPN和内网穿透原理",
            "date_modified": "2026-03-19T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "网络原理",
                "vpn",
                "内网穿透"
            ]
        },
        {
            "id": "https://devvv.cn/blog/build-a-personal-site-with-astro-and-starlight",
            "content_html": "<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"为什么选择-astro--starlight\">为什么选择 Astro + Starlight？<a href=\"https://devvv.cn/blog/build-a-personal-site-with-astro-and-starlight#%E4%B8%BA%E4%BB%80%E4%B9%88%E9%80%89%E6%8B%A9-astro--starlight\" class=\"hash-link\" aria-label=\"为什么选择 Astro + Starlight？的直接链接\" title=\"为什么选择 Astro + Starlight？的直接链接\" translate=\"no\">​</a></h2>\n<p>官网：<a href=\"https://docs.astro.build/zh-cn/install-and-setup/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://docs.astro.build/zh-cn/install-and-setup/</a></p>\n<table><thead><tr><th style=\"text-align:left\">需求</th><th style=\"text-align:left\">Astro + Starlight 如何满足</th></tr></thead><tbody><tr><td style=\"text-align:left\">官网、产品介绍</td><td style=\"text-align:left\">Astro 天生适合营销页面，支持岛屿架构，可自由定制首页和产品页</td></tr><tr><td style=\"text-align:left\">API 文档</td><td style=\"text-align:left\">Starlight 内置文档主题，配合 <strong>starlight-openapi</strong> 插件可从 OpenAPI 规范自动生成 API 文档</td></tr><tr><td style=\"text-align:left\">技术文章与书籍</td><td style=\"text-align:left\">Starlight 完美支持 Markdown/MDX，内置搜索和导航</td></tr><tr><td style=\"text-align:left\">知识库</td><td style=\"text-align:left\">文档即知识库，支持版本化、多级侧边栏</td></tr><tr><td style=\"text-align:left\">App 落地页</td><td style=\"text-align:left\">可创建独立页面，支持响应式设计，Astro 静态生成性能极佳</td></tr><tr><td style=\"text-align:left\">API 开放平台</td><td style=\"text-align:left\">可通过 Astro 的实时内容集合从后端获取动态数据</td></tr><tr><td style=\"text-align:left\">对接 Spring Boot</td><td style=\"text-align:left\">Astro 支持从 API 获取数据，可轻松对接后端接口</td></tr></tbody></table>\n<p><strong>核心优势</strong>：Astro 作为基础框架提供高性能和灵活性，Starlight 提供开箱即用的文档功能，插件生态补齐 API 文档、博客等能力 。Astro 5.10+ 的实时内容集合让可以按需从后端获取数据，实现静态与动态的完美结合 。</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"一环境准备\">一、环境准备<a href=\"https://devvv.cn/blog/build-a-personal-site-with-astro-and-starlight#%E4%B8%80%E7%8E%AF%E5%A2%83%E5%87%86%E5%A4%87\" class=\"hash-link\" aria-label=\"一、环境准备的直接链接\" title=\"一、环境准备的直接链接\" translate=\"no\">​</a></h2>\n<p>确保已安装：</p>\n<ul>\n<li class=\"\"><strong>Node.js</strong> v22.12.0 或更高版本。（奇数版本如 v23 不支持）</li>\n<li class=\"\"><strong>npm</strong> 或 <strong>pnpm</strong> / <strong>yarn</strong></li>\n<li class=\"\">vscode 安装 Astro 插件</li>\n</ul>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">node</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--version</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--version</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>输出：</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">终端输出<span style=\"flex:1;text-align:right\">text</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">vv@jjc:~/桌面/vv/web$ node --version</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">v24.14.0</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">vv@jjc:~/桌面/vv/web$ npm --version</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">11.9.0</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"二创建-astro--starlight-项目\">二、创建 Astro + Starlight 项目<a href=\"https://devvv.cn/blog/build-a-personal-site-with-astro-and-starlight#%E4%BA%8C%E5%88%9B%E5%BB%BA-astro--starlight-%E9%A1%B9%E7%9B%AE\" class=\"hash-link\" aria-label=\"二、创建 Astro + Starlight 项目的直接链接\" title=\"二、创建 Astro + Starlight 项目的直接链接\" translate=\"no\">​</a></h2>\n<p><a href=\"https://github.com/withastro/astro\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://github.com/withastro/astro</a></p>\n<p>官方模板链接(全部模板)：<a href=\"https://astro.build/themes/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://astro.build/themes/</a></p>\n<p>官方模板链接(免费模板)：<a href=\"https://astro.build/themes/1/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://astro.build/themes/1/</a></p>\n<p>Starlight 社区资源链接：<a href=\"https://starlight.astro.build/resources/community-content/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://starlight.astro.build/resources/community-content/</a></p>\n<p>以下模板聚合网站定期更新 Astro 模板榜单，且已验证兼容性：</p>\n<p><a href=\"https://adminlte.io/blog/free-astro-templates/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">AdminLTE.IO</a>：</p>\n<ul>\n<li class=\"\">已筛选 15+ 免费 Astro 5 模板</li>\n<li class=\"\">每个模板都标注了 GitHub 星标和适用场景</li>\n</ul>\n<p><a href=\"https://statichunt.com/astro-themes\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">Statichunt</a>：</p>\n<ul>\n<li class=\"\">专注静态站生成器的模板库</li>\n<li class=\"\">可按类型、技术栈筛选</li>\n</ul>\n<p>Astrowind：(<a href=\"https://github.com/arthelokyo/astrowind)%5Bhttps://github.com/arthelokyo/astrowind\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://github.com/arthelokyo/astrowind)[https://github.com/arthelokyo/astrowind</a>]</p>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"1-初始化项目\">1. 初始化项目<a href=\"https://devvv.cn/blog/build-a-personal-site-with-astro-and-starlight#1-%E5%88%9D%E5%A7%8B%E5%8C%96%E9%A1%B9%E7%9B%AE\" class=\"hash-link\" aria-label=\"1. 初始化项目的直接链接\" title=\"1. 初始化项目的直接链接\" translate=\"no\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 使用 Starlight 模板创建项目</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> create astro@latest -- </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--template</span><span class=\"token plain\"> starlight</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 按照提示操作：</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># - 输入项目名称（例如：FriendlyWebV2）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># - 选择 TypeScript（推荐 Yes）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># - 选择初始化 Git（推荐 Yes）</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"2-启动开发环境\">2. 启动开发环境<a href=\"https://devvv.cn/blog/build-a-personal-site-with-astro-and-starlight#2-%E5%90%AF%E5%8A%A8%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83\" class=\"hash-link\" aria-label=\"2. 启动开发环境的直接链接\" title=\"2. 启动开发环境的直接链接\" translate=\"no\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">pnpm</span><span class=\"token plain\"> start</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>访问 <code>http://localhost:4321</code> 查看默认文档站。</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"mizuki\">Mizuki<a href=\"https://devvv.cn/blog/build-a-personal-site-with-astro-and-starlight#mizuki\" class=\"hash-link\" aria-label=\"Mizuki的直接链接\" title=\"Mizuki的直接链接\" translate=\"no\">​</a></h2>\n<p><a href=\"https://github.com/matsuzaka-yuki/mizuki\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://github.com/matsuzaka-yuki/mizuki</a></p>\n<p>在开始使用 Mizuki 之前，您需要确保系统满足以下要求：</p>\n<ul>\n<li class=\"\">Node.js &gt;= 20</li>\n<li class=\"\">pnpm &gt;= 9</li>\n<li class=\"\">Git</li>\n</ul>\n<p>集成步骤：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> clone https://github.com/matsuzaka-yuki/mizuki.git</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> Mizuki</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-g</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">pnpm</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果没安装 pnpm</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">pnpm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>然后复制根目录下的 <code>.env.example</code> 文件并重命名为 <code>.env</code>，之后启动项目：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">pnpm</span><span class=\"token plain\"> dev</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>打包则运行以下命令将网站打包成静态文件，生成到 dist 目录中：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">pnpm</span><span class=\"token plain\"> build</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>生成的 dist 目录可以部署到自己的服务器上。</p>",
            "url": "https://devvv.cn/blog/build-a-personal-site-with-astro-and-starlight",
            "title": "Astro + Starlight 搭建个人站点",
            "summary": "Astro + Starlight 搭建个人站点",
            "date_modified": "2026-03-13T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "Astro",
                "TypeScript‌",
                "React"
            ]
        },
        {
            "id": "https://devvv.cn/blog/docsaurus-build-self-site-record",
            "content_html": "<p>官网：<a href=\"https://www.docusaurus.cn/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://www.docusaurus.cn/</a></p>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"1-进入项目目录\">1. 进入项目目录<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#1-%E8%BF%9B%E5%85%A5%E9%A1%B9%E7%9B%AE%E7%9B%AE%E5%BD%95\" class=\"hash-link\" aria-label=\"1. 进入项目目录的直接链接\" title=\"1. 进入项目目录的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 创建新项目</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">npx create-docusaurus@latest FriendlyWeb classic</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 进入项目目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> FriendlyWeb</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果不使用 docker</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 启动开发服务器</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run start</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 打包</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run build</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果缺少依赖，例如：找不到 prismjs </span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> prism-react-renderer@^2.4.1</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">项目结构<span style=\"flex:1;text-align:right\">text</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">docusaurus.config.ts      # 网站配置文件</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">sidebars.ts              # 侧边栏配置</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">package.json             # 项目依赖和脚本</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">package-lock.json        # 锁定依赖版本（重要！）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">tsconfig.json            # TypeScript 配置</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">README.md                # 项目说明</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">blog/                    # 博客文章（你的内容）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">docs/                    # 文档内容（你的内容）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">src/                     # 源代码（自定义组件、页面）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">static/                  # 静态资源（图片、文件等）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">node_modules/            # 体积巨大，可以在服务器上通过 npm install 重新生成</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"2-docker-配置\">2. Docker 配置<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#2-docker-%E9%85%8D%E7%BD%AE\" class=\"hash-link\" aria-label=\"2. Docker 配置的直接链接\" title=\"2. Docker 配置的直接链接\" translate=\"no\">​</a></h2>\n<p>创建 Dockerfile（项目根目录）：</p>\n<div class=\"language-dockerfile codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">Dockerfile<span style=\"flex:1;text-align:right\">dockerfile</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-dockerfile codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># syntax=docker/dockerfile:1</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># Stage 1: 基础镜像</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">FROM node:20-bookworm AS base</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ENV FORCE_COLOR=0</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ENV NODE_ENV=development</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">RUN corepack enable</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">WORKDIR /app</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># Stage 2: 开发环境</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">FROM base AS development</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 复制依赖文件</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">COPY package*.json ./</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 安装所有依赖（包括开发依赖）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">RUN npm install</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 暴露开发服务器端口</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">EXPOSE 3000</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 启动开发服务器（热重载已配置）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">CMD [\"npm\", \"run\", \"start\", \"--\", \"--host\", \"0.0.0.0\", \"--poll\", \"1000\"]</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># Stage 3: 构建生产版本</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">FROM base AS build</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 设置生产环境</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ENV NODE_ENV=production</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 复制依赖文件</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">COPY package*.json ./</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 只安装生产依赖（更小体积）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">RUN npm ci --omit=dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 复制源代码</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">COPY . .</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 构建静态文件</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">RUN npm run build</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># Stage 4: 生产环境</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">FROM nginx:stable-alpine AS production</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 复制构建产物</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">COPY --from=build /app/build /usr/share/nginx/html</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 复制 nginx 配置</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">COPY nginx.conf /etc/nginx/conf.d/default.conf</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"># 暴露端口</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">EXPOSE 80</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">CMD [\"nginx\", \"-g\", \"daemon off;\"]</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<p>创建 docker-compose.yml（项目根目录）：</p>\n<div class=\"language-yaml codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">docker-compose.yml<span style=\"flex:1;text-align:right\">yaml</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-yaml codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># version: '3.8'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">services</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 开发服务</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">blog-dev</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">build</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">context</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> .</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">target</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> development</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">dockerfile</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> Dockerfile</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">container_name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> blog</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">ports</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"3000:3000\"</span><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 网站主端口</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"35729:35729\"</span><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 热重载 live-reload 端口</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">volumes</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 挂载源代码（选择性挂载，避免覆盖 node_modules）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./blog</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/blog</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./docs</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/docs</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./src</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/src</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./static</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/static</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./docusaurus.config.ts</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/docusaurus.config.ts</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./sidebars.ts</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/sidebars.ts</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./tsconfig.json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/tsconfig.json</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./package.json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/package.json</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 不挂载 node_modules，使用容器内的</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">environment</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> NODE_ENV=development</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> CHOKIDAR_USEPOLLING=true  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 文件监听优化</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">stdin_open</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">true</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">tty</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">true</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">restart</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> unless</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">stopped</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 生产预览服务（可选）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">blog-prod</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">build</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">context</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> .</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">target</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> production</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">dockerfile</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> Dockerfile</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">container_name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> blog</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">prod</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">ports</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"8080:80\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">environment</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> NODE_ENV=production</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">restart</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> unless</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">stopped</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<p>创建 nginx.conf（项目根目录，用于生产环境）：</p>\n<div class=\"language-nginx codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">nginx.conf<span style=\"flex:1;text-align:right\">nginx</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-nginx codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">server {</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    listen 80;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    server_name localhost;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    root /usr/share/nginx/html;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    index index.html;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    # 开启 gzip 压缩</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    gzip on;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    gzip_vary on;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    gzip_min_length 1024;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    gzip_types text/plain text/css text/xml text/javascript </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                application/javascript application/xml+rss </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                application/json application/xml;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    # 安全 headers</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    add_header X-Frame-Options \"SAMEORIGIN\" always;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    add_header X-Content-Type-Options \"nosniff\" always;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    add_header X-XSS-Protection \"1; mode=block\" always;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    # 处理 SPA 路由</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    location / {</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        try_files $uri $uri/ /index.html;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    }</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    # 静态资源缓存</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    location /assets/ {</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        expires 1y;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        add_header Cache-Control \"public, immutable\";</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    }</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    location /blog/ {</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        expires 1y;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        add_header Cache-Control \"public, immutable\";</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    }</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    location /img/ {</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        expires 1y;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        add_header Cache-Control \"public, immutable\";</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    }</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    # 健康检查</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    location /health {</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        access_log off;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        return 200 \"healthy\\n\";</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        add_header Content-Type text/plain;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    }</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    # 禁止访问隐藏文件</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    location ~ /\\. {</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        deny all;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        access_log off;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        log_not_found off;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    }</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<p>创建 .dockerignore（项目根目录）：</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">.dockerignore<span style=\"flex:1;text-align:right\">text</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">node_modules</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">build</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">dist</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">logs</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">coverage</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">tmp</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">temp</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">README.md</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">docker-compose*.yml</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">.docusaurus</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">.git</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">.github</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">.gitignore</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">.vscode</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">.idea</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">.env</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">.env.local</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">.env.development.local</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">.env.test.local</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">.env.production.local</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">.DS_Store</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">.dockerignore</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">*.log</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">npm-debug.log*</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">yarn-debug.log*</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">yarn-error.log*</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">*.swp</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">*.swo</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">*~</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">Thumbs.db</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"3-vscode-开发环境配置\">3. VSCode 开发环境配置<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#3-vscode-%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE\" class=\"hash-link\" aria-label=\"3. VSCode 开发环境配置的直接链接\" title=\"3. VSCode 开发环境配置的直接链接\" translate=\"no\">​</a></h2>\n<p>安装 Dev Containers 扩展。</p>\n<p>创建 .devcontainer/devcontainer.json（项目根目录）：</p>\n<div class=\"language-json codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">.devcontainer/devcontainer.json<span style=\"flex:1;text-align:right\">json</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-json codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"name\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"FriendlyWeb Development\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"dockerComposeFile\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"../docker-compose.yml\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"service\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"blog-dev\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"workspaceFolder\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"/app\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"shutdownAction\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"stopCompose\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"extensions\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"dbaeumer.vscode-eslint\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"esbenp.prettier-vscode\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"bradlc.vscode-tailwindcss\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"ms-vscode.vscode-typescript-next\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"settings\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"terminal.integrated.defaultProfile.linux\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"bash\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"editor.formatOnSave\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"editor.defaultFormatter\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"esbenp.prettier-vscode\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"typescript.tsdk\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"node_modules/typescript/lib\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"files.watcherExclude\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"**/node_modules/**\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"**/.git/objects/**\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"**/.git/subtree-cache/**\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"**/build/**\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"forwardPorts\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3000</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">35729</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"postCreateCommand\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"npm install\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"remoteUser\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"node\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"4-typescript-配置\">4. TypeScript 配置<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#4-typescript-%E9%85%8D%E7%BD%AE\" class=\"hash-link\" aria-label=\"4. TypeScript 配置的直接链接\" title=\"4. TypeScript 配置的直接链接\" translate=\"no\">​</a></h2>\n<p>创建 tsconfig.json（项目根目录）：</p>\n<div class=\"language-json codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">tsconfig.json<span style=\"flex:1;text-align:right\">json</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-json codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// This file is not used in compilation. It is here just for a nice editor experience.</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"extends\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"@docusaurus/tsconfig\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"compilerOptions\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"baseUrl\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\".\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"jsx\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"react-jsx\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"paths\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"@site/*\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"*\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"types\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"@docusaurus/module-type-aliases\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"@docusaurus/theme-classic\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"exclude\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\".docusaurus\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"build\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<p>创建 src/types.d.ts（类型声明文件）：</p>\n<div class=\"language-typescript codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">src/types.d.ts<span style=\"flex:1;text-align:right\">typescript</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-typescript codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/// &lt;reference types=\"@docusaurus/module-type-aliases\" /&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/// &lt;reference types=\"@docusaurus/theme-classic\" /&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">declare</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">module</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"*.md\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">type</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> ComponentType </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"react\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> metadata</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    title</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    description</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    permalink</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    date</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Date</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    tags</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">?</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">Array</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> label</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> permalink</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\">key</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">unknown</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> toc</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">Array</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    value</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">string</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    level</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token builtin\" style=\"color:hsl(119, 34%, 47%)\">number</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> Component</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> ComponentType</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">default</span><span class=\"token plain\"> Component</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">declare</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">module</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"*.mdx\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">*</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"*.md\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"5-docusaurusconfigts\">5. docusaurus.config.ts<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#5-docusaurusconfigts\" class=\"hash-link\" aria-label=\"5. docusaurus.config.ts的直接链接\" title=\"5. docusaurus.config.ts的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-typescript codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">docusaurus.config.ts<span style=\"flex:1;text-align:right\">typescript</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-typescript codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">themes </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">as</span><span class=\"token plain\"> prismThemes</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'prism-react-renderer'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">type</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">Config</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@docusaurus/types'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">type</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">*</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">as</span><span class=\"token plain\"> Preset </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@docusaurus/preset-classic'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> config</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Config </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  title</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'vv的博客'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  tagline</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'记录技术与生活'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  favicon</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'img/favicon.ico'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  future</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    v4</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  url</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'https://your-docusaurus-site.example.com'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  baseUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'/'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  organizationName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'your-github-name'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  projectName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'your-repo-name'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  onBrokenLinks</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'throw'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  markdown</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    mermaid</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    hooks</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      onBrokenMarkdownLinks</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'warn'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  i18n</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    defaultLocale</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'zh-CN'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    locales</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'zh-CN'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  presets</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'classic'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        docs</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">         sidebarPath</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">require</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">resolve</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'./sidebars.js'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          editUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'#'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          showLastUpdateTime</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">   </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 显示最后更新时间</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          showLastUpdateAuthor</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 显示最后更新作者</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        blog</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          showReadingTime</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          feedOptions</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            type</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'rss'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'atom'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            xslt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          editUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'#'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          onInlineTags</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'warn'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          onInlineAuthors</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'warn'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          onUntruncatedBlogPosts</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'warn'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          blogSidebarTitle</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'最新文章'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          blogSidebarCount</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">5</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        theme</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          customCss</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">require</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">resolve</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'./src/css/custom.css'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        sitemap</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          changefreq</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'weekly'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          priority</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0.5</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> satisfies Preset</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Options</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 添加多实例插件 - 支持多本书</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  plugins</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@docusaurus/plugin-content-docs'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'docker-book'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        path</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'books/docker_practice'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        routeBasePath</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'books/docker_practice'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        sidebarPath</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">require</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">resolve</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'./sidebars-docker.js'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        editUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'#'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        showLastUpdateTime</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        showLastUpdateAuthor</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 以后可以添加更多书籍</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// [</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//   '@docusaurus/plugin-content-docs',</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//   {</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//     id: 'kubernetes-book',</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//     path: 'books/kubernetes_handbook',</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//     routeBasePath: 'books/kubernetes_handbook',</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//     sidebarPath: require.resolve('./sidebars-kubernetes.js'),</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//   },</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ],</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  themeConfig</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    image</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'img/docusaurus-social-card.jpg'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    colorMode</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      defaultMode</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'light'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      disableSwitch</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      respectPrefersColorScheme</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    tableOfContents</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      minHeadingLevel</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 从 h2 开始显示</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      maxHeadingLevel</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">5</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 最多显示到 h5</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    navbar</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      title</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'我的博客'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      logo</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        alt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'vv的博客'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        src</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'img/logo.svg'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      items</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          type</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'docSidebar'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          sidebarId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'tutorialSidebar'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          position</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'left'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          label</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'文档'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">to</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'/blog'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> label</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'博客'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> position</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'left'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          type</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'dropdown'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          label</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'📚 技术书籍'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          position</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'left'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          items</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">              type</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'docSidebar'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">              sidebarId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'dockerBookSidebar'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">              docsPluginId</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'docker-book'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">              label</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'🐳 Docker — 从入门到实践'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 可以添加更多书籍</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// {</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//   type: 'docSidebar',</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//   sidebarId: 'kubernetesBookSidebar',</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//   label: '☸️ Kubernetes 指南',</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// },</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">to</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'/about'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> label</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'关于'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> position</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'left'</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          href</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'https://gitee.com/weijun233'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          label</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'GitHub'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          position</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'right'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          type</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'localeDropdown'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          position</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'right'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    footer</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      style</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'dark'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// links: [</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//   {</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//     title: '文档',</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//     items: [</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//       {</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//         label: '介绍',</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//         to: '/docs/intro',</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//       },</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//     ],</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//   },</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//   {</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//     title: '社区',</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//     items: [</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//       { label: 'Stack Overflow', href: '#' },</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//       { label: 'Discord', href: '#' },</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//       { label: 'GitHub', href: '#' },</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//       { label: 'Twitter', href: '#' }</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//     ],</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//   },</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//   {</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//     title: '更多',</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//     items: [</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//       {</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//         label: '博客',</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//         to: '/blog',</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//       },</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//       {</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//         label: 'GitHub',</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//         href: '#',</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//       },</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//     ],</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">//   },</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ],</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      copyright</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token template-string template-punctuation string\" style=\"color:hsl(119, 34%, 47%)\">`</span><span class=\"token template-string string\" style=\"color:hsl(119, 34%, 47%)\">Copyright © </span><span class=\"token template-string interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">${</span><span class=\"token template-string interpolation keyword\" style=\"color:hsl(301, 63%, 40%)\">new</span><span class=\"token template-string interpolation\"> </span><span class=\"token template-string interpolation class-name\" style=\"color:hsl(35, 99%, 36%)\">Date</span><span class=\"token template-string interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token template-string interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token template-string interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token template-string interpolation function\" style=\"color:hsl(221, 87%, 60%)\">getFullYear</span><span class=\"token template-string interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token template-string interpolation punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token template-string interpolation interpolation-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token template-string string\" style=\"color:hsl(119, 34%, 47%)\"> vv 的个人网站.</span><span class=\"token template-string template-punctuation string\" style=\"color:hsl(119, 34%, 47%)\">`</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    prism</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      theme</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> prismThemes</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">github</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      darkTheme</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> prismThemes</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">dracula</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      additionalLanguages</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'bash'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'json'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'typescript'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'javascript'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    metadata</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'keywords'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> content</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'个人网站, 博客, tech'</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"> name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'author'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> content</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'vv'</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> satisfies Preset</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">ThemeConfig</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">default</span><span class=\"token plain\"> config</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"6-sidebarsts侧边栏配置\">6. sidebars.ts（侧边栏配置）<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#6-sidebarsts%E4%BE%A7%E8%BE%B9%E6%A0%8F%E9%85%8D%E7%BD%AE\" class=\"hash-link\" aria-label=\"6. sidebars.ts（侧边栏配置）的直接链接\" title=\"6. sidebars.ts（侧边栏配置）的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-typescript codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">sidebars.ts<span style=\"flex:1;text-align:right\">typescript</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-typescript codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">type</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">SidebarsConfig</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@docusaurus/plugin-content-docs'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// This runs in Node.js - Don't use client-side code here (browser APIs, JSX...)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token doc-comment comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token doc-comment comment\" style=\"color:hsl(230, 4%, 64%)\"> * Creating a sidebar enables you to:</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token doc-comment comment\" style=\"color:hsl(230, 4%, 64%)\"> - create an ordered group of docs</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token doc-comment comment\" style=\"color:hsl(230, 4%, 64%)\"> - render a sidebar for each doc of that group</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token doc-comment comment\" style=\"color:hsl(230, 4%, 64%)\"> - provide next/previous navigation</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token doc-comment comment\" style=\"display:inline-block;color:hsl(230, 4%, 64%)\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token doc-comment comment\" style=\"color:hsl(230, 4%, 64%)\"> The sidebars can be generated from the filesystem, or explicitly defined here.</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token doc-comment comment\" style=\"display:inline-block;color:hsl(230, 4%, 64%)\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token doc-comment comment\" style=\"color:hsl(230, 4%, 64%)\"> Create as many sidebars as you want.</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token doc-comment comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> sidebars</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> SidebarsConfig </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// By default, Docusaurus generates a sidebar from the docs folder structure</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  tutorialSidebar</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">type</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'autogenerated'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> dirName</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'.'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// But you can create a sidebar manually</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/*</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">  tutorialSidebar: [</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">    'intro',</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">    'hello',</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">    {</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">      type: 'category',</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">      label: 'Tutorial',</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">      items: ['tutorial-basics/create-a-document'],</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">    },</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">  ],</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">   */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">default</span><span class=\"token plain\"> sidebars</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"7-srccsscustomcss自定义样式\">7. src/css/custom.css（自定义样式）<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#7-srccsscustomcss%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A0%B7%E5%BC%8F\" class=\"hash-link\" aria-label=\"7. src/css/custom.css（自定义样式）的直接链接\" title=\"7. src/css/custom.css（自定义样式）的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-css codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">custom.css<span style=\"flex:1;text-align:right\">css</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-css codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/**</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * Any CSS included here will be global. The classic template</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * bundles Infima by default. Infima is a CSS framework designed to</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> * work well for content-centric websites.</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"> */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/* You can override the default Infima variables here. */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token selector pseudo-class\" style=\"color:hsl(119, 34%, 47%)\">:root</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--ifm-color-primary</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token hexcode color\">#2e8555</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--ifm-color-primary-dark</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token hexcode color\">#29784c</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--ifm-color-primary-darker</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token hexcode color\">#277148</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--ifm-color-primary-darkest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token hexcode color\">#205d3b</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--ifm-color-primary-light</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token hexcode color\">#33925d</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--ifm-color-primary-lighter</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token hexcode color\">#359962</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--ifm-color-primary-lightest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token hexcode color\">#3cad6e</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--ifm-code-font-size</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">95</span><span class=\"token unit\">%</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--docusaurus-highlighted-code-line-bg</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token color function\" style=\"color:hsl(221, 87%, 60%)\">rgba</span><span class=\"token color punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token color number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token color punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token color\"> </span><span class=\"token color number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token color punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token color\"> </span><span class=\"token color number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token color punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token color\"> </span><span class=\"token color number\" style=\"color:hsl(35, 99%, 36%)\">0.1</span><span class=\"token color punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">/* For readability concerns, you should choose a lighter palette in dark mode. */</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token selector attribute punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token selector attribute attr-name\" style=\"color:hsl(35, 99%, 36%)\">data-theme</span><span class=\"token selector attribute operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token selector attribute attr-value\" style=\"color:hsl(119, 34%, 47%)\">'dark'</span><span class=\"token selector attribute punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--ifm-color-primary</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token hexcode color\">#25c2a0</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--ifm-color-primary-dark</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token hexcode color\">#21af90</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--ifm-color-primary-darker</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token hexcode color\">#1fa588</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--ifm-color-primary-darkest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token hexcode color\">#1a8870</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--ifm-color-primary-light</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token hexcode color\">#29d5b0</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--ifm-color-primary-lighter</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token hexcode color\">#32d8b4</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--ifm-color-primary-lightest</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token hexcode color\">#4fddbf</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">--docusaurus-highlighted-code-line-bg</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token color function\" style=\"color:hsl(221, 87%, 60%)\">rgba</span><span class=\"token color punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token color number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token color punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token color\"> </span><span class=\"token color number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token color punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token color\"> </span><span class=\"token color number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token color punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token color\"> </span><span class=\"token color number\" style=\"color:hsl(35, 99%, 36%)\">0.3</span><span class=\"token color punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"8-packagejson\">8. package.json<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#8-packagejson\" class=\"hash-link\" aria-label=\"8. package.json的直接链接\" title=\"8. package.json的直接链接\" translate=\"no\">​</a></h2>\n<p>主要新增了 devDependencies。</p>\n<div class=\"language-json codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">package.json<span style=\"flex:1;text-align:right\">json</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-json codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"name\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"friendly-web\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"version\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"0.0.0\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"private\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"scripts\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"docusaurus\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"docusaurus\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"start\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"docusaurus start\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"build\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"docusaurus build\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"swizzle\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"docusaurus swizzle\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"deploy\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"docusaurus deploy\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"clear\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"docusaurus clear\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"serve\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"docusaurus serve\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"write-translations\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"docusaurus write-translations\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"write-heading-ids\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"docusaurus write-heading-ids\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"typecheck\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"tsc\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"dependencies\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"@docusaurus/core\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"3.9.2\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"@docusaurus/preset-classic\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"3.9.2\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"@mdx-js/react\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"^3.0.0\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"clsx\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"^2.0.0\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"prism-react-renderer\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"^2.3.0\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"react\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"^19.0.0\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"react-dom\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"^19.0.0\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"devDependencies\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"@docusaurus/module-type-aliases\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"^3.9.2\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"@docusaurus/tsconfig\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"^3.9.2\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"@docusaurus/types\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"^3.9.2\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"@types/react\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"^19.2.14\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"@types/react-dom\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"^19.2.3\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"typescript\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"~5.6.2\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"browserslist\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"production\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"&gt;0.5%\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"not dead\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"not op_mini all\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"development\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"last 3 chrome version\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"last 3 firefox version\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"last 5 safari version\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"engines\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"node\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"&gt;=20.0\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"9-启动项目\">9. 启动项目<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#9-%E5%90%AF%E5%8A%A8%E9%A1%B9%E7%9B%AE\" class=\"hash-link\" aria-label=\"9. 启动项目的直接链接\" title=\"9. 启动项目的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 构建并启动容器</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose up blog-dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 或后台运行</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose up </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-d</span><span class=\"token plain\"> blog-dev</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>启动完成后访问 <a href=\"http://localhost:3000/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">http://localhost:3000</a> 查看网站。</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"10-重启-vscode-使用-docker-环境\">10. 重启 vscode 使用 docker 环境<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#10-%E9%87%8D%E5%90%AF-vscode-%E4%BD%BF%E7%94%A8-docker-%E7%8E%AF%E5%A2%83\" class=\"hash-link\" aria-label=\"10. 重启 vscode 使用 docker 环境的直接链接\" title=\"10. 重启 vscode 使用 docker 环境的直接链接\" translate=\"no\">​</a></h2>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"方法一使用-vscode-自动检测-推荐\">方法一：使用 VSCode 自动检测 (推荐)<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E6%96%B9%E6%B3%95%E4%B8%80%E4%BD%BF%E7%94%A8-vscode-%E8%87%AA%E5%8A%A8%E6%A3%80%E6%B5%8B-%E6%8E%A8%E8%8D%90\" class=\"hash-link\" aria-label=\"方法一：使用 VSCode 自动检测 (推荐)的直接链接\" title=\"方法一：使用 VSCode 自动检测 (推荐)的直接链接\" translate=\"no\">​</a></h3>\n<ol>\n<li class=\"\">打开 VSCode</li>\n<li class=\"\">打开项目文件夹 <code>/home/vv/桌面/vv/web/FriendlyWeb</code></li>\n<li class=\"\">VSCode 会检测到 <code>.devcontainer/devcontainer.json</code> 文件</li>\n<li class=\"\">点击右下角的 <strong>\"Reopen in Container\"</strong> 按钮</li>\n<li class=\"\">VSCode 会自动构建 Docker 镜像并启动容器</li>\n<li class=\"\">等待容器启动完成，所有依赖会自动安装</li>\n</ol>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"重启vscode后右下角\" src=\"data:image/png;base64,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\" width=\"462\" height=\"139\" class=\"img_m9Pm\"></p>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"方法二手动启动\">方法二：手动启动<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E6%96%B9%E6%B3%95%E4%BA%8C%E6%89%8B%E5%8A%A8%E5%90%AF%E5%8A%A8\" class=\"hash-link\" aria-label=\"方法二：手动启动的直接链接\" title=\"方法二：手动启动的直接链接\" translate=\"no\">​</a></h3>\n<p>如果 VSCode 没有自动提示，可以:</p>\n<ol>\n<li class=\"\">按 <code>F1</code> 打开命令面板</li>\n<li class=\"\">输入 <code>Dev Containers: Reopen in Container</code></li>\n<li class=\"\">选择并确认</li>\n</ol>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"已配置的扩展\">已配置的扩展<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E5%B7%B2%E9%85%8D%E7%BD%AE%E7%9A%84%E6%89%A9%E5%B1%95\" class=\"hash-link\" aria-label=\"已配置的扩展的直接链接\" title=\"已配置的扩展的直接链接\" translate=\"no\">​</a></h3>\n<p>.devcontainer/devcontainer.json 中已配置的扩展:</p>\n<ul>\n<li class=\"\"><strong>ESLint</strong> - 代码检查</li>\n<li class=\"\"><strong>Prettier</strong> - 代码格式化</li>\n<li class=\"\"><strong>TypeScript</strong> - TypeScript 支持</li>\n<li class=\"\"><strong>Tailwind CSS</strong> - CSS 支持 (可选)</li>\n</ul>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"端口映射\">端口映射<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E7%AB%AF%E5%8F%A3%E6%98%A0%E5%B0%84\" class=\"hash-link\" aria-label=\"端口映射的直接链接\" title=\"端口映射的直接链接\" translate=\"no\">​</a></h3>\n<p>容器内已映射的端口(docker-compose.yml):</p>\n<ul>\n<li class=\"\"><strong>3000</strong> - Docusaurus 开发服务器</li>\n<li class=\"\"><strong>35729</strong> - 热重载 Live Reload 服务器</li>\n</ul>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"在容器中运行\">在容器中运行<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E5%9C%A8%E5%AE%B9%E5%99%A8%E4%B8%AD%E8%BF%90%E8%A1%8C\" class=\"hash-link\" aria-label=\"在容器中运行的直接链接\" title=\"在容器中运行的直接链接\" translate=\"no\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 启动开发服务器 (热重载)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run start</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 构建生产版本</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run build</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 预览生产构建</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run serve</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 类型检查</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run typecheck</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 清理缓存</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">clear</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"11-常用命令\">11. 常用命令<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#11-%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4\" class=\"hash-link\" aria-label=\"11. 常用命令的直接链接\" title=\"11. 常用命令的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 停止开发环境</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose stop</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 进入容器</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exec</span><span class=\"token plain\"> blog-dev </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">bash</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 重启开发容器</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose restart blog-dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查看日志</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose logs </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-f</span><span class=\"token plain\"> blog-dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 安装新依赖（在容器内执行）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exec</span><span class=\"token plain\"> blog-dev </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> some-package</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 构建生产版本</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exec</span><span class=\"token plain\"> blog-dev </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run build</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果需要重新构建（如修改了 package.json）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose build --no-cache blog-dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose up blog-dev</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 删除指定 container id 的容器</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">rm</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;</span><span class=\"token plain\">container id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 完全清理（删除容器和卷）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose down </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-v</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>生产版本:</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose up blog-prod</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 构建生产镜像</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> build </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--target</span><span class=\"token plain\"> production </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-t</span><span class=\"token plain\"> my-blog:latest </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">.</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 运行预览</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> run </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-p</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">8080</span><span class=\"token plain\">:80 my-blog:latest</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"12-打包镜像迁移环境\">12. 打包镜像迁移环境<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#12-%E6%89%93%E5%8C%85%E9%95%9C%E5%83%8F%E8%BF%81%E7%A7%BB%E7%8E%AF%E5%A2%83\" class=\"hash-link\" aria-label=\"12. 打包镜像迁移环境的直接链接\" title=\"12. 打包镜像迁移环境的直接链接\" translate=\"no\">​</a></h2>\n<p>在旧电脑上保存镜像：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 1. 进入项目目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> /home/vv/桌面/vv/web/FriendlyWeb</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查看所有镜像</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> images</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 2. 提交当前容器为镜像（包含所有安装好的依赖）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> commit blog-dev docusaurus-dev:latest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查看刚刚 commit 的镜像</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> images </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">grep</span><span class=\"token plain\"> docusaurus</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 3. 保存镜像为 tar 文件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> save docusaurus-dev:latest </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-o</span><span class=\"token plain\"> docusaurus-dev.tar</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 4. 压缩文件减小体积</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">gzip</span><span class=\"token plain\"> docusaurus-dev.tar</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 5. 查看文件大小</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ls</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-lh</span><span class=\"token plain\"> docusaurus-dev2.0.tar</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>传输到新电脑上：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 使用 U 盘、scp 或其他方式传输</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 假设传输到新电脑的 /home/vv/ 目录下</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">scp</span><span class=\"token plain\"> docusaurus-dev.tar.gz vv@新电脑IP:/home/vv/</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>在新电脑上加载镜像：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 1. 解压</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">gunzip docusaurus-dev.tar.gz</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 2. 加载镜像</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> load </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-i</span><span class=\"token plain\"> docusaurus-dev.tar</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 3. 确认镜像已加载</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> images </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">grep</span><span class=\"token plain\"> docusaurus-dev</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>在新电脑上运行：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 1. 创建项目目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">mkdir</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-p</span><span class=\"token plain\"> ~/web/FriendlyWeb</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> ~/web/FriendlyWeb</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 2. 从旧电脑复制项目文件（除了 node_modules）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 使用 U 盘或 scp 复制所有项目文件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">scp</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-r</span><span class=\"token plain\"> vv@旧电脑IP:/home/vv/桌面/vv/web/FriendlyWeb/* ./</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">scp</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-r</span><span class=\"token plain\"> vv@旧电脑IP:/home/vv/桌面/vv/web/FriendlyWeb/.* ./ </span><span class=\"token operator file-descriptor important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">2</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\">/dev/null </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">||</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 3. 创建 docker-compose.yml（参考下面的配置）</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>创建 <code>docker-compose.yml</code>：</p>\n<div class=\"language-yaml codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">docker-compose.yml<span style=\"flex:1;text-align:right\">yaml</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-yaml codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">services</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">blog-dev</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">image</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> docusaurus</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">dev</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">latest  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 使用刚才加载的镜像</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">container_name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> blog</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">ports</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"3000:3000\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"35729:35729\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">volumes</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./blog</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/blog</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./docs</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/docs</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./books</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/books</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./src</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/src</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./static</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/static</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./docusaurus.config.ts</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/docusaurus.config.ts</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./sidebars.ts</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/sidebars.ts</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./sidebars</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">docker.js</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/sidebars</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">docker.js</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./tsconfig.json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/tsconfig.json</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> ./package.json</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">/app/package.json</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">environment</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> NODE_ENV=development</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> CHOKIDAR_USEPOLLING=true</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">stdin_open</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">true</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">tty</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">true</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">restart</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> unless</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">stopped</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<p>启动开发环境：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose up </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-d</span><span class=\"token plain\"> blog-dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose logs </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-f</span><span class=\"token plain\"> blog-dev</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"13-安装插件\">13. 安装插件<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#13-%E5%AE%89%E8%A3%85%E6%8F%92%E4%BB%B6\" class=\"hash-link\" aria-label=\"13. 安装插件的直接链接\" title=\"13. 安装插件的直接链接\" translate=\"no\">​</a></h2>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"安装-mermaid-主题\">安装 Mermaid 主题<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E5%AE%89%E8%A3%85-mermaid-%E4%B8%BB%E9%A2%98\" class=\"hash-link\" aria-label=\"安装 Mermaid 主题的直接链接\" title=\"安装 Mermaid 主题的直接链接\" translate=\"no\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exec</span><span class=\"token plain\"> blog-dev </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">bash</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> @docusaurus/theme-mermaid</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exit</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>检查你的 docusaurus.config.ts 中是否启用了 Mermaid：</p>\n<div class=\"language-typescript codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">docusaurus.config.ts<span style=\"flex:1;text-align:right\">typescript</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-typescript codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> config</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Config </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ... 其他配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  markdown</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    mermaid</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  themes</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@docusaurus/theme-mermaid'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> stop blog-dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose up blog-dev</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"安装搜索插件\">安装搜索插件<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E5%AE%89%E8%A3%85%E6%90%9C%E7%B4%A2%E6%8F%92%E4%BB%B6\" class=\"hash-link\" aria-label=\"安装搜索插件的直接链接\" title=\"安装搜索插件的直接链接\" translate=\"no\">​</a></h3>\n<p>链接：<a href=\"https://github.com/easyops-cn/docusaurus-search-local\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://github.com/easyops-cn/docusaurus-search-local</a></p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exec</span><span class=\"token plain\"> blog-dev </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">bash</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--save</span><span class=\"token plain\"> @easyops-cn/docusaurus-search-local</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> list </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--depth</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">grep</span><span class=\"token plain\"> docusaurus-search-local</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exit</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>配置 docusaurus.config.ts：</p>\n<div class=\"language-typescript codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">docusaurus.config.ts<span style=\"flex:1;text-align:right\">typescript</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-typescript codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> config</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Config </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ... 其他配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  themes</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ... 其他主题</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">require</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">resolve</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"@easyops-cn/docusaurus-search-local\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        indexDocs</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 是否索引文档</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        indexBlog</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 是否索引博客</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        indexPages</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 是否索引静态页面</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        language</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"en\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"zh\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 中文文档推荐配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        hashed</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 添加哈希以便长期缓存</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        searchResultLimits</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">8</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 搜索结果数量</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        searchResultContextMaxLength</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">50</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 搜索结果上下文长度</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        searchBarShortcutHint</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 是否显示键盘快捷键提示</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 自定义快捷键 (可选)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// searchBarShortcutKeymap: \"mod+k\",</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"已废弃的方案\">已废弃的方案<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E5%B7%B2%E5%BA%9F%E5%BC%83%E7%9A%84%E6%96%B9%E6%A1%88\" class=\"hash-link\" aria-label=\"已废弃的方案的直接链接\" title=\"已废弃的方案的直接链接\" translate=\"no\">​</a></h3>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> @cmfcmf/docusaurus-search-local</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> uninstall @cmfcmf/docusaurus-search-local</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> list </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--depth</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">grep</span><span class=\"token plain\"> docusaurus-search-local </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 验证是否安装成功</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果需要中文，需要安装 nodejieba</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> nodejieba </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># (已被废弃)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> uninstall nodejieba</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>修改 docusaurus.config.ts：</p>\n<div class=\"language-typescript codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">docusaurus.config.ts<span style=\"flex:1;text-align:right\">typescript</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-typescript codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> config</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Config </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ... 其他配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  plugins</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 有的其他插件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@docusaurus/plugin-content-docs'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ... 书籍插件配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line theme-code-block-highlighted-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line theme-code-block-highlighted-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@cmfcmf/docusaurus-search-local'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line theme-code-block-highlighted-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line theme-code-block-highlighted-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        indexDocs</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 是否索引文档页面</span><span class=\"token plain\"></span><br></span><span class=\"token-line theme-code-block-highlighted-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        indexBlog</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 是否索引博客页面</span><span class=\"token plain\"></span><br></span><span class=\"token-line theme-code-block-highlighted-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        indexPages</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 是否索引静态页面</span><span class=\"token plain\"></span><br></span><span class=\"token-line theme-code-block-highlighted-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        language</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'zh'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">   </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 文档语言，中文用 'zh'</span><span class=\"token plain\"></span><br></span><span class=\"token-line theme-code-block-highlighted-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        maxSearchResults</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">8</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 搜索结果数量</span><span class=\"token plain\"></span><br></span><span class=\"token-line theme-code-block-highlighted-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// Lunr.js 搜索配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line theme-code-block-highlighted-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        lunr</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line theme-code-block-highlighted-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          titleBoost</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">5</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 标题匹配权重</span><span class=\"token plain\"></span><br></span><span class=\"token-line theme-code-block-highlighted-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          contentBoost</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 内容匹配权重</span><span class=\"token plain\"></span><br></span><span class=\"token-line theme-code-block-highlighted-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          tagsBoost</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 标签匹配权重</span><span class=\"token plain\"></span><br></span><span class=\"token-line theme-code-block-highlighted-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line theme-code-block-highlighted-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line theme-code-block-highlighted-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"14-安装-remark-数学插件\">14. 安装 Remark 数学插件<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#14-%E5%AE%89%E8%A3%85-remark-%E6%95%B0%E5%AD%A6%E6%8F%92%E4%BB%B6\" class=\"hash-link\" aria-label=\"14. 安装 Remark 数学插件的直接链接\" title=\"14. 安装 Remark 数学插件的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exec</span><span class=\"token plain\"> blog-dev </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">bash</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> remark-math rehype-katex</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> list remark-math rehype-katex  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 检查是否安装成功</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果需要，重新安装指定版本</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--save</span><span class=\"token plain\"> remark-math@6 rehype-katex@7</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exit</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>然后修改 docusaurus.config.ts：</p>\n<div class=\"language-typescript codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">docusaurus.config.ts<span style=\"flex:1;text-align:right\">typescript</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-typescript codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> remarkMath </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">require</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'remark-math'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> rehypeKatex </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">require</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'rehype-katex'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> config</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Config </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ... 其他配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  presets</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'classic'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        docs</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">         sidebarPath</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">require</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">resolve</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'./sidebars.js'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          editUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'#'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          showLastUpdateTime</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">   </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 显示最后更新时间</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          showLastUpdateAuthor</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 显示最后更新作者</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 添加数学公式插件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          remarkPlugins</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\">remarkMath</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          rehypePlugins</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\">rehypeKatex</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        blog</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          showReadingTime</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          feedOptions</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            type</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'rss'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'atom'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            xslt</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          editUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'#'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          onInlineTags</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'warn'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          onInlineAuthors</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'warn'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          onUntruncatedBlogPosts</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'warn'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          blogSidebarTitle</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'最新文章'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          blogSidebarCount</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">5</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 博客也启用数学公式</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          remarkPlugins</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\">remarkMath</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          rehypePlugins</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\">rehypeKatex</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        theme</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          customCss</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">require</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">resolve</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'./src/css/custom.css'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        sitemap</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          changefreq</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'weekly'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">          priority</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0.5</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"> satisfies Preset</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token plain\">Options</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 添加 KaTeX 样式</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  stylesheets</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      href</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'https://cdn.jsdelivr.net/npm/katex@0.13.24/dist/katex.min.css'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      type</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'text/css'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      integrity</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'sha384-odtC+0UGzzFL/6PNoE8rX/SPcQDXBJ+uRepguP4QkPCm2LBxH3FA3y+fKSiJ+AmM'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      crossorigin</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'anonymous'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  plugins</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@docusaurus/plugin-content-docs'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'docker-book'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        path</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'books/docker_practice'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        routeBasePath</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'books/docker_practice'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        sidebarPath</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">require</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">resolve</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'./sidebars-docker.js'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        editUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'#'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        showLastUpdateTime</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        showLastUpdateAuthor</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 书籍也启用数学公式</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        remarkPlugins</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">require</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'remark-math'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        rehypePlugins</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">require</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'rehype-katex'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@docusaurus/plugin-content-docs'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        id</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'ai-beginner-guide-book'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        path</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'books/ai_beginner_guide'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        routeBasePath</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'books/ai_beginner_guide'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        sidebarPath</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">require</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">.</span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">resolve</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'./sidebars-aibeginner.js'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        editUrl</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'#'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        showLastUpdateTime</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        showLastUpdateAuthor</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        remarkPlugins</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">require</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'remark-math'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        rehypePlugins</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">require</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'rehype-katex'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> stop blog-dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose up blog-dev</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"15-最终打包静态资源步骤\">15. 最终打包静态资源步骤<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#15-%E6%9C%80%E7%BB%88%E6%89%93%E5%8C%85%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E6%AD%A5%E9%AA%A4\" class=\"hash-link\" aria-label=\"15. 最终打包静态资源步骤的直接链接\" title=\"15. 最终打包静态资源步骤的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> /home/vv/桌面/vv/web/FriendlyWeb</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose up blog-dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exec</span><span class=\"token plain\"> blog-dev </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">bash</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 进入容器后</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> /app</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> run build</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exit</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">./copy_build.sh</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 运行一个临时 Nginx 容器来提供 build 目录下的文件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> run </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--rm</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-p</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">8081</span><span class=\"token plain\">:80 </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-v</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token string variable builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">pwd</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/build:/usr/share/nginx/html:ro\"</span><span class=\"token plain\"> nginx:alpine</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 打包 build 目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">tar</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-czf</span><span class=\"token plain\"> friendlyweb-build.tar.gz build/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查看文件大小</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ls</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-lh</span><span class=\"token plain\"> friendlyweb-build.tar.gz</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>命令解释：\n--rm: 容器停止后自动删除，不留垃圾 。\n-p 8081:80: 将宿主机的 8081 端口映射到容器的 80 端口 。访问 <a href=\"http://localhost:8081/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">http://localhost:8081</a> 即可。\n-v \"$(pwd)/build:/usr/share/nginx/html<!-- -->:ro<!-- -->\": 这是核心。它将你当前目录下的 build 文件夹挂载到 Nginx 容器内的默认网站根目录，ro 表示只读，确保容器不会修改你的文件 。\nnginx:alpine: 使用基于 Alpine Linux 的轻量级 Nginx 镜像，下载快，体积小。</p>\n<p>运行后，打开浏览器访问 <a href=\"http://localhost:8081/\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">http://localhost:8081</a> 就能看到网站了。</p>\n<p>打包完成后，静态文件生成在：build/ 目录:</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">文件结构<span style=\"flex:1;text-align:right\">text</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">FriendlyWeb/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── build/                    # 👈 打包后的静态文件在这里</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── index.html            # 首页</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── blog/                 # 博客页面</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── docs/                 # 文档页面</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── books/                # 书籍页面</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   ├── assets/               # 静态资源（CSS、JS等）</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   │   ├── css/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   │   ├── js/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   │   └── images/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">│   └── ...</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── books/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">├── src/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">└── ...</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 进入容器</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose run </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--rm</span><span class=\"token plain\"> blog-dev </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">bash</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 相当于：临时启动一个新容器</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># - 即使 blog-dev 没运行，也会启动新容器</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># - 不继承 ports 配置（不会映射端口）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># - 继承 volumes 配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># - 退出 bash 后容器自动删除（--rm）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 进入容器</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exec</span><span class=\"token plain\"> blog-dev </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">bash</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 相当于：进入正在运行的容器</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># - 容器必须已经运行（docker ps 能看到）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># - 所有端口映射、挂载卷都保持</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># - 退出 bash 不会停止容器</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 执行打包命令</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"16-自定义页面\">16. 自定义页面<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#16-%E8%87%AA%E5%AE%9A%E4%B9%89%E9%A1%B5%E9%9D%A2\" class=\"hash-link\" aria-label=\"16. 自定义页面的直接链接\" title=\"16. 自定义页面的直接链接\" translate=\"no\">​</a></h2>\n<p>安装必要插件：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exec</span><span class=\"token plain\"> blog-dev </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">bash</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> @iconify/react framer-motion tailwindcss@^3 postcss@^8 autoprefixer@^10 @tailwindcss/typography mini-svg-data-uri tailwind-merge copy-text-to-clipboard react-icon-cloud</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-D</span><span class=\"token plain\"> typescript @types/react @types/react-dom @types/node</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 代码高亮</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> prism-react-renderer@^2.4.1</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--save</span><span class=\"token plain\"> prism-react-renderer</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 这个插件自动生效，安装配置后，用户点击网站上的图片就会自动放大显示。</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> docusaurus-plugin-image-zoom  </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 这个插件不会自动生效，需要在代码中显式使用其提供的组件。主要用于优化图片加载性能。</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> @docusaurus/plugin-ideal-image</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exit</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>检查你的 docusaurus.config.ts 中是否启用了 Mermaid：</p>\n<div class=\"language-typescript codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">docusaurus.config.ts<span style=\"flex:1;text-align:right\">typescript</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-typescript codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> config</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Config </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ... 其他配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  markdown</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    mermaid</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  themes</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@docusaurus/theme-mermaid'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> stop blog-dev</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">docker</span><span class=\"token plain\"> compose up blog-dev</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"17-图片插件使用\">17. 图片插件使用<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#17-%E5%9B%BE%E7%89%87%E6%8F%92%E4%BB%B6%E4%BD%BF%E7%94%A8\" class=\"hash-link\" aria-label=\"17. 图片插件使用的直接链接\" title=\"17. 图片插件使用的直接链接\" translate=\"no\">​</a></h2>\n<p>这两个插件一个用于实现图片点击放大功能，另一个用于图片性能优化，我来给你详细说明：</p>\n<hr>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"1-docusaurus-plugin-image-zoom\">1. docusaurus-plugin-image-zoom<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#1-docusaurus-plugin-image-zoom\" class=\"hash-link\" aria-label=\"1. docusaurus-plugin-image-zoom的直接链接\" title=\"1. docusaurus-plugin-image-zoom的直接链接\" translate=\"no\">​</a></h3>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"安装依赖\">安装依赖<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E5%AE%89%E8%A3%85%E4%BE%9D%E8%B5%96\" class=\"hash-link\" aria-label=\"安装依赖的直接链接\" title=\"安装依赖的直接链接\" translate=\"no\">​</a></h4>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> docusaurus-plugin-image-zoom</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"在哪里使用\">在哪里使用<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E5%9C%A8%E5%93%AA%E9%87%8C%E4%BD%BF%E7%94%A8\" class=\"hash-link\" aria-label=\"在哪里使用的直接链接\" title=\"在哪里使用的直接链接\" translate=\"no\">​</a></h4>\n<p>这个插件<strong>自动生效</strong>，安装配置后，用户点击网站上的图片就会自动放大显示。</p>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"配置方法\">配置方法<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95\" class=\"hash-link\" aria-label=\"配置方法的直接链接\" title=\"配置方法的直接链接\" translate=\"no\">​</a></h4>\n<p>在 <code>docusaurus.config.ts</code> 中配置：</p>\n<div class=\"language-typescript codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">docusaurus.config.ts<span style=\"flex:1;text-align:right\">typescript</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-typescript codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> config</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Config </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 在 plugins 数组中添加</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  plugins</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'docusaurus-plugin-image-zoom'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ...其他插件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 在 themeConfig 中添加 zoom 配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  themeConfig</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    zoom</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      selector</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'.markdown :not(em) &gt; img'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 选择哪些图片可缩放</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      background</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        light</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'rgb(255, 255, 255)'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 浅色模式背景</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        dark</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'rgb(50, 50, 50)'</span><span class=\"token plain\">       </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 深色模式背景</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      config</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// medium-zoom 的配置选项</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// margin: 24,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// scrollOffset: 0,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ...其他配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"配置参数说明\">配置参数说明<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E9%85%8D%E7%BD%AE%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E\" class=\"hash-link\" aria-label=\"配置参数说明的直接链接\" title=\"配置参数说明的直接链接\" translate=\"no\">​</a></h4>\n<table><thead><tr><th>参数</th><th>说明</th><th>默认值</th></tr></thead><tbody><tr><td><code>selector</code></td><td>选择哪些图片应用缩放功能</td><td><code>.markdown img</code></td></tr><tr><td><code>background</code></td><td>缩放时的背景颜色</td><td><code>{ light: '#fff', dark: '#222' }</code></td></tr><tr><td><code>config</code></td><td>medium-zoom 库的配置选项</td><td><code>{}</code></td></tr></tbody></table>\n<blockquote>\n<p>📌 这个插件基于 <code>medium-zoom</code> 库实现，你可以在 <a href=\"https://github.com/francoischalifour/medium-zoom#usage\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">medium-zoom 文档</a> 查看更多配置选项。</p>\n</blockquote>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"2-docusaurusplugin-ideal-image\">2. @docusaurus/plugin-ideal-image<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#2-docusaurusplugin-ideal-image\" class=\"hash-link\" aria-label=\"2. @docusaurus/plugin-ideal-image的直接链接\" title=\"2. @docusaurus/plugin-ideal-image的直接链接\" translate=\"no\">​</a></h3>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"安装依赖-1\">安装依赖<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E5%AE%89%E8%A3%85%E4%BE%9D%E8%B5%96-1\" class=\"hash-link\" aria-label=\"安装依赖的直接链接\" title=\"安装依赖的直接链接\" translate=\"no\">​</a></h4>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> @docusaurus/plugin-ideal-image</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"在哪里使用-1\">在哪里使用<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E5%9C%A8%E5%93%AA%E9%87%8C%E4%BD%BF%E7%94%A8-1\" class=\"hash-link\" aria-label=\"在哪里使用的直接链接\" title=\"在哪里使用的直接链接\" translate=\"no\">​</a></h4>\n<p>这个插件<strong>不会自动生效</strong>，需要在代码中显式使用其提供的组件。主要用于优化图片加载性能。</p>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"配置方法-1\">配置方法<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E9%85%8D%E7%BD%AE%E6%96%B9%E6%B3%95-1\" class=\"hash-link\" aria-label=\"配置方法的直接链接\" title=\"配置方法的直接链接\" translate=\"no\">​</a></h4>\n<p>在 <code>docusaurus.config.ts</code> 中配置：</p>\n<div class=\"language-typescript codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">docusaurus.config.ts<span style=\"flex:1;text-align:right\">typescript</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-typescript codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">const</span><span class=\"token plain\"> config</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> Config </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  plugins</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@docusaurus/plugin-ideal-image'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        quality</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">85</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">           </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// JPEG 压缩质量</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        max</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1030</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">             </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 最大图片宽度</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        min</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">640</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">              </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 最小图片宽度</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        steps</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">4</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">              </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 生成图片尺寸的数量</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        disableInDev</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\">   </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 开发模式下是否启用（默认 true 表示禁用）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">      </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// ...其他插件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"使用方法\">使用方法<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95\" class=\"hash-link\" aria-label=\"使用方法的直接链接\" title=\"使用方法的直接链接\" translate=\"no\">​</a></h4>\n<p><strong>在 MDX/Markdown 中</strong>，不能直接使用 <code>![alt](image.png)</code>，需要使用 <code>@theme/IdealImage</code> 组件：</p>\n<div class=\"language-mdx codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">使用 IdealImage<span style=\"flex:1;text-align:right\">mdx</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-mdx codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">import Image from '@theme/IdealImage';</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">import myImage from './path/to/image.png';</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">// 使用 IdealImage 组件</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">&lt;Image img={myImage} /&gt;</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">// 或使用 require</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">&lt;Image img={require('./path/to/image.png')} /&gt;</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<p><strong>在 JSX/TSX 组件中</strong>：</p>\n<div class=\"language-tsx codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">使用 IdealImage<span style=\"flex:1;text-align:right\">tsx</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-tsx codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token imports maybe-class-name\">Image</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'@theme/IdealImage'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">import</span><span class=\"token plain\"> </span><span class=\"token imports\">thumbnail</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">from</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'./img/thumbnail.png'</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">export</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">default</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">function</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">MyComponent</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">div</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">      </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;</span><span class=\"token tag class-name\" style=\"color:hsl(35, 99%, 36%)\">Image</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token tag attr-name\" style=\"color:hsl(35, 99%, 36%)\">img</span><span class=\"token tag script language-javascript script-punctuation punctuation\" style=\"color:hsl(119, 34%, 47%)\">=</span><span class=\"token tag script language-javascript punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token tag script language-javascript\" style=\"color:hsl(5, 74%, 59%)\">thumbnail</span><span class=\"token tag script language-javascript punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">/&gt;</span><span class=\"token plain-text\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain-text\">    </span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&lt;/</span><span class=\"token tag\" style=\"color:hsl(5, 74%, 59%)\">div</span><span class=\"token tag punctuation\" style=\"color:hsl(119, 34%, 47%)\">&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"配置参数说明-1\">配置参数说明<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E9%85%8D%E7%BD%AE%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E-1\" class=\"hash-link\" aria-label=\"配置参数说明的直接链接\" title=\"配置参数说明的直接链接\" translate=\"no\">​</a></h4>\n<table><thead><tr><th>参数</th><th>说明</th><th>默认值</th></tr></thead><tbody><tr><td><code>name</code></td><td>输出文件命名模板</td><td><code>ideal-img/[name].[hash:hex:7].[width].[ext]</code></td></tr><tr><td><code>sizes</code></td><td>指定生成的图片尺寸数组</td><td>原始尺寸</td></tr><tr><td><code>min</code></td><td>最小图片宽度</td><td>-</td></tr><tr><td><code>max</code></td><td>最大图片宽度</td><td>-</td></tr><tr><td><code>steps</code></td><td>min 和 max 之间生成的图片数量</td><td>4</td></tr><tr><td><code>quality</code></td><td>JPEG 压缩质量</td><td>85</td></tr><tr><td><code>disableInDev</code></td><td>开发模式禁用（提升开发体验）</td><td>true</td></tr></tbody></table>\n<h4 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"️-重要注意事项\">⚠️ 重要注意事项<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%EF%B8%8F-%E9%87%8D%E8%A6%81%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9\" class=\"hash-link\" aria-label=\"⚠️ 重要注意事项的直接链接\" title=\"⚠️ 重要注意事项的直接链接\" translate=\"no\">​</a></h4>\n<ol>\n<li class=\"\"><strong>仅支持 PNG 和 JPG 格式</strong></li>\n<li class=\"\"><strong>开发模式下默认不生效</strong>：为了开发体验，开发模式下图片不会进行优化处理。如需调试，设置 <code>disableInDev: false</code></li>\n<li class=\"\"><strong>导入图片类型会改变</strong>：<!-- -->\n<ul>\n<li class=\"\">之前：<code>string</code>（图片路径字符串）</li>\n<li class=\"\">之后：<code>{ preSrc: string, src: SrcImage }</code> 对象</li>\n</ul>\n</li>\n<li class=\"\"><strong>如果使用 pnpm</strong>：需要配置 <code>onlyBuiltDependencies</code> 来确保 sharp 依赖正确安装</li>\n</ol>\n<div class=\"language-json codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">package.json<span style=\"flex:1;text-align:right\">json</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-json codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// package.json</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"pnpm\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token property\" style=\"color:hsl(5, 74%, 59%)\">\"onlyBuiltDependencies\"</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"fsevents\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"两个插件的功能对比\">两个插件的功能对比<a href=\"https://devvv.cn/blog/docsaurus-build-self-site-record#%E4%B8%A4%E4%B8%AA%E6%8F%92%E4%BB%B6%E7%9A%84%E5%8A%9F%E8%83%BD%E5%AF%B9%E6%AF%94\" class=\"hash-link\" aria-label=\"两个插件的功能对比的直接链接\" title=\"两个插件的功能对比的直接链接\" translate=\"no\">​</a></h3>\n<table><thead><tr><th>功能</th><th>image-zoom</th><th>ideal-image</th></tr></thead><tbody><tr><td>图片点击放大</td><td>✅ 主要功能</td><td>❌</td></tr><tr><td>响应式图片（不同屏幕尺寸）</td><td>❌</td><td>✅</td></tr><tr><td>懒加载</td><td>❌</td><td>✅</td></tr><tr><td>低质量占位符</td><td>❌</td><td>✅</td></tr><tr><td>自动 WebP 转换</td><td>❌</td><td>✅</td></tr><tr><td>使用方式</td><td>自动生效</td><td>需要手动使用 <code>&lt;Image&gt;</code> 组件</td></tr></tbody></table>\n<p>两个插件<strong>可以同时使用</strong>，互不冲突。ideal-image 负责优化图片加载性能，image-zoom 负责提供点击放大的交互体验。</p>",
            "url": "https://devvv.cn/blog/docsaurus-build-self-site-record",
            "title": "Docusaurus 搭建个人站点",
            "summary": "Docusaurus 搭建个人站点",
            "date_modified": "2026-03-12T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "Docusaurus",
                "TypeScript‌",
                "React"
            ]
        },
        {
            "id": "https://devvv.cn/blog/install-npm-and-nvm",
            "content_html": "<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"安装\">安装<a href=\"https://devvv.cn/blog/install-npm-and-nvm#%E5%AE%89%E8%A3%85\" class=\"hash-link\" aria-label=\"安装的直接链接\" title=\"安装的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">apt</span><span class=\"token plain\"> update</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">sudo</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">apt</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-y</span><span class=\"token plain\"> nodejs </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-g</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">pnpm</span><span class=\"token plain\"> </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果没权限，先 sudo -i 切换到 root</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 验证安装</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">node</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-v</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-v</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">pnpm</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--version</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"升级\">升级<a href=\"https://devvv.cn/blog/install-npm-and-nvm#%E5%8D%87%E7%BA%A7\" class=\"hash-link\" aria-label=\"升级的直接链接\" title=\"升级的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 升级npm到最新稳定版</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-g</span><span class=\"token plain\"> npm@latest</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 升级到指定的9.6.5+版本</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-g</span><span class=\"token plain\"> npm@9.6.5</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 配置国内镜像</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> config </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">set</span><span class=\"token plain\"> registry https://registry.npmmirror.com</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"nvm\">nvm<a href=\"https://devvv.cn/blog/install-npm-and-nvm#nvm\" class=\"hash-link\" aria-label=\"nvm的直接链接\" title=\"nvm的直接链接\" translate=\"no\">​</a></h2>\n<p>安装 nvm，nvm 是最灵活的 Node.js 版本管理工具，可以轻松安装和切换多个版本：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 安装 nvm</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">curl</span><span class=\"token plain\"> -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">bash</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 重新加载 shell 配置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">source</span><span class=\"token plain\"> ~/.bashrc</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果使用 Zsh，则运行 source ~/.zshrc</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 验证 nvm 安装</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">nvm </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--version</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 安装最新 LTS 版本</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">nvm </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">install</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--lts</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 这将会安装最新的长期支持版本</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 设置为默认版本</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">nvm </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">alias</span><span class=\"token plain\"> default </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">node</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 验证升级结果</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">node</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-v</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">npm</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-v</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>",
            "url": "https://devvv.cn/blog/install-npm-and-nvm",
            "title": "安装 npm 和 nvm",
            "summary": "安装 npm 和 nvm",
            "date_modified": "2026-03-09T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "npm",
                "nvm"
            ]
        },
        {
            "id": "https://devvv.cn/blog/git-command-record-usage",
            "content_html": "<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"查看-git-信息\">查看 git 信息<a href=\"https://devvv.cn/blog/git-command-record-usage#%E6%9F%A5%E7%9C%8B-git-%E4%BF%A1%E6%81%AF\" class=\"hash-link\" aria-label=\"查看 git 信息的直接链接\" title=\"查看 git 信息的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> config </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--global</span><span class=\"token plain\"> user.name</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> config </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--global</span><span class=\"token plain\"> user.email</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"添加-giteecom-公钥\">添加 gitee@com 公钥<a href=\"https://devvv.cn/blog/git-command-record-usage#%E6%B7%BB%E5%8A%A0-giteecom-%E5%85%AC%E9%92%A5\" class=\"hash-link\" aria-label=\"添加 gitee@com 公钥的直接链接\" title=\"添加 gitee@com 公钥的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># -t key 类型</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># -C 注释</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">ssh-keygen </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-t</span><span class=\"token plain\"> ed25519 </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-C</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"Gitee SSH Key\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 然后连按三次回车</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ls</span><span class=\"token plain\"> ~/.ssh/</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 私钥文件 id_ed25519</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 公钥文件 id_ed25519.pub</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 读取公钥文件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">cat</span><span class=\"token plain\"> ~/.ssh/id_ed25519.pub</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 复制整个输出(ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAADIQHTBW8jsHPp+5FlrEdcA5eXRgclBIS+PsVVE3ysGJJ Gitee SSH Key)，添加到 gitee 公钥</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 测试输出</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ssh</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-T</span><span class=\"token plain\"> git@gitee.com</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 输入 yes</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># Warning: Permanently added 'gitee.com' (ED25519) to the list of known hosts.</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># Hi weijun(@weijun233)! You've successfully authenticated, but GITEE.COM does not provide shell access.</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"1查看本地有但远程没有的提交\">1.查看本地有但远程没有的提交<a href=\"https://devvv.cn/blog/git-command-record-usage#1%E6%9F%A5%E7%9C%8B%E6%9C%AC%E5%9C%B0%E6%9C%89%E4%BD%86%E8%BF%9C%E7%A8%8B%E6%B2%A1%E6%9C%89%E7%9A%84%E6%8F%90%E4%BA%A4\" class=\"hash-link\" aria-label=\"1.查看本地有但远程没有的提交的直接链接\" title=\"1.查看本地有但远程没有的提交的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> log origin/main</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">..</span><span class=\"token plain\">HEAD   </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果远程分支是 main</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> log origin/master</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">..</span><span class=\"token plain\">HEAD </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果远程分支是 master</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> log </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--oneline</span><span class=\"token plain\"> </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查看提交历史</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> log </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--oneline</span><span class=\"token plain\"> origin/master</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">..</span><span class=\"token plain\">HEAD </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 简洁显示</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> log </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--stat</span><span class=\"token plain\"> origin/master</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">..</span><span class=\"token plain\">HEAD </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查看未推送提交的详细内容</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> log </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--oneline</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--graph</span><span class=\"token plain\"> origin/master</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">..</span><span class=\"token plain\">HEAD </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 图形化显示</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> log @</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\">u</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">..</span><span class=\"token plain\"> </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查看当前分支对应的远程分支未推送的提交</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> log --name-only </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--oneline</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-3</span><span class=\"token plain\"> </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查看最近三次提交的文件列表</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> log </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--stat</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-3</span><span class=\"token plain\"> </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 更详细的文件列表（含状态）</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>可以将常用命令设置为别名：</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 添加到 ~/.gitconfig</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\">alias</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">unpushed </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> log </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--oneline</span><span class=\"token plain\"> origin/master</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">..</span><span class=\"token plain\">HEAD</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">unpushed-all </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> log origin/master</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">..</span><span class=\"token plain\">HEAD</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>示例输出</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">$ git log --oneline origin/master..HEAD</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">a1b2c3d 修复登录页面样式问题</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">e4f5g6h 添加用户注册功能</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">text</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"2显示未推送到远程的提交\">2.显示未推送到远程的提交<a href=\"https://devvv.cn/blog/git-command-record-usage#2%E6%98%BE%E7%A4%BA%E6%9C%AA%E6%8E%A8%E9%80%81%E5%88%B0%E8%BF%9C%E7%A8%8B%E7%9A%84%E6%8F%90%E4%BA%A4\" class=\"hash-link\" aria-label=\"2.显示未推送到远程的提交的直接链接\" title=\"2.显示未推送到远程的提交的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> cherry </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-v</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> cherry </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-v</span><span class=\"token plain\"> origin/master </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 指定远程分支</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"3显示本地领先远程多少个提交\">3.显示本地领先远程多少个提交<a href=\"https://devvv.cn/blog/git-command-record-usage#3%E6%98%BE%E7%A4%BA%E6%9C%AC%E5%9C%B0%E9%A2%86%E5%85%88%E8%BF%9C%E7%A8%8B%E5%A4%9A%E5%B0%91%E4%B8%AA%E6%8F%90%E4%BA%A4\" class=\"hash-link\" aria-label=\"3.显示本地领先远程多少个提交的直接链接\" title=\"3.显示本地领先远程多少个提交的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> status </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-sb</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 或</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> branch </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-vv</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>这会显示类似 [ahead 2] 的信息，表示有 2 个本地提交未推送。</p>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"4查看未推送的提交差异\">4.查看未推送的提交差异<a href=\"https://devvv.cn/blog/git-command-record-usage#4%E6%9F%A5%E7%9C%8B%E6%9C%AA%E6%8E%A8%E9%80%81%E7%9A%84%E6%8F%90%E4%BA%A4%E5%B7%AE%E5%BC%82\" class=\"hash-link\" aria-label=\"4.查看未推送的提交差异的直接链接\" title=\"4.查看未推送的提交差异的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">diff</span><span class=\"token plain\"> origin/master</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">..</span><span class=\"token plain\">HEAD</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"5强制推送到远程\">5.强制推送到远程<a href=\"https://devvv.cn/blog/git-command-record-usage#5%E5%BC%BA%E5%88%B6%E6%8E%A8%E9%80%81%E5%88%B0%E8%BF%9C%E7%A8%8B\" class=\"hash-link\" aria-label=\"5.强制推送到远程的直接链接\" title=\"5.强制推送到远程的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> push </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--force</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"6备份当前修改\">6.备份当前修改<a href=\"https://devvv.cn/blog/git-command-record-usage#6%E5%A4%87%E4%BB%BD%E5%BD%93%E5%89%8D%E4%BF%AE%E6%94%B9\" class=\"hash-link\" aria-label=\"6.备份当前修改的直接链接\" title=\"6.备份当前修改的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> stash </span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"7重置到远程分支的状态\">7.重置到远程分支的状态<a href=\"https://devvv.cn/blog/git-command-record-usage#7%E9%87%8D%E7%BD%AE%E5%88%B0%E8%BF%9C%E7%A8%8B%E5%88%86%E6%94%AF%E7%9A%84%E7%8A%B6%E6%80%81\" class=\"hash-link\" aria-label=\"7.重置到远程分支的状态的直接链接\" title=\"7.重置到远程分支的状态的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> fetch origin</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> reset </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--hard</span><span class=\"token plain\"> origin/master</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"8查看未推送提交中的文件变化\">8.查看未推送提交中的文件变化<a href=\"https://devvv.cn/blog/git-command-record-usage#8%E6%9F%A5%E7%9C%8B%E6%9C%AA%E6%8E%A8%E9%80%81%E6%8F%90%E4%BA%A4%E4%B8%AD%E7%9A%84%E6%96%87%E4%BB%B6%E5%8F%98%E5%8C%96\" class=\"hash-link\" aria-label=\"8.查看未推送提交中的文件变化的直接链接\" title=\"8.查看未推送提交中的文件变化的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查看所有未推送提交中的文件变化</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">diff</span><span class=\"token plain\"> --name-only origin/master</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">..</span><span class=\"token plain\">HEAD</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 使用git show查看每个提交的文件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> show --name-only HEAD~2</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">..</span><span class=\"token plain\">HEAD </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查看最近三次提交的文件列表</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> log --name-only </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--oneline</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-3</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 更详细的文件列表（含状态）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> log </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--stat</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-3</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 首先确认有多少个未推送的提交</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> status </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-sb</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 输出类似: ## master...origin/master [ahead 5]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查看最近三次未推送提交的文件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> log --name-only </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--oneline</span><span class=\"token plain\"> HEAD~3</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">..</span><span class=\"token plain\">HEAD</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 或者使用相对引用</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> log --name-only </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--oneline</span><span class=\"token plain\"> origin/master</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">..</span><span class=\"token plain\">HEAD </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">head</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-20</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查看前三提交的大概信息</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"9分别查看每个未推送提交的文件\">9.分别查看每个未推送提交的文件<a href=\"https://devvv.cn/blog/git-command-record-usage#9%E5%88%86%E5%88%AB%E6%9F%A5%E7%9C%8B%E6%AF%8F%E4%B8%AA%E6%9C%AA%E6%8E%A8%E9%80%81%E6%8F%90%E4%BA%A4%E7%9A%84%E6%96%87%E4%BB%B6\" class=\"hash-link\" aria-label=\"9.分别查看每个未推送提交的文件的直接链接\" title=\"9.分别查看每个未推送提交的文件的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 列出最近三次提交的哈希值</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> log </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--oneline</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-3</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 分别查看每个提交的文件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> show --name-only HEAD     </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 最新提交的文件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> show --name-only HEAD~1   </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 第二个提交的文件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> show --name-only HEAD~2   </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 第三个提交的文件</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"10舍弃已提交但未push的记录\">10.舍弃已提交但未push的记录<a href=\"https://devvv.cn/blog/git-command-record-usage#10%E8%88%8D%E5%BC%83%E5%B7%B2%E6%8F%90%E4%BA%A4%E4%BD%86%E6%9C%AApush%E7%9A%84%E8%AE%B0%E5%BD%95\" class=\"hash-link\" aria-label=\"10.舍弃已提交但未push的记录的直接链接\" title=\"10.舍弃已提交但未push的记录的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 完全放弃所有未push的commit和更改（⚠️ 危险操作警告）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> fetch </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&amp;&amp;</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> reset </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--hard</span><span class=\"token plain\"> origin/</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> branch --show-current</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># git reset --hard 会永久删除以下内容：</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 1. 所有未push的commit</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 2. 所有未暂存(staged)的更改</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 3. 所有工作区的修改</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 无法用git命令恢复！除非你有stash备份</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 操作前建议备份</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 完全重置到远程分支状态（最彻底）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 方法1：使用 git reset</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> fetch origin                    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 获取远程最新状态</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> reset </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--hard</span><span class=\"token plain\"> origin/master      </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果是 master 分支</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 方法2：使用 git checkout（Git 2.23+ 推荐）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> fetch origin</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> switch </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-f</span><span class=\"token plain\"> master                </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 强制切换到远程状态</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 丢弃最近 N 次提交</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查看要丢弃多少次提交</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> log </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--oneline</span><span class=\"token plain\"> origin/master</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">..</span><span class=\"token plain\">HEAD</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 丢弃最近的3次提交（保留更改在工作区）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> reset </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--soft</span><span class=\"token plain\"> HEAD~3</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 丢弃最近的3次提交（完全丢弃更改）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> reset </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--hard</span><span class=\"token plain\"> HEAD~3</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 重置后检查</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> status          </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 应该显示 \"Your branch is up to date with 'origin/master'\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> log </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--oneline</span><span class=\"token plain\">   </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 应该和远程分支一致</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">diff</span><span class=\"token plain\"> origin/master </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 应该没有差异</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>",
            "url": "https://devvv.cn/blog/git-command-record-usage",
            "title": "Git 常用命令",
            "summary": "git 常用命令",
            "date_modified": "2026-03-04T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "git"
            ]
        },
        {
            "id": "https://devvv.cn/blog/cmake-multi-module-project-configuration",
            "content_html": "<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"第一步创建动态库项目\">第一步：创建动态库项目<a href=\"https://devvv.cn/blog/cmake-multi-module-project-configuration#%E7%AC%AC%E4%B8%80%E6%AD%A5%E5%88%9B%E5%BB%BA%E5%8A%A8%E6%80%81%E5%BA%93%E9%A1%B9%E7%9B%AE\" class=\"hash-link\" aria-label=\"第一步：创建动态库项目的直接链接\" title=\"第一步：创建动态库项目的直接链接\" translate=\"no\">​</a></h3>\n<ul>\n<li class=\"\">打开CLion，在欢迎界面点击 New Project。</li>\n<li class=\"\">在左侧列表中，选择 C++ Library。</li>\n<li class=\"\">为项目起一个名字，例如 MyMath。</li>\n<li class=\"\">在 Language standard 下拉菜单中，选择熟悉的C++标准，例如 C++20。</li>\n<li class=\"\">最关键的一步：在 Library type 下拉菜单中，选择 Shared。这告诉CLion我们将要创建一个动态库。 作为对比，Static对应的是静态库（.a文件） 。</li>\n<li class=\"\">在 Location 一栏，确保项目创建在本地能与远程同步的目录下。CLion的远程模式会自动处理同步。</li>\n<li class=\"\">点击 Create 按钮。</li>\n</ul>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"第二步编写库的代码\">第二步：编写库的代码<a href=\"https://devvv.cn/blog/cmake-multi-module-project-configuration#%E7%AC%AC%E4%BA%8C%E6%AD%A5%E7%BC%96%E5%86%99%E5%BA%93%E7%9A%84%E4%BB%A3%E7%A0%81\" class=\"hash-link\" aria-label=\"第二步：编写库的代码的直接链接\" title=\"第二步：编写库的代码的直接链接\" translate=\"no\">​</a></h3>\n<p>CLion的库模板会生成一个简单的 library.h 和 library.cpp 文件。我们需要对其进行修改，使其成为真正的动态库。</p>\n<p>关键点：符号导出\n在Windows上创建动态库（.dll）时，需要用 __declspec(dllexport) 显式声明要导出的函数、类等，否则外部程序无法使用。而在Linux上，默认所有非静态符号都会被导出。为了编写跨平台的代码，我们通常会使用宏来处理这个差异。</p>\n<p>修改头文件 library.h：\n我们将头文件修改为如下内容，定义一个跨平台的导出宏 MATHLIB_API。</p>\n<div class=\"language-cpp codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">library.h<span style=\"flex:1;text-align:right\">cpp</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-cpp codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// library.h</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token macro property directive-hash\" style=\"color:hsl(5, 74%, 59%)\">#</span><span class=\"token macro property directive keyword\" style=\"color:hsl(301, 63%, 40%)\">ifndef</span><span class=\"token macro property\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token macro property expression\" style=\"color:hsl(5, 74%, 59%)\">MYMATH_LIBRARY_H</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token macro property directive-hash\" style=\"color:hsl(5, 74%, 59%)\">#</span><span class=\"token macro property directive keyword\" style=\"color:hsl(301, 63%, 40%)\">define</span><span class=\"token macro property\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token macro property macro-name\" style=\"color:hsl(5, 74%, 59%)\">MYMATH_LIBRARY_H</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 跨平台导出宏定义</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token macro property directive-hash\" style=\"color:hsl(5, 74%, 59%)\">#</span><span class=\"token macro property directive keyword\" style=\"color:hsl(301, 63%, 40%)\">ifdef</span><span class=\"token macro property\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token macro property expression\" style=\"color:hsl(5, 74%, 59%)\">_WIN32 </span><span class=\"token macro property comment\" style=\"color:hsl(230, 4%, 64%)\">// 如果是Windows平台</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token macro property directive-hash\" style=\"color:hsl(5, 74%, 59%)\">#</span><span class=\"token macro property directive keyword\" style=\"color:hsl(301, 63%, 40%)\">ifdef</span><span class=\"token macro property\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token macro property expression\" style=\"color:hsl(5, 74%, 59%)\">MYMATH_EXPORTS </span><span class=\"token macro property comment\" style=\"color:hsl(230, 4%, 64%)\">// 如果当前正在构建库</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token macro property directive-hash\" style=\"color:hsl(5, 74%, 59%)\">#</span><span class=\"token macro property directive keyword\" style=\"color:hsl(301, 63%, 40%)\">define</span><span class=\"token macro property\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token macro property macro-name\" style=\"color:hsl(5, 74%, 59%)\">MATHLIB_API</span><span class=\"token macro property\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token macro property expression function\" style=\"color:hsl(221, 87%, 60%)\">__declspec</span><span class=\"token macro property expression punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token macro property expression\" style=\"color:hsl(5, 74%, 59%)\">dllexport</span><span class=\"token macro property expression punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token macro property directive-hash\" style=\"color:hsl(5, 74%, 59%)\">#</span><span class=\"token macro property directive keyword\" style=\"color:hsl(301, 63%, 40%)\">else</span><span class=\"token macro property\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token macro property comment\" style=\"color:hsl(230, 4%, 64%)\">// 如果是使用库</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token macro property directive-hash\" style=\"color:hsl(5, 74%, 59%)\">#</span><span class=\"token macro property directive keyword\" style=\"color:hsl(301, 63%, 40%)\">define</span><span class=\"token macro property\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token macro property macro-name\" style=\"color:hsl(5, 74%, 59%)\">MATHLIB_API</span><span class=\"token macro property\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token macro property expression function\" style=\"color:hsl(221, 87%, 60%)\">__declspec</span><span class=\"token macro property expression punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token macro property expression\" style=\"color:hsl(5, 74%, 59%)\">dllimport</span><span class=\"token macro property expression punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token macro property directive-hash\" style=\"color:hsl(5, 74%, 59%)\">#</span><span class=\"token macro property directive keyword\" style=\"color:hsl(301, 63%, 40%)\">endif</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token macro property directive-hash\" style=\"color:hsl(5, 74%, 59%)\">#</span><span class=\"token macro property directive keyword\" style=\"color:hsl(301, 63%, 40%)\">else</span><span class=\"token macro property\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token macro property comment\" style=\"color:hsl(230, 4%, 64%)\">// 如果是Linux/Unix平台</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token macro property directive-hash\" style=\"color:hsl(5, 74%, 59%)\">#</span><span class=\"token macro property directive keyword\" style=\"color:hsl(301, 63%, 40%)\">define</span><span class=\"token macro property\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token macro property macro-name\" style=\"color:hsl(5, 74%, 59%)\">MATHLIB_API</span><span class=\"token macro property\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token macro property comment\" style=\"color:hsl(230, 4%, 64%)\">// 在Linux上，所有符号默认导出，此宏定义为空</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token macro property directive-hash\" style=\"color:hsl(5, 74%, 59%)\">#</span><span class=\"token macro property directive keyword\" style=\"color:hsl(301, 63%, 40%)\">endif</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 使用 MATHLIB_API 宏来修饰需要导出的函数</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 这对于Linux不是必须的，但保持了代码的跨平台一致性</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">extern</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"C\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">MATHLIB_API </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">int</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">add</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">int</span><span class=\"token plain\"> a</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">int</span><span class=\"token plain\"> b</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">MATHLIB_API </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">int</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">subtract</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">int</span><span class=\"token plain\"> a</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">int</span><span class=\"token plain\"> b</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token macro property directive-hash\" style=\"color:hsl(5, 74%, 59%)\">#</span><span class=\"token macro property directive keyword\" style=\"color:hsl(301, 63%, 40%)\">endif</span><span class=\"token macro property\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token macro property comment\" style=\"color:hsl(230, 4%, 64%)\">//MYMATH_LIBRARY_H</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<p>extern \"C\" 是为了防止C++编译器对函数名进行名字改编（name mangling），这样从其他语言（或C++本身）调用这个库时会更容易，函数名也会更清晰。</p>\n<p>修改源文件 library.cpp：\n实现头文件中声明的函数。</p>\n<div class=\"language-cpp codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">library.cpp<span style=\"flex:1;text-align:right\">cpp</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-cpp codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// library.cpp</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token macro property directive-hash\" style=\"color:hsl(5, 74%, 59%)\">#</span><span class=\"token macro property directive keyword\" style=\"color:hsl(301, 63%, 40%)\">include</span><span class=\"token macro property\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token macro property string\" style=\"color:hsl(119, 34%, 47%)\">\"library.h\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token macro property directive-hash\" style=\"color:hsl(5, 74%, 59%)\">#</span><span class=\"token macro property directive keyword\" style=\"color:hsl(301, 63%, 40%)\">include</span><span class=\"token macro property\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token macro property string\" style=\"color:hsl(119, 34%, 47%)\">&lt;iostream&gt;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\">// 定义一个宏，标记当前正在构建库，用于Windows平台</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token macro property directive-hash\" style=\"color:hsl(5, 74%, 59%)\">#</span><span class=\"token macro property directive keyword\" style=\"color:hsl(301, 63%, 40%)\">define</span><span class=\"token macro property\" style=\"color:hsl(5, 74%, 59%)\"> </span><span class=\"token macro property macro-name\" style=\"color:hsl(5, 74%, 59%)\">MYMATH_EXPORTS</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">int</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">add</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">int</span><span class=\"token plain\"> a</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">int</span><span class=\"token plain\"> b</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">std</span><span class=\"token double-colon punctuation\" style=\"color:hsl(119, 34%, 47%)\">::</span><span class=\"token plain\">cout </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;&lt;</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"Calling add function from dynamic library.\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;&lt;</span><span class=\"token plain\"> std</span><span class=\"token double-colon punctuation\" style=\"color:hsl(119, 34%, 47%)\">::</span><span class=\"token plain\">endl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> a </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">+</span><span class=\"token plain\"> b</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">int</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">subtract</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">int</span><span class=\"token plain\"> a</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">int</span><span class=\"token plain\"> b</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">std</span><span class=\"token double-colon punctuation\" style=\"color:hsl(119, 34%, 47%)\">::</span><span class=\"token plain\">cout </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;&lt;</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"Calling subtract function from dynamic library.\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&lt;&lt;</span><span class=\"token plain\"> std</span><span class=\"token double-colon punctuation\" style=\"color:hsl(119, 34%, 47%)\">::</span><span class=\"token plain\">endl</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">return</span><span class=\"token plain\"> a </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">-</span><span class=\"token plain\"> b</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"第三步编译生成动态库\">第三步：编译生成动态库<a href=\"https://devvv.cn/blog/cmake-multi-module-project-configuration#%E7%AC%AC%E4%B8%89%E6%AD%A5%E7%BC%96%E8%AF%91%E7%94%9F%E6%88%90%E5%8A%A8%E6%80%81%E5%BA%93\" class=\"hash-link\" aria-label=\"第三步：编译生成动态库的直接链接\" title=\"第三步：编译生成动态库的直接链接\" translate=\"no\">​</a></h3>\n<ul>\n<li class=\"\">在CLion的右上角，确保当前配置选择的是远程工具链（例如 Remote 或 WSL）。</li>\n<li class=\"\">点击 Build 菜单，然后选择 Build Project（或者直接点击 hammer 图标）。CLion会通过SSH在远程Ubuntu虚拟机上执行编译命令。</li>\n<li class=\"\">编译完成后，在屏幕下方的 Messages 窗口可以看到 Build Finished 的提示。</li>\n<li class=\"\">打开 File -&gt; Project Structure (或者直接在左侧 Project 视图里找到 cmake-build-debug-remote 这样的构建目录，具体名称取决于远程配置)。</li>\n<li class=\"\">在该目录下，应该能找到一个名为 libmymath.so 的文件，这就是我们编译好的动态库。</li>\n</ul>\n<p>这里做了子模块处理：</p>\n<ul>\n<li class=\"\">编译单个模块：选择对应的模块名，点击Build按钮</li>\n<li class=\"\">编译所有模块：Build → Build Project</li>\n</ul>\n<p>编译完成后，在cmake-build-debug/lib目录下会生成：</p>\n<div class=\"language-text codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">lib目录结构<span style=\"flex:1;text-align:right\">text</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-text codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">liblib_test.so          → 紫色图标（软链接）→ 指向 liblib_test.so.1</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">liblib_test.so.1        → 紫色图标（软链接）→ 指向 liblib_test.so.1.0.0  </span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">liblib_test.so.1.0.0    → 普通文件图标 → 真正的动态库文件</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<p>编译器链接名: liblib_test.so</p>\n<ul>\n<li class=\"\">编译时使用的名字（不带版本号）</li>\n<li class=\"\">链接器（ld）在编译程序时找这个名字</li>\n<li class=\"\">通常指向最新的主版本</li>\n</ul>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"第四步新建测试项目\">第四步：新建测试项目<a href=\"https://devvv.cn/blog/cmake-multi-module-project-configuration#%E7%AC%AC%E5%9B%9B%E6%AD%A5%E6%96%B0%E5%BB%BA%E6%B5%8B%E8%AF%95%E9%A1%B9%E7%9B%AE\" class=\"hash-link\" aria-label=\"第四步：新建测试项目的直接链接\" title=\"第四步：新建测试项目的直接链接\" translate=\"no\">​</a></h3>\n<p>先执行:</p>\n<div class=\"language-bash codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-bash codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">./build_and_install.sh </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-m</span><span class=\"token plain\"> lib_test</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">bash</span></div></div></div>\n<p>然后打开测试项目 <a href=\"https://devvv.cn/assets/files/TestSoDemo%E6%B5%8B%E8%AF%95%E5%8A%A8%E6%80%81%E5%BA%93%E7%9A%84%E5%BC%95%E7%94%A8-ce60344a1a110caed819e5d87fdbdcf8.rar\" target=\"_blank\" class=\"\">TestSoDemo测试动态库的引用.rar</a> 运行即可。</p>\n<div class=\"language-shell codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">build_and_install.sh<span style=\"flex:1;text-align:right\">shell</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-shell codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token shebang important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">#!/bin/bash</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 自动编译当前模块并安装动态库到指定目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 编译 lib_test 模块: ./build_and_install.sh -m lib_test</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 颜色定义，让输出更美观</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">RED</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'\\033[0;31m'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">GREEN</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'\\033[0;32m'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">YELLOW</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'\\033[1;33m'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">BLUE</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'\\033[0;34m'</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">NC</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">'\\033[0m'</span><span class=\"token plain\"> </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># No Color</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 目标安装目录，so 动态库存放目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">INSTALL_DIR</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"/home/vv/cpp/lib\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 当前目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">CURRENT_DIR</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">pwd</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">PROJECT_ROOT</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">git</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> rev-parse --show-toplevel </span><span class=\"token variable operator file-descriptor important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">2</span><span class=\"token variable operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">/dev/null </span><span class=\"token variable operator\" style=\"color:hsl(221, 87%, 60%)\">||</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> $CURRENT_DIR</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 显示帮助信息</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function-name function\" style=\"color:hsl(221, 87%, 60%)\">show_help</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BLUE}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">用法:</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$0</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> [选项] [模块名]\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${YELLOW}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">选项:</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"  -h, --help     显示此帮助信息\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"  -a, --all      编译并安装所有模块\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"  -c, --clean    编译前先清理\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"  -b, --build-dir 指定构建目录 (默认: ./build)\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"  -m, --module    指定模块名 (可选)\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${YELLOW}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">示例:</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"  </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$0</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">                      # 编译当前目录下的模块\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"  </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$0</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> -c module1           # 清理并编译module1\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"  </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$0</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> -a                   # 编译所有模块\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"  </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$0</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> -b ~/mybuild module2 # 指定构建目录\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 创建安装目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function-name function\" style=\"color:hsl(221, 87%, 60%)\">create_install_dir</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">!</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-d</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$INSTALL_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BLUE}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">创建安装目录: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${INSTALL_DIR}</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">mkdir</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-p</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$INSTALL_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$?</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-ne</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${RED}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">错误: 无法创建安装目录</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exit</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查找CMakeLists.txt</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function-name function\" style=\"color:hsl(221, 87%, 60%)\">find_cmakelists</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">search_dir</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$1</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果在模块目录，检查当前目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-f</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$search_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/CMakeLists.txt\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$search_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 向上查找直到找到CMakeLists.txt</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">current</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$search_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">while</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$current</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">!=</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"/\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">do</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-f</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$current</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/CMakeLists.txt\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$current</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">current</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">dirname</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$current</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">done</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 获取模块名（从目录名或CMakeLists.txt）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function-name function\" style=\"color:hsl(221, 87%, 60%)\">get_module_name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">module_dir</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$1</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果指定了模块名，直接使用</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-n</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$MODULE_NAME</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$MODULE_NAME</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 否则使用目录名作为模块名</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">basename</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_dir</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 编译模块</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function-name function\" style=\"color:hsl(221, 87%, 60%)\">build_module</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">module_dir</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$1</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">module_name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">get_module_name </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_dir</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string entity\" style=\"color:hsl(230, 8%, 24%)\">\\n</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${GREEN}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">========== 开始编译模块: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${module_name}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> ==========</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 进入模块目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">||</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${RED}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">错误: 无法进入目录 </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${module_dir}</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 设置构建目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">build_dir</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BUILD_DIR</span><span class=\"token string variable operator\" style=\"color:hsl(221, 87%, 60%)\">:-</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_dir</span><span class=\"token string variable operator\" style=\"color:hsl(221, 87%, 60%)\">/</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">build}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果需要清理</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$CLEAN_BUILD</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${YELLOW}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">清理构建目录: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${build_dir}</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">rm</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-rf</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$build_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 创建构建目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">mkdir</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-p</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$build_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$build_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">||</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${RED}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">错误: 无法进入构建目录</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 运行CMake</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BLUE}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">配置CMake...</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    cmake </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">..</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-DCMAKE_BUILD_TYPE</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">Release</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$?</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-ne</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${RED}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">CMake配置失败</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 编译</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BLUE}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">编译中...</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">make</span><span class=\"token plain\"> -j</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">nproc</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$?</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-ne</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${RED}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">编译失败</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${GREEN}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">编译完成</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查找真正的动态库文件（带完整版本号的）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function-name function\" style=\"color:hsl(221, 87%, 60%)\">find_real_so_file</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">build_dir</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$1</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">module_name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$2</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 在构建目录的lib子目录或当前目录查找</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">search_dirs</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$build_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/lib\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$build_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$build_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/src\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">for</span><span class=\"token plain\"> </span><span class=\"token for-or-select variable\" style=\"color:hsl(221, 87%, 60%)\">dir</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">in</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${search_dirs</span><span class=\"token string variable punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token string variable punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">do</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-d</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查找带完整版本号的.so文件（如 libxxx.so.X.Y.Z）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 使用find命令找到真正的文件（不是软链接）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">so_file</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">find</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$dir</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-maxdepth</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-type</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> f </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-name</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"lib</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">${module_name}</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">.so.*.*.*\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">head</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-1</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-n</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$so_file</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$so_file</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果没有找到带三个版本号的，找带一个版本号的</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">so_file</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">find</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$dir</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-maxdepth</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-type</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> f </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-name</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"lib</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">${module_name}</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">.so.*\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable operator\" style=\"color:hsl(221, 87%, 60%)\">!</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-name</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"*.so\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">head</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-1</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-n</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$so_file</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$so_file</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">done</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 创建软链接（如果不存在或不正确）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function-name function\" style=\"color:hsl(221, 87%, 60%)\">create_symlink_if_needed</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">target</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$1</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">link_name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$2</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">link_path</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$INSTALL_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$link_name</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果软链接不存在，创建它</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">!</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-L</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$link_path</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ln</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-s</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$target</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$link_path</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${GREEN}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">✓ 创建软链接: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${link_name}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> -&gt; </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${target}</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果软链接存在但指向错误，更新它</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">current_target</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">readlink </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$link_path</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$current_target</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">!=</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$target</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ln</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-sf</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$target</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$link_path</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${YELLOW}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">✓ 更新软链接: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${link_name}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> -&gt; </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${target}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> (原指向: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${current_target}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 拷贝动态库到安装目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function-name function\" style=\"color:hsl(221, 87%, 60%)\">install_library</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">module_dir</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$1</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">module_name</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">get_module_name </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_dir</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">build_dir</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BUILD_DIR</span><span class=\"token string variable operator\" style=\"color:hsl(221, 87%, 60%)\">:-</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_dir</span><span class=\"token string variable operator\" style=\"color:hsl(221, 87%, 60%)\">/</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">build}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string entity\" style=\"color:hsl(230, 8%, 24%)\">\\n</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BLUE}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">安装模块: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${module_name}</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查找真正的.so文件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">so_file</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">find_real_so_file </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$build_dir</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_name</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-z</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$so_file</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${RED}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">错误: 在构建目录中找不到 </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${module_name}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> 的动态库文件</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${YELLOW}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">查找路径: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${build_dir}</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${GREEN}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">找到库文件: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${so_file}</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 获取文件名和路径信息</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">so_filename</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">basename</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$so_file</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">so_dir</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">dirname</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$so_file</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">target_file</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$INSTALL_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$so_filename</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">lib_basename</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$so_filename</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">cut</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> -d</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">'.'</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-f1</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如: liblib_test</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">major_version</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$so_filename</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">cut</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> -d</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">'.'</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-f3</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如: 1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 拷贝真正的库文件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BLUE}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">拷贝真正的库文件到: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${target_file}</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">cp</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$so_file</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$target_file</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$?</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-eq</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${GREEN}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">✓ 安装成功: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${so_filename}</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 进入安装目录创建软链接</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$INSTALL_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">||</span><span class=\"token plain\"> </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 创建主版本软链接 (libxxx.so.1)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-n</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$major_version</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            create_symlink_if_needed </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$so_filename</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${lib_basename}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">.so.</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${major_version}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 创建编译器软链接 (libxxx.so)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        create_symlink_if_needed </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$so_filename</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${lib_basename}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">.so\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 显示最终结果</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string entity\" style=\"color:hsl(230, 8%, 24%)\">\\n</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BLUE}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">安装目录内容:</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ls</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-l</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${lib_basename}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\">*</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 返回原目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">cd</span><span class=\"token plain\"> - </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> /dev/null</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># ========== 新增：头文件拷贝部分 ==========</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string entity\" style=\"color:hsl(230, 8%, 24%)\">\\n</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BLUE}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">处理头文件...</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 定义头文件安装目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">INCLUDE_INSTALL_DIR</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"/home/vv/cpp/include\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 创建头文件安装目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">mkdir</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-p</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$INCLUDE_INSTALL_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string entity\" style=\"color:hsl(230, 8%, 24%)\">\\n</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">当前路径: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${module_dir}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">...</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查找模块中的头文件目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">possible_include_dirs</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_name</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/include\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">header_copied</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">false</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">for</span><span class=\"token plain\"> </span><span class=\"token for-or-select variable\" style=\"color:hsl(221, 87%, 60%)\">include_dir</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">in</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${possible_include_dirs</span><span class=\"token string variable punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token string variable punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">do</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-d</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$include_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BLUE}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">找到头文件目录: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${include_dir}</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 创建模块专用的头文件子目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">module_include_dir</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$INCLUDE_INSTALL_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_name</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">mkdir</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-p</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_include_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 拷贝所有.h文件到模块子目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BLUE}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">拷贝头文件到: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${module_include_dir}</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 使用rsync或cp拷贝</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">command</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-v</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">rsync</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&amp;&gt;</span><span class=\"token plain\"> /dev/null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">rsync</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-av</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--include</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"*/\"</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--include</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"*.h\"</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--include</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"*.hpp\"</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">--exclude</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"*\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">\\</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$include_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/\"</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_include_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">else</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果没有rsync，用find+cp</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">find</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$include_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-name</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"*.h\"</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-o</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-name</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"*.hpp\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">while</span><span class=\"token plain\"> </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">read</span><span class=\"token plain\"> header</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">do</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 保持相对路径结构</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">rel_path</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${header</span><span class=\"token string variable operator\" style=\"color:hsl(221, 87%, 60%)\">#</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$include_dir</span><span class=\"token string variable operator\" style=\"color:hsl(221, 87%, 60%)\">/</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">target_path</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_include_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$rel_path</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">target_dir</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">dirname</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$target_path</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">mkdir</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-p</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$target_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">cp</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$header</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$target_path</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"  Copied: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$rel_path</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">done</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 统计拷贝的文件数</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">file_count</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">find</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_include_dir</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-name</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"*.h\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-o</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-name</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"*.hpp\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">wc</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-l</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$file_count</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-gt</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${GREEN}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">✓ 已安装 </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${file_count}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> 个头文件到 </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${module_include_dir}</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                    </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">header_copied</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">true</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">else</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${YELLOW}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">警告: 在 </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${include_dir}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> 中没有找到头文件</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">rmdir</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_include_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token operator file-descriptor important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">2</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\">/dev/null</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">break</span><span class=\"token plain\">  </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 找到第一个有效目录后就退出</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">done</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果没有找到标准目录，尝试在源码目录中查找头文件</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$header_copied</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">false</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${YELLOW}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">未找到标准头文件目录，尝试在源码中查找...</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">src_dirs</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/src\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">for</span><span class=\"token plain\"> </span><span class=\"token for-or-select variable\" style=\"color:hsl(221, 87%, 60%)\">src_dir</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">in</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${src_dirs</span><span class=\"token string variable punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">@</span><span class=\"token string variable punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">do</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-d</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$src_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">found_headers</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">find</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$src_dir</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-maxdepth</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-name</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"*.h\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-o</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-name</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"*.hpp\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">head</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-1</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-n</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$found_headers</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BLUE}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">在 </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${src_dir}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> 中找到头文件</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">module_include_dir</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$INCLUDE_INSTALL_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_name</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">mkdir</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-p</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_include_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">find</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$src_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-maxdepth</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-name</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"*.h\"</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-o</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-name</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"*.hpp\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">while</span><span class=\"token plain\"> </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">read</span><span class=\"token plain\"> header</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">do</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">cp</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$header</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_include_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"  Copied: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token string variable function\" style=\"color:hsl(221, 87%, 60%)\">basename</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token string variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$header</span><span class=\"token string variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">done</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">file_count</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">find</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_include_dir</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-name</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"*.h\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-o</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-name</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"*.hpp\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">wc</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-l</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${GREEN}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">✓ 已安装 </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${file_count}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> 个头文件到 </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${module_include_dir}</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">header_copied</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">true</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">break</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">done</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$header_copied</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${GREEN}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">✓ 头文件安装完成</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 创建模块的版本信息文件（可选）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"Module: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_name</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$INCLUDE_INSTALL_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_name</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/version.txt\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"Installed: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token string variable function\" style=\"color:hsl(221, 87%, 60%)\">date</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;&gt;</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$INCLUDE_INSTALL_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_name</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/version.txt\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"Library: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$so_filename</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;&gt;</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$INCLUDE_INSTALL_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_name</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/version.txt\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">else</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${YELLOW}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">警告: 未找到任何头文件</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 显示最终的目录结构</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string entity\" style=\"color:hsl(230, 8%, 24%)\">\\n</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BLUE}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">安装目录结构:</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"库文件目录 (</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$INSTALL_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">):\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ls</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-lh</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$INSTALL_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">grep</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_name</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"头文件目录 (</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$INCLUDE_INSTALL_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_name</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">):\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-d</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$INCLUDE_INSTALL_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_name</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">ls</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-lh</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$INCLUDE_INSTALL_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">/</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_name</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 可选：运行ldconfig更新缓存（需要sudo）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token string variable function\" style=\"color:hsl(221, 87%, 60%)\">id</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token string variable parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-u</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"0\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            ldconfig</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${GREEN}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">已更新动态链接器缓存</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">else</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${YELLOW}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">提示: 如需更新系统缓存，请运行: sudo ldconfig</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">else</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${RED}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">✗ 安装失败</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 编译并安装单个模块</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function-name function\" style=\"color:hsl(221, 87%, 60%)\">process_module</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">module_dir</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$1</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 编译</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    build_module </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$?</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-ne</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 安装</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    install_library </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">return</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$?</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查找所有模块</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function-name function\" style=\"color:hsl(221, 87%, 60%)\">find_all_modules</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">local</span><span class=\"token plain\"> </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">root_dir</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$1</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查找包含CMakeLists.txt且add_library的目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">find</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$root_dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-maxdepth</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">2</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-name</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"CMakeLists.txt\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">while</span><span class=\"token plain\"> </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">read</span><span class=\"token plain\"> cmake_file</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">do</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">dir</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable function\" style=\"color:hsl(221, 87%, 60%)\">dirname</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\"> </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$cmake_file</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 检查是否包含SHARED或add_library</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token function\" style=\"color:hsl(221, 87%, 60%)\">grep</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-q</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"add_library.*SHARED\"</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$cmake_file</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token operator file-descriptor important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">2</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">&gt;</span><span class=\"token plain\">/dev/null</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$dir</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">done</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 主函数</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token function-name function\" style=\"color:hsl(221, 87%, 60%)\">main</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">(</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">{</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 解析命令行参数</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">BUILD_ALL</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">false</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">CLEAN_BUILD</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">false</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">MODULE_NAME</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">BUILD_DIR</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">while</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$#</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-gt</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">do</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">case</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$1</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">in</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            -h</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\">--help</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                show_help</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exit</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            -a</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\">--all</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">BUILD_ALL</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">true</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">shift</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            -c</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\">--clean</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">CLEAN_BUILD</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\">true</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">shift</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            -b</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\">--build-dir</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">BUILD_DIR</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$2</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">shift</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">2</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            -m</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">|</span><span class=\"token plain\">--module</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">MODULE_NAME</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$2</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">shift</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">2</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            -*</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${RED}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">错误: 未知选项 </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$1</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                show_help</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exit</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            *</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 如果还有参数，当作模块名</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-z</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$MODULE_NAME</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                    </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">MODULE_NAME</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$1</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">else</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${RED}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">错误: 多余的参数 </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$1</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                    show_help</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exit</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">shift</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">esac</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">done</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 创建安装目录</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    create_install_dir</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${GREEN}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">========================================</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${GREEN}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">自动编译安装脚本</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${GREEN}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">========================================</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BLUE}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">安装目录: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${INSTALL_DIR}</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BLUE}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">当前目录: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${CURRENT_DIR}</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查找CMakeLists.txt所在位置</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">CMAKE_DIR</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">find_cmakelists </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$CURRENT_DIR</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$BUILD_ALL</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token plain\"> </span><span class=\"token boolean\" style=\"color:hsl(35, 99%, 36%)\">true</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 编译所有模块</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BLUE}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">模式: 编译所有模块</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-z</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$CMAKE_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${RED}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">错误: 找不到CMakeLists.txt</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exit</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 查找所有模块</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">modules</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$(</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">find_all_modules </span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable string variable\" style=\"color:hsl(221, 87%, 60%)\">$CMAKE_DIR</span><span class=\"token variable string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">)</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-z</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$modules</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${YELLOW}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">警告: 未找到任何模块</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exit</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">success_count</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token assign-left variable\" style=\"color:hsl(221, 87%, 60%)\">fail_count</span><span class=\"token operator\" style=\"color:hsl(221, 87%, 60%)\">=</span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">0</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">for</span><span class=\"token plain\"> </span><span class=\"token for-or-select variable\" style=\"color:hsl(221, 87%, 60%)\">module</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">in</span><span class=\"token plain\"> </span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">$modules</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">do</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string entity\" style=\"color:hsl(230, 8%, 24%)\">\\n</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BLUE}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">处理模块: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${module}</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> process_module </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$module</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token variable punctuation\" style=\"color:hsl(119, 34%, 47%)\">((</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">success_count</span><span class=\"token variable operator\" style=\"color:hsl(221, 87%, 60%)\">++</span><span class=\"token variable punctuation\" style=\"color:hsl(119, 34%, 47%)\">))</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">else</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">                </span><span class=\"token variable punctuation\" style=\"color:hsl(119, 34%, 47%)\">((</span><span class=\"token variable\" style=\"color:hsl(221, 87%, 60%)\">fail_count</span><span class=\"token variable operator\" style=\"color:hsl(221, 87%, 60%)\">++</span><span class=\"token variable punctuation\" style=\"color:hsl(119, 34%, 47%)\">))</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">done</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string entity\" style=\"color:hsl(230, 8%, 24%)\">\\n</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${GREEN}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">========================================</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${GREEN}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">编译安装完成: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${success_count}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> 成功, </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${fail_count}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\"> 失败</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">else</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 编译单个模块（当前目录）</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${BLUE}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">模式: 编译当前模块</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">if</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-z</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$CMAKE_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">;</span><span class=\"token plain\"> </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">then</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${RED}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">错误: 当前目录不在CMake项目中</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">            </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">exit</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">        process_module </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$CMAKE_DIR</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token keyword\" style=\"color:hsl(301, 63%, 40%)\">fi</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string entity\" style=\"color:hsl(230, 8%, 24%)\">\\n</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${GREEN}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">库文件已安装到: </span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${INSTALL_DIR}</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token parameter variable\" style=\"color:hsl(221, 87%, 60%)\">-e</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${YELLOW}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">如需使用这些库，请在CMakeLists.txt中添加:</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${NC}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"  link_directories(</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${INSTALL_DIR}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">)\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token builtin class-name\" style=\"color:hsl(35, 99%, 36%)\">echo</span><span class=\"token plain\"> </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"  或设置环境变量: export LD_LIBRARY_PATH=</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">${INSTALL_DIR}</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">:\\</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$LD_LIBRARY_PATH</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">}</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\" style=\"display:inline-block\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token comment\" style=\"color:hsl(230, 4%, 64%)\"># 运行主函数</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">main </span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><span class=\"token string variable\" style=\"color:hsl(221, 87%, 60%)\">$@</span><span class=\"token string\" style=\"color:hsl(119, 34%, 47%)\">\"</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>",
            "url": "https://devvv.cn/blog/cmake-multi-module-project-configuration",
            "title": "CMake 多模块项目配置",
            "summary": "CMake 多模块项目配置",
            "date_modified": "2026-03-02T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "CMake",
                "c++"
            ]
        },
        {
            "id": "https://devvv.cn/blog/android-studio-proxy-setting",
            "content_html": "<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"取消代理\">取消代理<a href=\"https://devvv.cn/blog/android-studio-proxy-setting#%E5%8F%96%E6%B6%88%E4%BB%A3%E7%90%86\" class=\"hash-link\" aria-label=\"取消代理的直接链接\" title=\"取消代理的直接链接\" translate=\"no\">​</a></h2>\n<p><code>Settings -&gt; Appearance &amp; Behavior -&gt; System Settings -&gt; HTTP Proxy -&gt; No Proxy</code></p>\n<p>已经通过上述设置取消了代理，但是还是走的代理：</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"no_proxy.png\" src=\"https://devvv.cn/assets/images/no_proxy-16603ba232b96149b1894e841916cec8.png\" width=\"1375\" height=\"895\" class=\"img_m9Pm\"></p>\n<p>打开 <code>GRADLE_USER_HOME/gradle.properties</code> 文件，将代理设置取消：</p>\n<p><code>GRADLE_USER_HOME</code> 路径：</p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"gradle_user_home.png\" src=\"https://devvv.cn/assets/images/gradle_user_home-7539397fc46c66854ad0c27c873c7921.png\" width=\"916\" height=\"708\" class=\"img_m9Pm\"></p>\n<p><img decoding=\"async\" loading=\"lazy\" alt=\"全局配置文件\" src=\"https://devvv.cn/assets/images/global_config_file-ad9e2ecdad3112a651893d888c075c9b.png\" width=\"640\" height=\"509\" class=\"img_m9Pm\"></p>\n<p>找到并删除：</p>\n<div class=\"language-properties codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockTitle_P25_\">gradle.properties<span style=\"flex:1;text-align:right\">properties</span></div><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-properties codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">systemProp.http.proxyHost=127.0.0.1</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">systemProp.http.proxyPassword=</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">systemProp.http.proxyPort=10810</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">systemProp.https.proxyHost=127.0.0.1</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">systemProp.https.proxyPassword=</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">systemProp.https.proxyPort=10810</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div></div></div></div>\n<p>删除后，重启 <code>Android Studio</code>，问题解决。</p>",
            "url": "https://devvv.cn/blog/android-studio-proxy-setting",
            "title": "Android Studio 设置代理后，再取消，仍然走代理的解决方法",
            "summary": "Android Studio 设置代理后，再取消，仍然走代理的解决方法",
            "date_modified": "2026-02-28T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "Android",
                "Android Studio",
                "Proxy",
                "代理"
            ]
        },
        {
            "id": "https://devvv.cn/blog/android-studio-download-record",
            "content_html": "<p>windows：</p>\n<p><a href=\"https://dl.google.com/dl/android/studio/ide-zips/2022.3.1.20/android-studio-2022.3.1.20-windows.zip\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://dl.google.com/dl/android/studio/ide-zips/2022.3.1.20/android-studio-2022.3.1.20-windows.zip</a></p>\n<p><a href=\"https://dl.google.com/dl/android/studio/ide-zips/2024.3.2.15/android-studio-2024.3.2.15-windows.zip\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://dl.google.com/dl/android/studio/ide-zips/2024.3.2.15/android-studio-2024.3.2.15-windows.zip</a></p>\n<p><a href=\"https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2025.1.2.11/android-studio-2025.1.2.11-windows.zip\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2025.1.2.11/android-studio-2025.1.2.11-windows.zip</a></p>\n<p><a href=\"https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2025.3.2.6/android-studio-panda2-windows.zip\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2025.3.2.6/android-studio-panda2-windows.zip</a></p>\n<p>linux：</p>\n<p><a href=\"https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2025.1.2.11/android-studio-2025.1.2.11-linux.tar.gz\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2025.1.2.11/android-studio-2025.1.2.11-linux.tar.gz</a></p>\n<p><a href=\"https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2025.3.2.6/android-studio-panda2-linux.tar.gz\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2025.3.2.6/android-studio-panda2-linux.tar.gz</a></p>\n<p>历史版本归档：</p>\n<p><a href=\"https://developer.android.google.cn/studio/archive\" target=\"_blank\" rel=\"noopener noreferrer\" class=\"\">https://developer.android.google.cn/studio/archive</a></p>",
            "url": "https://devvv.cn/blog/android-studio-download-record",
            "title": "android studio 下载记录",
            "summary": "Android Studio 下载的记录",
            "date_modified": "2026-02-25T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "Android",
                "Android Studio"
            ]
        },
        {
            "id": "https://devvv.cn/blog/testBlog",
            "content_html": "<p>这些属性是 Docusaurus 博客文章的 <strong>Front Matter</strong>（前置元数据），用于定义文章的元信息和控制页面行为。下面是每个属性的作用及常见扩展属性。</p>\n<hr>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"已给出属性的作用\">已给出属性的作用<a href=\"https://devvv.cn/blog/testBlog#%E5%B7%B2%E7%BB%99%E5%87%BA%E5%B1%9E%E6%80%A7%E7%9A%84%E4%BD%9C%E7%94%A8\" class=\"hash-link\" aria-label=\"已给出属性的作用的直接链接\" title=\"已给出属性的作用的直接链接\" translate=\"no\">​</a></h2>\n<table><thead><tr><th>属性</th><th>作用</th></tr></thead><tbody><tr><td><code>slug</code></td><td>自定义文章 URL 路径（默认为文件名）。例如 <code>slug: /my-post</code> 则文章访问地址为 <code>/my-post</code>。</td></tr><tr><td><code>title</code></td><td>文章标题，显示在页面和列表中。</td></tr><tr><td><code>date</code></td><td>文章发布日期，格式通常为 <code>YYYY-MM-DD</code>，影响排序和归档。</td></tr><tr><td><code>authors</code></td><td>作者，可以是字符串（作者名）或对象数组（包含 <code>name</code>, <code>title</code>, <code>url</code>, <code>imageURL</code> 等）。</td></tr><tr><td><code>tags</code></td><td>文章标签，用于分类和筛选。可以是字符串数组或标签对象数组。</td></tr><tr><td><code>keywords</code></td><td>SEO 关键词，放入 <code>&lt;meta&gt;</code> 标签。</td></tr><tr><td><code>description</code></td><td>文章描述，用于 SEO 和列表摘要。</td></tr><tr><td><code>image</code></td><td>文章封面图 URL，用于社交媒体分享卡片。</td></tr><tr><td><code>draft</code></td><td>草稿状态。设为 <code>true</code> 时文章不会出现在生产构建中，仅在开发模式可见。</td></tr></tbody></table>\n<hr>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"其他常用-front-matter-属性\">其他常用 Front Matter 属性<a href=\"https://devvv.cn/blog/testBlog#%E5%85%B6%E4%BB%96%E5%B8%B8%E7%94%A8-front-matter-%E5%B1%9E%E6%80%A7\" class=\"hash-link\" aria-label=\"其他常用 Front Matter 属性的直接链接\" title=\"其他常用 Front Matter 属性的直接链接\" translate=\"no\">​</a></h2>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"1-页面行为控制\">1. 页面行为控制<a href=\"https://devvv.cn/blog/testBlog#1-%E9%A1%B5%E9%9D%A2%E8%A1%8C%E4%B8%BA%E6%8E%A7%E5%88%B6\" class=\"hash-link\" aria-label=\"1. 页面行为控制的直接链接\" title=\"1. 页面行为控制的直接链接\" translate=\"no\">​</a></h3>\n<table><thead><tr><th>属性</th><th>说明</th></tr></thead><tbody><tr><td><code>hide_table_of_contents</code></td><td>隐藏右侧目录（TOC），默认 <code>false</code>。</td></tr><tr><td><code>toc_min_heading_level</code></td><td>TOC 最小标题级别（如 <code>2</code>）。</td></tr><tr><td><code>toc_max_heading_level</code></td><td>TOC 最大标题级别（如 <code>3</code>）。</td></tr><tr><td><code>sidebar_label</code></td><td>侧边栏显示的自定义标签（仅文档）。</td></tr><tr><td><code>sidebar_position</code></td><td>侧边栏排序位置（数字，仅文档）。</td></tr></tbody></table>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"2-博客相关\">2. 博客相关<a href=\"https://devvv.cn/blog/testBlog#2-%E5%8D%9A%E5%AE%A2%E7%9B%B8%E5%85%B3\" class=\"hash-link\" aria-label=\"2. 博客相关的直接链接\" title=\"2. 博客相关的直接链接\" translate=\"no\">​</a></h3>\n<table><thead><tr><th>属性</th><th>说明</th></tr></thead><tbody><tr><td><code>sticky</code></td><td>置顶优先级（数字越大越靠前），需配合自定义插件实现。</td></tr><tr><td><code>unlisted</code></td><td>设为 <code>true</code> 后文章不出现在博客列表，但可通过直接链接访问（Docusaurus 2.4+）。</td></tr><tr><td><code>hide_comment</code></td><td>控制是否隐藏评论组件（需要自定义）。</td></tr></tbody></table>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"3-搜索与-seo\">3. 搜索与 SEO<a href=\"https://devvv.cn/blog/testBlog#3-%E6%90%9C%E7%B4%A2%E4%B8%8E-seo\" class=\"hash-link\" aria-label=\"3. 搜索与 SEO的直接链接\" title=\"3. 搜索与 SEO的直接链接\" translate=\"no\">​</a></h3>\n<table><thead><tr><th>属性</th><th>说明</th></tr></thead><tbody><tr><td><code>keywords</code></td><td>同上，支持字符串数组。</td></tr><tr><td><code>image</code></td><td>社交卡片图片。</td></tr></tbody></table>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"4-文档专用如果使用-docs\">4. 文档专用（如果使用 docs）<a href=\"https://devvv.cn/blog/testBlog#4-%E6%96%87%E6%A1%A3%E4%B8%93%E7%94%A8%E5%A6%82%E6%9E%9C%E4%BD%BF%E7%94%A8-docs\" class=\"hash-link\" aria-label=\"4. 文档专用（如果使用 docs）的直接链接\" title=\"4. 文档专用（如果使用 docs）的直接链接\" translate=\"no\">​</a></h3>\n<table><thead><tr><th>属性</th><th>说明</th></tr></thead><tbody><tr><td><code>id</code></td><td>文档唯一标识（默认文件名）。</td></tr><tr><td><code>sidebar_position</code></td><td>侧边栏位置。</td></tr><tr><td><code>sidebar_label</code></td><td>侧边栏显示标题。</td></tr></tbody></table>\n<h3 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"5-自定义字段\">5. 自定义字段<a href=\"https://devvv.cn/blog/testBlog#5-%E8%87%AA%E5%AE%9A%E4%B9%89%E5%AD%97%E6%AE%B5\" class=\"hash-link\" aria-label=\"5. 自定义字段的直接链接\" title=\"5. 自定义字段的直接链接\" translate=\"no\">​</a></h3>\n<p>你可以添加任意自定义字段，并在主题组件中通过 <code>frontMatter</code> 获取。</p>\n<hr>\n<h2 class=\"anchor anchorTargetStickyNavbar_UCMm\" id=\"示例\">示例<a href=\"https://devvv.cn/blog/testBlog#%E7%A4%BA%E4%BE%8B\" class=\"hash-link\" aria-label=\"示例的直接链接\" title=\"示例的直接链接\" translate=\"no\">​</a></h2>\n<div class=\"language-yaml codeBlockContainer_APcc theme-code-block\" style=\"--prism-background-color:hsl(230, 1%, 98%);--prism-color:hsl(230, 8%, 24%)\"><div class=\"codeBlockContent_m3Ux\"><pre class=\"prism-code language-yaml codeBlock_qGQc thin-scrollbar\" style=\"background-color:hsl(230, 1%, 98%);color:hsl(230, 8%, 24%)\"><code class=\"codeBlockLines_p187\"><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">---</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">slug</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> /my</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">awesome</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\">post</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">title</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> 我的第一篇博客</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">date</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token datetime number\" style=\"color:hsl(35, 99%, 36%)\">2025-01-01</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">authors</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">  </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">-</span><span class=\"token plain\"> </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">name</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> 张三</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">title</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> 全栈开发者</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">url</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> https</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\">//example.com</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\">    </span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">imageURL</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> /img/avatar.png</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">tags</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\">技术</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> 前端</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">keywords</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">[</span><span class=\"token plain\">JavaScript</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">,</span><span class=\"token plain\"> React</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">]</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">description</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> 这是一篇关于前端技术的文章。</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">image</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> /img/cover.png</span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">draft</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">false</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">hide_table_of_contents</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token boolean important\" style=\"color:hsl(230, 8%, 24%);font-weight:bold\">false</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">toc_min_heading_level</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">2</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">toc_max_heading_level</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">3</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token key atrule\" style=\"color:hsl(35, 99%, 36%)\">sticky</span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">:</span><span class=\"token plain\"> </span><span class=\"token number\" style=\"color:hsl(35, 99%, 36%)\">1</span><span class=\"token plain\"></span><br></span><span class=\"token-line\" style=\"color:hsl(230, 8%, 24%)\"><span class=\"token plain\"></span><span class=\"token punctuation\" style=\"color:hsl(119, 34%, 47%)\">---</span><br></span></code></pre><div class=\"buttonGroup_6DOT\"><div><div class=\"copyButtonWrapper_Ja4V\"><button type=\"button\" aria-label=\"复制代码到剪贴板\" title=\"复制\" class=\"clean-btn codeButton_RCLg\"><span class=\"copyButtonIcons_FhaS\" aria-hidden=\"true\"><svg viewBox=\"0 0 24 24\" class=\"copyButtonIcon_phi_\"><path fill=\"currentColor\" d=\"M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z\"></path></svg><svg viewBox=\"0 0 24 24\" class=\"copyButtonSuccessIcon_FfTR\"><path fill=\"currentColor\" d=\"M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z\"></path></svg></span></button></div></div><span class=\"codeLanguage_p4Xy\">yaml</span></div></div></div>\n<p>这些属性可以灵活组合，满足大多数博客和文档站点的需求。</p>",
            "url": "https://devvv.cn/blog/testBlog",
            "title": "这是一篇测试文章",
            "summary": "这篇文章是测试",
            "date_modified": "2025-12-31T00:00:00.000Z",
            "author": {
                "name": "vv",
                "url": "https://devvv.cn"
            },
            "tags": [
                "测试"
            ]
        }
    ]
}