https://hitoli.com
涛声依旧
天下事有难易乎?为之,则难者亦易矣
https://hitoli.com/images/favicon.ico
Hito Li
2026-11-13T03:42:19.000Z
https://hitoli.com/2026/11/13/AI%E5%8F%8D%E4%BB%A3%E5%A5%BD%E5%B7%A5%E5%85%B7-Agent2Api%E6%8E%A8%E8%8D%90/
AI反代好工具-Agent2Api推荐
<h4 id="起因额度都锁在客户端里"><a class="anchor" href="#起因额度都锁在客户端里">#</a> 起因:额度都锁在客户端里</h4>
<p>现在手里能用的 AI 额度,一多半是跟着客户端走的:某个 IDE 送的、某个 CLI 登录后才有的、某个网页版账号每天签到的。这些额度要么只能在它自家的客户端里点,要么协议各说各话 ——OpenAI 的 Chat Completions、Responses,Anthropic 的 Messages,还有一堆只有自家才认的私有接口。</p>
<p>想把这些额度接进 Cherry Studio、Open WebUI、LobeChat,或者接进自己的脚本里跑点自动化,就得有个东西站在中间,把客户端的登录态接过来,翻译成标准的 OpenAI 兼容接口。这就是所谓「AI 反代」。</p>
<p>试过几个之后,这段时间一直在用的是 <strong>Agent2API</strong>( <code>aimod-cc/agent2api</code> ),记录一下。</p>
<h4 id="项目基本情况"><a class="anchor" href="#项目基本情况">#</a> 项目基本情况</h4>
<ul>
<li>仓库:<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2FpbW9kLWNjL2FnZW50MmFwaQ==">https://github.com/aimod-cc/agent2api</span></li>
<li>定位:本地 AI 路由网关 + Agent 客户端接管</li>
<li>协议:AGPL-3.0</li>
<li>形态:桌面端(Windows /macOS/ Linux)、无头服务器(Windows Server / Linux)、Docker(amd64 /arm64)</li>
<li>默认端口:3065,同一个端口既是管理面板也是 OpenAI 兼容网关</li>
</ul>
<p>一句话概括它的思路:<strong>复用各家客户端的登录态,用一个 base_url 调 50 多家模型额度,统一 OpenAI / Anthropic / 生图接口,多账号选路、签到、余额和请求报表全在一个面板里。</strong></p>
<h4 id="功能介绍"><a class="anchor" href="#功能介绍">#</a> 功能介绍</h4>
<p><strong>1. 统一模型接口</strong></p>
<p>同时提供 OpenAI 的 Chat Completions、Responses、Images 和 Anthropic 的 Messages 接口,模型目录统一管理。也就是说 Cherry Studio 这种只认 OpenAI 的客户端,和 Claude Code 这种只认 Anthropic 的,可以共用同一个网关、同一个 key。生图和参考图编辑也在里面(小浣熊、Loomy、Antigravity、ModelScope、WorkBuddy、豆包工作台这些来源)。</p>
<p><strong>2. AI 路由</strong></p>
<p>模型映射、账号优先级、负载均衡、会话粘性和故障切换放在一处配。实际用起来最舒服的是「会话粘性」—— 同一轮对话固定走同一个账号,缓存命中率会好看很多。</p>
<p><strong>3. Agent 客户端接管</strong></p>
<p>这个是我觉得最省事的部分。它不只是给你一个 URL,还能管理本地客户端的多套连接配置:一键导入现有设置、预览将要写入的内容、在「走网关」和「走官方」之间切换。改完即时生效,不用手工去翻各个客户端的 json 配置文件。</p>
<p><strong>4. Provider 插件化</strong></p>
<p>50 多家 provider 不是全塞在主程序里,而是按插件独立安装、独立更新。主程序升级不会把 provider 的实现冲掉;自定义 provider 则不需要装插件。</p>
<p><strong>5. 出口代理</strong></p>
<p>可以给每个账号单独选代理池出口。多账号场景下这点很关键 —— 同一个 IP 上挂一堆账号,风控基本躲不过。作者还和 ProxyLane 有合作,用优惠码 <code>AGENT2API25</code> 首购 25% off(这个按需,不是必须)。</p>
<p><strong>6. 网关安全</strong></p>
<p>网关 key 支持作用域划分;面板登录可以开人机验证;没配 key 的时候模型请求默认直接拒绝,不会出现部署完就裸奔的情况。</p>
<p><strong>7. 请求报表</strong></p>
<p>请求量、成功率、token 消耗、<strong>缓存命中率</strong>,还有账号和 provider 的排行、用量环形图、365 天活跃热力图。趋势页是双轴的:24 小时缓存命中率折线 + token 消耗面积图。排查「到底是谁在烧额度」比翻日志快多了。</p>
<p><strong>8. 后台维护</strong></p>
<p>模型目录定时刷新、凭证维护、更新检查,外加每日自动签到 —— 按 provider 各自的时间窗跑(Qoder 10:01,ZCode 19:01,其它按设定时间),之后还有一轮补签,只补没签到的账号。</p>
<p><strong>9. 手机端</strong></p>
<p>浏览器打开 <code>http://<网关IP>:3065/m</code> 就是移动端面板,可以「添加到主屏幕」当 PWA 用;也有独立的 apk /ipa(iOS 那个未签名,要自己签)。</p>
<h4 id="适合什么场景"><a class="anchor" href="#适合什么场景">#</a> 适合什么场景</h4>
<ul>
<li>把 IDE / CLI 送的额度接进 Cherry Studio、Open WebUI、LobeChat、new-api 之类的地方统一用</li>
<li>多账号轮着用,顺手看余额、签到、用量统计</li>
<li>给自己的脚本、机器人、内部小工具提供一个稳定的统一入口</li>
</ul>
<p>反过来,如果只是想把几个正规的 API key 聚合成一个入口做分发,那 one-api /new-api 更合适,不需要 Agent2API 这套「接管客户端」的机制。</p>
<h4 id="如何下载"><a class="anchor" href="#如何下载">#</a> 如何下载</h4>
<p>Release 页面:<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2FpbW9kLWNjL2FnZW50MmFwaS9yZWxlYXNlcw==">https://github.com/aimod-cc/agent2api/releases</span></p>
<p>按用途挑一个就行:</p>
<pre><code># 桌面端
Agent2API_<版本>_x64-setup.exe # Windows
Agent2API_<版本>_universal.dmg # macOS
Agent2API_<版本>_amd64.deb / .AppImage # Linux
# 服务器(无界面,注册成系统服务,开机自启)
agent2api-server-windows-amd64.zip
agent2api-server-linux-<arch>.tar.gz
# Docker
aimodcc/agent2api:latest # amd64 / arm64
</code></pre>
<p>桌面端的用法:添加自定义 provider 和账号 → 建一个网关 key → 到 Agent 页面应用连接配置,或者直接把客户端指向 <code>http://127.0.0.1:3065/v1</code> 并填上 key。</p>
<p>服务器版的安装:</p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment"># Linux</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token function">tar</span> <span class="token parameter variable">-xzf</span> agent2api-server-linux-amd64.tar.gz <span class="token operator">&&</span> <span class="token builtin class-name">cd</span> agent2api-server-linux-amd64 <span class="token operator">&&</span> <span class="token function">sudo</span> <span class="token function">bash</span> install.sh</pre></td></tr></table></figure><figure class="highlight powershell"><figcaption data-lang="PowerShell"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment"># Windows Server(管理员 PowerShell)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token function">Expand-Archive</span> agent2api-server-windows-amd64<span class="token punctuation">.</span>zip <span class="token operator">-</span>DestinationPath C:\agent2api-pkg</pre></td></tr><tr><td data-num="3"></td><td><pre>cd C:\agent2api-pkg<span class="token punctuation">;</span> <span class="token punctuation">.</span>\<span class="token function">install-service</span><span class="token punctuation">.</span>ps1</pre></td></tr></table></figure><h4 id="docker-安装"><a class="anchor" href="#docker-安装">#</a> Docker 安装</h4>
<p><strong>方式一:一条命令跑起来</strong></p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">docker</span> run <span class="token parameter variable">-d</span> <span class="token parameter variable">--name</span> agent2api <span class="token parameter variable">--restart</span> unless-stopped <span class="token parameter variable">-p</span> <span class="token number">3065</span>:3065 <span class="token parameter variable">-v</span> ./data:/data aimodcc/agent2api:latest</pre></td></tr></table></figure><p>注意 <code>./data</code> 建议换成绝对路径,比如 <code>-v /opt/agent2api/data:/data</code> ,不然换个目录执行 compose/run 就找不到原来的数据了。ARM 的机器(群晖、树莓派、ARM 云主机)直接拉就行,镜像本身就是多架构的。</p>
<p><strong>方式二:docker compose(推荐)</strong></p>
<figure class="highlight yaml"><figcaption data-lang="YAML"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token key atrule">services</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token key atrule">agent2api</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token key atrule">image</span><span class="token punctuation">:</span> aimodcc/agent2api<span class="token punctuation">:</span>latest</pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token key atrule">container_name</span><span class="token punctuation">:</span> agent2api</pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token key atrule">restart</span><span class="token punctuation">:</span> unless<span class="token punctuation">-</span>stopped</pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token key atrule">ports</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token punctuation">-</span> <span class="token string">"3065:3065"</span> <span class="token comment"># 网关(/v1/*)与面板</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token key atrule">environment</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token comment"># 可选项:不填就走面板首次登录注册</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token key atrule">AGENT2API_ADMIN_USER</span><span class="token punctuation">:</span> admin</pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token key atrule">AGENT2API_ADMIN_PASSWORD</span><span class="token punctuation">:</span> 换成你自己的密码</pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token comment"># 登录页人机验证,默认开;1 开 0 关</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token key atrule">AGENT2API_CAPTCHA_ENABLED</span><span class="token punctuation">:</span> <span class="token number">1</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token comment"># 面板「设置 → 软件更新」一键更新,默认开</span></pre></td></tr><tr><td data-num="15"></td><td><pre> <span class="token key atrule">AGENT2API_SELF_UPDATE</span><span class="token punctuation">:</span> <span class="token number">1</span></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token key atrule">volumes</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token comment"># 全部状态(SQLite 库、配置、日志)都在这一个卷里</span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token punctuation">-</span> ./data<span class="token punctuation">:</span>/data</pre></td></tr><tr><td data-num="19"></td><td><pre> <span class="token comment"># 小内存机器(512M~1G 的 VPS / NAS)建议加个上限,超限重启一次而不是拖垮宿主机</span></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token comment"># mem_limit: 1g</span></pre></td></tr></table></figure><figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">docker</span> compose up <span class="token parameter variable">-d</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token function">docker</span> compose logs <span class="token parameter variable">-f</span> agent2api</pre></td></tr></table></figure><p><strong>方式三:面板和网关分端口(想把面板留在内网)</strong></p>
<p>设了 <code>AGENT2API_PANEL_PORT</code> 之后,管理面(界面 + <code>/api/*</code> )单独监听那个端口,主端口只剩 <code>/v1/*</code> 网关。这时候只把网关暴露到公网,面板绑回环:</p>
<figure class="highlight yaml"><figcaption data-lang="YAML"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token key atrule">environment</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token key atrule">AGENT2API_PANEL_PORT</span><span class="token punctuation">:</span> <span class="token number">3066</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token key atrule">ports</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token punctuation">-</span> <span class="token string">"3065:3065"</span> <span class="token comment"># 网关,公网可暴露</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token punctuation">-</span> <span class="token string">"127.0.0.1:3066:3066"</span> <span class="token comment"># 面板,只绑本机,走 SSH 隧道或内网访问</span></pre></td></tr></table></figure><p><strong>验证部署</strong></p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment"># 连通性检查</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token function">curl</span> http://127.0.0.1:3065/health</pre></td></tr></table></figure><p>返回正常就打开面板 <code>http://<主机IP>:3065/</code> ,首次打开会提示注册管理员账号(如果 compose 里预置了账号密码,启动时会自动转成 bcrypt 哈希入库,直接登录即可)。</p>
<p><strong>首次配置流程</strong></p>
<ol>
<li>面板里添加 provider,选版本后网页登录授权(登录态就存在本地库里了)</li>
<li>到「网关 Key」页创建一个 key,按需要划作用域</li>
<li>客户端填 <code>base_url = http://<主机IP>:3065/v1</code> ,key 用上一步建的</li>
<li>模型名在「模型管理」页的目录里选,填对应的映射名</li>
</ol>
<p>验证一下能不能通:</p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">curl</span> http://127.0.0.1:3065/v1/chat/completions <span class="token punctuation">\</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token parameter variable">-H</span> <span class="token string">"Authorization: Bearer sk-你建的key"</span> <span class="token punctuation">\</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token parameter variable">-H</span> <span class="token string">"Content-Type: application/json"</span> <span class="token punctuation">\</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token parameter variable">-d</span> <span class="token string">'{"model":"<模型管理里选一个>","messages":[{"role":"user","content":"你好"}]}'</span></pre></td></tr></table></figure><p><strong>升级与备份</strong></p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment"># 标准升级:拉新镜像重建容器</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token function">docker</span> compose pull <span class="token operator">&&</span> <span class="token function">docker</span> compose up <span class="token parameter variable">-d</span></pre></td></tr></table></figure><figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment"># 备份 = 打包 data 卷</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token function">tar</span> <span class="token parameter variable">-czf</span> agent2api-<span class="token variable"><span class="token variable">$(</span><span class="token function">date</span> +%F<span class="token variable">)</span></span>.tar.gz <span class="token parameter variable">-C</span> /opt/agent2api data</pre></td></tr></table></figure><p>面板里的「软件更新」替换的是<strong>容器内</strong>的文件,compose 里的镜像 tag 没变,所以下次 <code>up -d</code> 重建容器会退回旧版本。要么就用 <code>docker compose pull</code> 升级,要么就别开自更新。</p>
<h4 id="几个实际踩到的点"><a class="anchor" href="#几个实际踩到的点">#</a> 几个实际踩到的点</h4>
<ul>
<li><strong>端口冲突</strong>:3065 不算冷门,装之前先 <code>ss -lntp | grep 3065</code> 看一眼。</li>
<li><strong>账号要配出口</strong>:不配代理直接跑,多账号很容易触发风控。账号页里一个账号一个出口,别图省事共用。</li>
<li><strong>别公网裸奔</strong>:面板默认就在 3065 上,公网暴露的话至少开人机验证、给 key 划作用域;能绑内网就绑内网。</li>
<li><strong> <code>./data</code> 里是敏感数据</strong>:SQLite 库里存着加密后的账号凭证,导出和备份文件可能是明文级别的东西,别往 Git、网盘、群聊里丢。</li>
<li><strong>出问题先看日志</strong>: <code>docker compose logs -f agent2api</code> 基本能定位到是鉴权、供应商还是网络的问题。</li>
<li><strong>模型名对不上</strong>:客户端里报 model not found,多半是模型目录里的名字和映射没对上,回「模型管理」页看一眼实际可用列表。</li>
</ul>
<h4 id="使用须知"><a class="anchor" href="#使用须知">#</a> 使用须知</h4>
<ul>
<li>项目是 AGPL-3.0,商用、修改、分发都允许,但对外提供网络服务时要按要求提供对应源码。</li>
<li>凭证虽然在库里加密,但导出、备份、key 文件仍可能含敏感信息。</li>
<li>复用客户端登录态这件事,各家服务条款的态度并不一致,<strong>仅建议个人研究自用</strong>,别拿去对外卖 token 做中转站,封号风险自担。</li>
<li>项目本身 as-is 提供,不担保可用性、稳定性和安全性。</li>
</ul>
<h4 id="小结"><a class="anchor" href="#小结">#</a> 小结</h4>
<p>Agent2API 属于那种「装上就一直在后台待着」的工具:平时想不起来它,但每次要换客户端、要加账号、要看这个月谁烧了多少额度,都会去面板点两下。对于手里额度散落在十几个客户端里的人,省下来的配置时间比它占的那点内存值多了。</p>
<p>如果只是想聚合几个正规 API key,one-api /new-api 更轻;如果要接管客户端登录态、还要多账号调度和报表,那这个目前是我用过最顺手的。</p>
2026-11-13T03:42:19.000Z
https://hitoli.com/2025/10/04/%E8%87%AA%E5%BB%BA%E7%A7%81%E6%9C%8D/
自建私服
<h1 id="前言"><a class="anchor" href="#前言">#</a> 前言</h1>
<p>国庆闲的无聊,自建了两个私服。有感兴趣的朋友可以一起玩玩!不充值不氪金不变态,纯休闲娱乐!</p>
<h4 id="客户端下载"><a class="anchor" href="#客户端下载">#</a> 客户端下载</h4>
<p><span class="exturl" data-url="aHR0cHM6Ly9wYW4uYmFpZHUuY29tL3MvMVdjZko0UmVwZnE1MlBVVHNEWWcwbFE/cHdkPWhpdG8=">客户端</span></p>
<h4 id="魔兽世界注册"><a class="anchor" href="#魔兽世界注册">#</a> 魔兽世界注册</h4>
<p><span class="exturl" data-url="aHR0cHM6Ly93b3cuaGl0b2xpLmNvbTo4NDQzLw==">注册账号</span></p>
2025-10-04T14:55:00.000Z
https://hitoli.com/2025/02/16/%E6%9E%81%E7%A9%BA%E9%97%B4%E9%83%A8%E7%BD%B2Deepseek%EF%BC%88API%E8%B0%83%E7%94%A8%EF%BC%89/
极空间部署DeepSeek(API调用)
<h4 id="前言"><a class="anchor" href="#前言">#</a> 前言</h4>
<p>最近 DeepSeek 比较火爆,到处都在夸。大部分人都想搭建自己的私有服务器,但我查了查资料还是放弃了想法,毕竟需要投入一笔不小的费用!🙂,最后又经不住诱惑就搞一个调用 api 的吧。经过研究,最终决定使用 justsong/one-api 加 vinlic/deepseek-free-api 加 yidadaa/chatgpt-next-web 的方案。justsong/one-api 用于统一管理、调用 AI 服务(当然也可以调用自己搭建的 DeepSeek🙂),vinlic/deepseek-free-api 用于调用 DeepSeek 官方接口,yidadaa/chatgpt-next-web 提供 web 界面用户和 ai 进行对话。大致了解清楚后就开始吧!</p>
<h4 id="前期准备"><a class="anchor" href="#前期准备">#</a> 前期准备</h4>
<p>需要自己先申请一个<span class="exturl" data-url="aHR0cHM6Ly9jaGF0LmRlZXBzZWVrLmNvbS8="> DeepSeek</span> 账号,并获取 token。获取方法是登陆后随便说一句话,然后按 F12 到应用程序 - 存储 - 本地存储中找到 userToken 的 value 值。<br />
<img data-src="https://npic.hitoli.com:8443/images/2025/02/16/2025-02-16-23-54-54.png" alt="2025-02-16-23-54-54.png" /></p>
<h5 id="安装deepseek-free-api"><a class="anchor" href="#安装deepseek-free-api">#</a> 安装 deepseek-free-api</h5>
<ul>
<li>1、端口</li>
</ul>
<p><img data-src="https://npic.hitoli.com:8443/images/2025/02/16/2025-02-16-23-52-13.png" alt="2025-02-16-23-52-13.png" /></p>
<ul>
<li>2、环境<br />
<img data-src="https://npic.hitoli.com:8443/images/2025/02/16/2025-02-16-23-53-30.png" alt="2025-02-16-23-53-30.png" /></li>
</ul>
<div class="note info">
<p>增加参数 DEEP_SEEK_CHAT_AUTHORIZATION 值:userToken 的 value 值</p>
</div>
<h5 id="安装one-api"><a class="anchor" href="#安装one-api">#</a> 安装 one-api</h5>
<ul>
<li>
<p>1、文件夹与路径<br />
<img data-src="https://npic.hitoli.com:8443/images/2025/02/16/2025-02-16-23-56-44.png" alt="2025-02-16-23-56-44.png" /></p>
</li>
<li>
<p>2、端口<br />
<img data-src="https://npic.hitoli.com:8443/images/2025/02/16/2025-02-16-23-57-30.png" alt="2025-02-16-23-57-30.png" /></p>
</li>
<li>
<p>3、配置</p>
</li>
</ul>
<div class="note info">
<p>登陆 web 页面(极空间 ip+one-api 的本地端口,默认用户名密码 root/123456),先添加渠道,再添加令牌。渠道用于调用指定的 api,我这里调用的是 deepseek-free-api(密钥为 userToken 的 value 值)。令牌用于给 chatgpt-next-web 使用,记录、控制权限等。</p>
</div>
<p><img data-src="https://npic.hitoli.com:8443/images/2025/03/09/c200886ba8c9.jpg" alt="c200886ba8c9.jpg" /></p>
<p><img data-src="https://npic.hitoli.com:8443/images/2025/02/17/2025-02-17-00-01-17.png" alt="2025-02-17-00-01-17.png" /></p>
<h5 id="安装chatgpt-next-web"><a class="anchor" href="#安装chatgpt-next-web">#</a> 安装 chatgpt-next-web</h5>
<ul>
<li>
<p>1、端口<br />
<img data-src="https://npic.hitoli.com:8443/images/2025/02/17/2025-02-17-00-02-14.png" alt="2025-02-17-00-02-14.png" /></p>
</li>
<li>
<p>2、环境</p>
</li>
</ul>
<div class="note info">
<p>参数 OPENAI_API_KEY 的值填 one-api 令牌页面复制的值。再增加一个 BASE_URL 参数,值为 one-api 的地址(极空间 ip+one-api 的本地端口)</p>
</div>
<p><img data-src="https://npic.hitoli.com:8443/images/2025/02/17/2025-02-17-00-04-28.png" alt="2025-02-17-00-04-28.png" /><br />
<img data-src="https://npic.hitoli.com:8443/images/2025/02/17/2025-02-17-00-03-04.png" alt="2025-02-17-00-03-04.png" /></p>
<ul>
<li>3、对话</li>
</ul>
<div class="note info">
<p>恭喜你,至此已经搭建完成。通过极空间 ip+chatgpt-next-web 的本地端口就可以开始和 DeepSeek 对话了。</p>
</div>
<p><img data-src="https://npic.hitoli.com:8443/images/2025/02/17/2025-02-17-00-06-07.png" alt="2025-02-17-00-06-07.png" /></p>
<h5 id="nginx-proxy-manager配置"><a class="anchor" href="#nginx-proxy-manager配置">#</a> nginx proxy manager 配置</h5>
<div class="note info">
<p>chatgpt-next-web 反代时需要在高级里加入以下代码,否则会报错。</p>
</div>
<figure class="highlight yaml"><figcaption data-lang="YAML"></figcaption><table><tr><td data-num="1"></td><td><pre>location / <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td><pre> proxy_pass http<span class="token punctuation">:</span>//极空间ip<span class="token punctuation">:</span>chatgpt<span class="token punctuation">-</span>next<span class="token punctuation">-</span>web的本地端口;</pre></td></tr><tr><td data-num="3"></td><td><pre> proxy_set_header Host $host;</pre></td></tr><tr><td data-num="4"></td><td><pre> proxy_set_header X<span class="token punctuation">-</span>Forwarded<span class="token punctuation">-</span>Host $http_host;</pre></td></tr><tr><td data-num="5"></td><td><pre> proxy_set_header X<span class="token punctuation">-</span>Forwarded<span class="token punctuation">-</span>Proto $scheme;</pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr></table></figure><p>最终成果<br />
<img data-src="https://npic.hitoli.com:8443/images/2025/02/16/0d5ddc77d244fcc4e1a60a1828eed054.png" alt="0d5ddc77d244fcc4e1a60a1828eed054.png" /></p>
2025-02-16T14:32:00.000Z
https://hitoli.com/2024/09/29/dante-stunnel-clash-%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91/
dante+stunnel+clash 科学上网
<h4 id="前言"><a class="anchor" href="#前言">#</a> 前言</h4>
<p>上次介绍了使用 squid+stunnel 的方案进行科学上网。但是那个方案只适合在浏览器上使用,并不能让其它 app 也可以科学上网。此次介绍使用 dante+stunnel+clash 的方式来代理其它 app 科学上网。</p>
<h4 id="准备"><a class="anchor" href="#准备">#</a> 准备</h4>
<p>一台可以访问外网的服务器,如香港的云主机并安装 Ubuntu 系统。</p>
<h5 id="dante部分"><a class="anchor" href="#dante部分">#</a> dante 部分</h5>
<ul>
<li>1、安装</li>
</ul>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">apt-get</span> <span class="token function">install</span> <span class="token parameter variable">-y</span> dante-server</pre></td></tr></table></figure><ul>
<li>2、配置</li>
</ul>
<div class="note info">
<p>修改 dante 配置<br />
1、修改 /etc/danted.conf 文件,在末尾加入下面的配置<br />
2、如果不需要用户密码认证,则把 socksmethod 改为 none<br />
3、可以为认证单独添加一个用户<br />
sudo useradd -r -s /bin/false proxy<br />
sudo passwd proxy<br />
4、重启服务<br />
systemctl restart danted<br />
5、查看状态<br />
systemctl status danted</p>
</div>
<figure class="highlight yaml"><figcaption data-lang="YAML"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token key atrule">logoutput</span><span class="token punctuation">:</span> syslog</pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token key atrule">internal</span><span class="token punctuation">:</span> 0.0.0.0 port = 1080</pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token key atrule">external</span><span class="token punctuation">:</span> eth0</pre></td></tr><tr><td data-num="4"></td><td><pre></pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token key atrule">socksmethod</span><span class="token punctuation">:</span> username</pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token key atrule">clientmethod</span><span class="token punctuation">:</span> none</pre></td></tr><tr><td data-num="7"></td><td><pre></pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token key atrule">user.privileged</span><span class="token punctuation">:</span> root</pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token key atrule">user.notprivileged</span><span class="token punctuation">:</span> nobody</pre></td></tr><tr><td data-num="10"></td><td><pre></pre></td></tr><tr><td data-num="11"></td><td><pre>client pass <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token key atrule">from</span><span class="token punctuation">:</span> <span class="token key atrule">0.0.0.0/0 to</span><span class="token punctuation">:</span> 0.0.0.0/0</pre></td></tr><tr><td data-num="13"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="14"></td><td><pre></pre></td></tr><tr><td data-num="15"></td><td><pre>socks pass <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token key atrule">from</span><span class="token punctuation">:</span> <span class="token key atrule">0.0.0.0/0 to</span><span class="token punctuation">:</span> 0.0.0.0/0</pre></td></tr><tr><td data-num="17"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><h5 id="stunnel服务端部分"><a class="anchor" href="#stunnel服务端部分">#</a> stunnel 服务端部分</h5>
<ul>
<li>1、安装(和 danted 装在一起)</li>
</ul>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">apt-get</span> <span class="token function">install</span> <span class="token parameter variable">-y</span> stunnel</pre></td></tr></table></figure><ul>
<li>2、生成 TLS/SSL 证书</li>
</ul>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>openssl req <span class="token parameter variable">-new</span> <span class="token parameter variable">-x509</span> <span class="token parameter variable">-days</span> <span class="token number">3650</span> <span class="token parameter variable">-nodes</span> <span class="token parameter variable">-out</span> stunnel.pem <span class="token parameter variable">-keyout</span> stunnel.pem</pre></td></tr></table></figure><ul>
<li>
<p>3、将证书 stunnel.pem 放到 /etc/stunnel/ 目录下</p>
</li>
<li>
<p>4、修改 stunnel 配置 (/etc/stunnle/stunnle.conf)</p>
</li>
</ul>
<figure class="highlight yaml"><figcaption data-lang="YAML"></figcaption><table><tr><td data-num="1"></td><td><pre>; 设置stunnel的pid文件路径</pre></td></tr><tr><td data-num="2"></td><td><pre>pid = /etc/stunnel/stunnel.pid</pre></td></tr><tr><td data-num="3"></td><td><pre>; 设置stunnel工作的用户(组)</pre></td></tr><tr><td data-num="4"></td><td><pre>setuid = root</pre></td></tr><tr><td data-num="5"></td><td><pre>setgid = root</pre></td></tr><tr><td data-num="6"></td><td><pre></pre></td></tr><tr><td data-num="7"></td><td><pre>; 开启日志等级:emerg (0)<span class="token punctuation">,</span> alert (1)<span class="token punctuation">,</span> crit (2)<span class="token punctuation">,</span> err (3)<span class="token punctuation">,</span> warning (4)<span class="token punctuation">,</span> notice (5)<span class="token punctuation">,</span> info (6)<span class="token punctuation">,</span> or debug (7)</pre></td></tr><tr><td data-num="8"></td><td><pre>debug = 7</pre></td></tr><tr><td data-num="9"></td><td><pre>; 日志文件路径</pre></td></tr><tr><td data-num="10"></td><td><pre>output = /etc/stunnel/stunnel.log</pre></td></tr><tr><td data-num="11"></td><td><pre></pre></td></tr><tr><td data-num="12"></td><td><pre>; 证书文件</pre></td></tr><tr><td data-num="13"></td><td><pre>cert = /etc/stunnel/stunnel.pem</pre></td></tr><tr><td data-num="14"></td><td><pre>; 私钥文件</pre></td></tr><tr><td data-num="15"></td><td><pre>key = /etc/stunnel/stunnel.pem</pre></td></tr><tr><td data-num="16"></td><td><pre></pre></td></tr><tr><td data-num="17"></td><td><pre>; 自定义服务名danted</pre></td></tr><tr><td data-num="18"></td><td><pre><span class="token punctuation">[</span>danted<span class="token punctuation">]</span></pre></td></tr><tr><td data-num="19"></td><td><pre>; 服务监听的端口,client要连接这个端口与server通信</pre></td></tr><tr><td data-num="20"></td><td><pre>accept = 1081</pre></td></tr><tr><td data-num="21"></td><td><pre>; 服务要连接的端口,连接到danted的1080端口,将数据发给danted</pre></td></tr><tr><td data-num="22"></td><td><pre>connect = 1080</pre></td></tr></table></figure><ul>
<li>5、重启服务<br />
systemctl restart stunnel4</li>
<li>6、查看状态<br />
systemctl status stunnel4</li>
</ul>
<h5 id="stunnel客户端部分"><a class="anchor" href="#stunnel客户端部分">#</a> stunnel 客户端部分</h5>
<div class="note info">
<p>可以安装在要代理的机器上,在需要代理的情况下再开启(代理地址填 127.0.0.1 加客户端监听端口)。也可以安装在国内的服务器上一直保持连接(代理信息填国内服务器 ip 加客户端监听端口)。本示例客户端为 ubuntu 系统</p>
</div>
<ul>
<li>1、安装(和 danted 装在一起)</li>
</ul>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">apt-get</span> <span class="token function">install</span> <span class="token parameter variable">-y</span> stunnel</pre></td></tr></table></figure><ul>
<li>2、修改配置(/etc/stunnel/stunnel.conf)</li>
</ul>
<figure class="highlight yaml"><figcaption data-lang="YAML"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token punctuation">[</span>danted<span class="token punctuation">]</span></pre></td></tr><tr><td data-num="2"></td><td><pre>; 监听端口,用户的代理设置就是 stunnel<span class="token punctuation">-</span>client<span class="token punctuation">-</span>ip<span class="token punctuation">:</span><span class="token number">1080</span></pre></td></tr><tr><td data-num="3"></td><td><pre>accept = 1080</pre></td></tr><tr><td data-num="4"></td><td><pre>; 要连接到的stunnel server的ip与端口</pre></td></tr><tr><td data-num="5"></td><td><pre>connect = stunnel服务端ip<span class="token punctuation">:</span><span class="token number">1081</span></pre></td></tr><tr><td data-num="6"></td><td><pre>client = yes</pre></td></tr><tr><td data-num="7"></td><td><pre>; 需要验证对方发过来的证书</pre></td></tr><tr><td data-num="8"></td><td><pre>;verify = 2</pre></td></tr><tr><td data-num="9"></td><td><pre>; 用来进行证书验证的文件</pre></td></tr><tr><td data-num="10"></td><td><pre>;CAfile = /etc/stunnel/stunnel<span class="token punctuation">-</span>server.pem</pre></td></tr></table></figure><h5 id="clash部分"><a class="anchor" href="#clash部分">#</a> Clash 部分</h5>
<ul>
<li>
<p>1、下载<br />
<span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2NsYXNoLXZlcmdlLXJldi9jbGFzaC12ZXJnZS1yZXY/dGFiPXJlYWRtZS1vdi1maWxl"> Clash 客户端</span></p>
</li>
<li>
<p>2、配置</p>
</li>
</ul>
<p>新建订阅<br />
<img data-src="https://npic.hitoli.com:8443/images/2024/09/29/1e11845b78cb.png" alt="" /></p>
<p>编辑文件并写入以下配置<br />
<img data-src="https://npic.hitoli.com:8443/images/2024/09/29/d4f21f01c4bc.jpg" alt="" /></p>
<figure class="highlight yaml"><figcaption data-lang="YAML"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment"># Profile Template for clash verge</span></pre></td></tr><tr><td data-num="2"></td><td><pre></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token key atrule">proxies</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> <span class="token string">"PROXY"</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token key atrule">type</span><span class="token punctuation">:</span> socks5 <span class="token comment"># 节点类型</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token key atrule">server</span><span class="token punctuation">:</span> <span class="token string">""</span> <span class="token comment"># SOCKS5 服务器地址</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token key atrule">port</span><span class="token punctuation">:</span> <span class="token number">1080</span> <span class="token comment"># 服务器端口</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token key atrule">username</span><span class="token punctuation">:</span> <span class="token string">"proxy"</span> <span class="token comment"># 可选,用户名</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token key atrule">password</span><span class="token punctuation">:</span> <span class="token string">""</span> <span class="token comment"># 可选,密码</span></pre></td></tr><tr><td data-num="10"></td><td><pre></pre></td></tr><tr><td data-num="11"></td><td><pre><span class="token key atrule">rule-providers</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token key atrule">reject</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token key atrule">type</span><span class="token punctuation">:</span> http</pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token key atrule">behavior</span><span class="token punctuation">:</span> domain</pre></td></tr><tr><td data-num="15"></td><td><pre> <span class="token key atrule">url</span><span class="token punctuation">:</span> <span class="token string">"https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/reject.txt"</span></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token key atrule">path</span><span class="token punctuation">:</span> ./ruleset/reject.yaml</pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token key atrule">interval</span><span class="token punctuation">:</span> <span class="token number">86400</span></pre></td></tr><tr><td data-num="18"></td><td><pre></pre></td></tr><tr><td data-num="19"></td><td><pre> <span class="token key atrule">icloud</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token key atrule">type</span><span class="token punctuation">:</span> http</pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token key atrule">behavior</span><span class="token punctuation">:</span> domain</pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token key atrule">url</span><span class="token punctuation">:</span> <span class="token string">"https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/icloud.txt"</span></pre></td></tr><tr><td data-num="23"></td><td><pre> <span class="token key atrule">path</span><span class="token punctuation">:</span> ./ruleset/icloud.yaml</pre></td></tr><tr><td data-num="24"></td><td><pre> <span class="token key atrule">interval</span><span class="token punctuation">:</span> <span class="token number">86400</span></pre></td></tr><tr><td data-num="25"></td><td><pre></pre></td></tr><tr><td data-num="26"></td><td><pre> <span class="token key atrule">apple</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="27"></td><td><pre> <span class="token key atrule">type</span><span class="token punctuation">:</span> http</pre></td></tr><tr><td data-num="28"></td><td><pre> <span class="token key atrule">behavior</span><span class="token punctuation">:</span> domain</pre></td></tr><tr><td data-num="29"></td><td><pre> <span class="token key atrule">url</span><span class="token punctuation">:</span> <span class="token string">"https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/apple.txt"</span></pre></td></tr><tr><td data-num="30"></td><td><pre> <span class="token key atrule">path</span><span class="token punctuation">:</span> ./ruleset/apple.yaml</pre></td></tr><tr><td data-num="31"></td><td><pre> <span class="token key atrule">interval</span><span class="token punctuation">:</span> <span class="token number">86400</span></pre></td></tr><tr><td data-num="32"></td><td><pre></pre></td></tr><tr><td data-num="33"></td><td><pre> <span class="token key atrule">google</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="34"></td><td><pre> <span class="token key atrule">type</span><span class="token punctuation">:</span> http</pre></td></tr><tr><td data-num="35"></td><td><pre> <span class="token key atrule">behavior</span><span class="token punctuation">:</span> domain</pre></td></tr><tr><td data-num="36"></td><td><pre> <span class="token key atrule">url</span><span class="token punctuation">:</span> <span class="token string">"https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/google.txt"</span></pre></td></tr><tr><td data-num="37"></td><td><pre> <span class="token key atrule">path</span><span class="token punctuation">:</span> ./ruleset/google.yaml</pre></td></tr><tr><td data-num="38"></td><td><pre> <span class="token key atrule">interval</span><span class="token punctuation">:</span> <span class="token number">86400</span></pre></td></tr><tr><td data-num="39"></td><td><pre></pre></td></tr><tr><td data-num="40"></td><td><pre> <span class="token key atrule">proxy</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="41"></td><td><pre> <span class="token key atrule">type</span><span class="token punctuation">:</span> http</pre></td></tr><tr><td data-num="42"></td><td><pre> <span class="token key atrule">behavior</span><span class="token punctuation">:</span> domain</pre></td></tr><tr><td data-num="43"></td><td><pre> <span class="token key atrule">url</span><span class="token punctuation">:</span> <span class="token string">"https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/proxy.txt"</span></pre></td></tr><tr><td data-num="44"></td><td><pre> <span class="token key atrule">path</span><span class="token punctuation">:</span> ./ruleset/proxy.yaml</pre></td></tr><tr><td data-num="45"></td><td><pre> <span class="token key atrule">interval</span><span class="token punctuation">:</span> <span class="token number">86400</span></pre></td></tr><tr><td data-num="46"></td><td><pre></pre></td></tr><tr><td data-num="47"></td><td><pre> <span class="token key atrule">direct</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="48"></td><td><pre> <span class="token key atrule">type</span><span class="token punctuation">:</span> http</pre></td></tr><tr><td data-num="49"></td><td><pre> <span class="token key atrule">behavior</span><span class="token punctuation">:</span> domain</pre></td></tr><tr><td data-num="50"></td><td><pre> <span class="token key atrule">url</span><span class="token punctuation">:</span> <span class="token string">"https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/direct.txt"</span></pre></td></tr><tr><td data-num="51"></td><td><pre> <span class="token key atrule">path</span><span class="token punctuation">:</span> ./ruleset/direct.yaml</pre></td></tr><tr><td data-num="52"></td><td><pre> <span class="token key atrule">interval</span><span class="token punctuation">:</span> <span class="token number">86400</span></pre></td></tr><tr><td data-num="53"></td><td><pre></pre></td></tr><tr><td data-num="54"></td><td><pre> <span class="token key atrule">private</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="55"></td><td><pre> <span class="token key atrule">type</span><span class="token punctuation">:</span> http</pre></td></tr><tr><td data-num="56"></td><td><pre> <span class="token key atrule">behavior</span><span class="token punctuation">:</span> domain</pre></td></tr><tr><td data-num="57"></td><td><pre> <span class="token key atrule">url</span><span class="token punctuation">:</span> <span class="token string">"https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/private.txt"</span></pre></td></tr><tr><td data-num="58"></td><td><pre> <span class="token key atrule">path</span><span class="token punctuation">:</span> ./ruleset/private.yaml</pre></td></tr><tr><td data-num="59"></td><td><pre> <span class="token key atrule">interval</span><span class="token punctuation">:</span> <span class="token number">86400</span></pre></td></tr><tr><td data-num="60"></td><td><pre></pre></td></tr><tr><td data-num="61"></td><td><pre> <span class="token key atrule">gfw</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="62"></td><td><pre> <span class="token key atrule">type</span><span class="token punctuation">:</span> http</pre></td></tr><tr><td data-num="63"></td><td><pre> <span class="token key atrule">behavior</span><span class="token punctuation">:</span> domain</pre></td></tr><tr><td data-num="64"></td><td><pre> <span class="token key atrule">url</span><span class="token punctuation">:</span> <span class="token string">"https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/gfw.txt"</span></pre></td></tr><tr><td data-num="65"></td><td><pre> <span class="token key atrule">path</span><span class="token punctuation">:</span> ./ruleset/gfw.yaml</pre></td></tr><tr><td data-num="66"></td><td><pre> <span class="token key atrule">interval</span><span class="token punctuation">:</span> <span class="token number">86400</span></pre></td></tr><tr><td data-num="67"></td><td><pre></pre></td></tr><tr><td data-num="68"></td><td><pre> <span class="token key atrule">tld-not-cn</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="69"></td><td><pre> <span class="token key atrule">type</span><span class="token punctuation">:</span> http</pre></td></tr><tr><td data-num="70"></td><td><pre> <span class="token key atrule">behavior</span><span class="token punctuation">:</span> domain</pre></td></tr><tr><td data-num="71"></td><td><pre> <span class="token key atrule">url</span><span class="token punctuation">:</span> <span class="token string">"https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/tld-not-cn.txt"</span></pre></td></tr><tr><td data-num="72"></td><td><pre> <span class="token key atrule">path</span><span class="token punctuation">:</span> ./ruleset/tld<span class="token punctuation">-</span>not<span class="token punctuation">-</span>cn.yaml</pre></td></tr><tr><td data-num="73"></td><td><pre> <span class="token key atrule">interval</span><span class="token punctuation">:</span> <span class="token number">86400</span></pre></td></tr><tr><td data-num="74"></td><td><pre></pre></td></tr><tr><td data-num="75"></td><td><pre> <span class="token key atrule">telegramcidr</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="76"></td><td><pre> <span class="token key atrule">type</span><span class="token punctuation">:</span> http</pre></td></tr><tr><td data-num="77"></td><td><pre> <span class="token key atrule">behavior</span><span class="token punctuation">:</span> ipcidr</pre></td></tr><tr><td data-num="78"></td><td><pre> <span class="token key atrule">url</span><span class="token punctuation">:</span> <span class="token string">"https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/telegramcidr.txt"</span></pre></td></tr><tr><td data-num="79"></td><td><pre> <span class="token key atrule">path</span><span class="token punctuation">:</span> ./ruleset/telegramcidr.yaml</pre></td></tr><tr><td data-num="80"></td><td><pre> <span class="token key atrule">interval</span><span class="token punctuation">:</span> <span class="token number">86400</span></pre></td></tr><tr><td data-num="81"></td><td><pre></pre></td></tr><tr><td data-num="82"></td><td><pre> <span class="token key atrule">cncidr</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="83"></td><td><pre> <span class="token key atrule">type</span><span class="token punctuation">:</span> http</pre></td></tr><tr><td data-num="84"></td><td><pre> <span class="token key atrule">behavior</span><span class="token punctuation">:</span> ipcidr</pre></td></tr><tr><td data-num="85"></td><td><pre> <span class="token key atrule">url</span><span class="token punctuation">:</span> <span class="token string">"https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/cncidr.txt"</span></pre></td></tr><tr><td data-num="86"></td><td><pre> <span class="token key atrule">path</span><span class="token punctuation">:</span> ./ruleset/cncidr.yaml</pre></td></tr><tr><td data-num="87"></td><td><pre> <span class="token key atrule">interval</span><span class="token punctuation">:</span> <span class="token number">86400</span></pre></td></tr><tr><td data-num="88"></td><td><pre></pre></td></tr><tr><td data-num="89"></td><td><pre> <span class="token key atrule">lancidr</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="90"></td><td><pre> <span class="token key atrule">type</span><span class="token punctuation">:</span> http</pre></td></tr><tr><td data-num="91"></td><td><pre> <span class="token key atrule">behavior</span><span class="token punctuation">:</span> ipcidr</pre></td></tr><tr><td data-num="92"></td><td><pre> <span class="token key atrule">url</span><span class="token punctuation">:</span> <span class="token string">"https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/lancidr.txt"</span></pre></td></tr><tr><td data-num="93"></td><td><pre> <span class="token key atrule">path</span><span class="token punctuation">:</span> ./ruleset/lancidr.yaml</pre></td></tr><tr><td data-num="94"></td><td><pre> <span class="token key atrule">interval</span><span class="token punctuation">:</span> <span class="token number">86400</span></pre></td></tr><tr><td data-num="95"></td><td><pre></pre></td></tr><tr><td data-num="96"></td><td><pre> <span class="token key atrule">applications</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="97"></td><td><pre> <span class="token key atrule">type</span><span class="token punctuation">:</span> http</pre></td></tr><tr><td data-num="98"></td><td><pre> <span class="token key atrule">behavior</span><span class="token punctuation">:</span> classical</pre></td></tr><tr><td data-num="99"></td><td><pre> <span class="token key atrule">url</span><span class="token punctuation">:</span> <span class="token string">"https://cdn.jsdelivr.net/gh/Loyalsoldier/clash-rules@release/applications.txt"</span></pre></td></tr><tr><td data-num="100"></td><td><pre> <span class="token key atrule">path</span><span class="token punctuation">:</span> ./ruleset/applications.yaml</pre></td></tr><tr><td data-num="101"></td><td><pre> <span class="token key atrule">interval</span><span class="token punctuation">:</span> <span class="token number">86400</span></pre></td></tr><tr><td data-num="102"></td><td><pre></pre></td></tr><tr><td data-num="103"></td><td><pre><span class="token key atrule">rules</span><span class="token punctuation">:</span></pre></td></tr><tr><td data-num="104"></td><td><pre> <span class="token punctuation">-</span> RULE<span class="token punctuation">-</span>SET<span class="token punctuation">,</span>applications<span class="token punctuation">,</span>DIRECT</pre></td></tr><tr><td data-num="105"></td><td><pre> <span class="token punctuation">-</span> DOMAIN<span class="token punctuation">,</span>clash.razord.top<span class="token punctuation">,</span>DIRECT</pre></td></tr><tr><td data-num="106"></td><td><pre> <span class="token punctuation">-</span> DOMAIN<span class="token punctuation">,</span>yacd.haishan.me<span class="token punctuation">,</span>DIRECT</pre></td></tr><tr><td data-num="107"></td><td><pre> <span class="token punctuation">-</span> RULE<span class="token punctuation">-</span>SET<span class="token punctuation">,</span>private<span class="token punctuation">,</span>DIRECT</pre></td></tr><tr><td data-num="108"></td><td><pre> <span class="token punctuation">-</span> RULE<span class="token punctuation">-</span>SET<span class="token punctuation">,</span>reject<span class="token punctuation">,</span>REJECT</pre></td></tr><tr><td data-num="109"></td><td><pre> <span class="token punctuation">-</span> RULE<span class="token punctuation">-</span>SET<span class="token punctuation">,</span>icloud<span class="token punctuation">,</span>DIRECT</pre></td></tr><tr><td data-num="110"></td><td><pre> <span class="token punctuation">-</span> RULE<span class="token punctuation">-</span>SET<span class="token punctuation">,</span>apple<span class="token punctuation">,</span>DIRECT</pre></td></tr><tr><td data-num="111"></td><td><pre> <span class="token punctuation">-</span> RULE<span class="token punctuation">-</span>SET<span class="token punctuation">,</span>google<span class="token punctuation">,</span>PROXY</pre></td></tr><tr><td data-num="112"></td><td><pre> <span class="token punctuation">-</span> RULE<span class="token punctuation">-</span>SET<span class="token punctuation">,</span>proxy<span class="token punctuation">,</span>PROXY</pre></td></tr><tr><td data-num="113"></td><td><pre> <span class="token punctuation">-</span> RULE<span class="token punctuation">-</span>SET<span class="token punctuation">,</span>direct<span class="token punctuation">,</span>DIRECT</pre></td></tr><tr><td data-num="114"></td><td><pre> <span class="token punctuation">-</span> RULE<span class="token punctuation">-</span>SET<span class="token punctuation">,</span>lancidr<span class="token punctuation">,</span>DIRECT</pre></td></tr><tr><td data-num="115"></td><td><pre> <span class="token punctuation">-</span> RULE<span class="token punctuation">-</span>SET<span class="token punctuation">,</span>cncidr<span class="token punctuation">,</span>DIRECT</pre></td></tr><tr><td data-num="116"></td><td><pre> <span class="token punctuation">-</span> RULE<span class="token punctuation">-</span>SET<span class="token punctuation">,</span>telegramcidr<span class="token punctuation">,</span>PROXY</pre></td></tr><tr><td data-num="117"></td><td><pre> <span class="token punctuation">-</span> GEOIP<span class="token punctuation">,</span>LAN<span class="token punctuation">,</span>DIRECT</pre></td></tr><tr><td data-num="118"></td><td><pre> <span class="token punctuation">-</span> GEOIP<span class="token punctuation">,</span>CN<span class="token punctuation">,</span>DIRECT</pre></td></tr><tr><td data-num="119"></td><td><pre> <span class="token punctuation">-</span> MATCH<span class="token punctuation">,</span>PROXY</pre></td></tr></table></figure><p>开启代理和自启动<br />
<img data-src="https://npic.hitoli.com:8443/images/2024/09/29/d6c8dfeb5997.png" alt="" /></p>
<div class="note primary">
<p>至次运行 clash 的电脑就可以愉快的科学上网了,并且还可以代理同局域网的其它电脑科学上网。</p>
</div>
2024-09-29T08:25:00.000Z
https://hitoli.com/2024/08/21/%E5%88%A9%E7%94%A8jackson%E5%AF%B9%E8%BF%94%E5%9B%9E%E6%95%B0%E6%8D%AE%E5%81%9A%E5%AD%97%E5%85%B8%E8%BD%AC%E6%8D%A2/
利用jackson对返回数据做字典转换
<h4 id="简介"><a class="anchor" href="#简介">#</a> 简介</h4>
<blockquote>
<p>在项目中经常有一些类型字段用数字或者字母保存,但是前端展示时,则需要转换为用户能够理解的文字。于是公司内有人写了一个公用的注解,利用 java 的反射机制,修改字段的值或者添加属性来实现字典转换。由于 java 是静态类型语言,类在编译时固定,所以无法动态添加属性。于是他的解决方法是先把对象转为 map 再添加属性,或者在定义对象时先预定义字典的属于名称。我在使用中发现如果转换为 map(也可能是拦截处理的时机不对)则会丢失字段上的其它注解,如 swagger 文档定义、时间格式化等等。预设字典属性名称毕竟又增加了一道工序,操作起来也比较繁琐。于是我就想到了在返回阶段利用 jackson 的序列化步骤来对属性进行字典转换。json 对象类似 map 都是键值对,不用担心增减属性的问题。序列化时其它注解也已经处理完成,不会造成影响。</p>
</blockquote>
<h4 id="实现细节"><a class="anchor" href="#实现细节">#</a> 实现细节</h4>
<h6 id="需要的jar"><a class="anchor" href="#需要的jar">#</a> 需要的 jar</h6>
<figure class="highlight java"><figcaption data-lang="java"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token operator"><</span><span class="token operator">!</span><span class="token operator">--</span> 版本根据需求调整 <span class="token operator">--</span><span class="token operator">></span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token generics"><span class="token punctuation"><</span>dependency<span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token generics"><span class="token punctuation"><</span>groupId<span class="token punctuation">></span></span>com<span class="token punctuation">.</span>fasterxml<span class="token punctuation">.</span>jackson<span class="token punctuation">.</span>core<span class="token operator"><</span><span class="token operator">/</span>groupId<span class="token operator">></span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token generics"><span class="token punctuation"><</span>artifactId<span class="token punctuation">></span></span>jackson<span class="token operator">-</span>core<span class="token operator"><</span><span class="token operator">/</span>artifactId<span class="token operator">></span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token generics"><span class="token punctuation"><</span>version<span class="token punctuation">></span></span><span class="token number">2.15</span><span class="token number">.2</span><span class="token operator"><</span><span class="token operator">/</span>version<span class="token operator">></span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token operator"><</span><span class="token operator">/</span>dependency<span class="token operator">></span></pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token generics"><span class="token punctuation"><</span>dependency<span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token generics"><span class="token punctuation"><</span>groupId<span class="token punctuation">></span></span>com<span class="token punctuation">.</span>fasterxml<span class="token punctuation">.</span>jackson<span class="token punctuation">.</span>core<span class="token operator"><</span><span class="token operator">/</span>groupId<span class="token operator">></span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token generics"><span class="token punctuation"><</span>artifactId<span class="token punctuation">></span></span>jackson<span class="token operator">-</span>databind<span class="token operator"><</span><span class="token operator">/</span>artifactId<span class="token operator">></span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token generics"><span class="token punctuation"><</span>version<span class="token punctuation">></span></span><span class="token number">2.15</span><span class="token number">.2</span><span class="token operator"><</span><span class="token operator">/</span>version<span class="token operator">></span> </pre></td></tr><tr><td data-num="11"></td><td><pre><span class="token operator"><</span><span class="token operator">/</span>dependency<span class="token operator">></span></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token generics"><span class="token punctuation"><</span>dependency<span class="token punctuation">></span></span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token generics"><span class="token punctuation"><</span>groupId<span class="token punctuation">></span></span>com<span class="token punctuation">.</span>fasterxml<span class="token punctuation">.</span>jackson<span class="token punctuation">.</span>core<span class="token operator"><</span><span class="token operator">/</span>groupId<span class="token operator">></span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token generics"><span class="token punctuation"><</span>artifactId<span class="token punctuation">></span></span>jackson<span class="token operator">-</span>annotations<span class="token operator"><</span><span class="token operator">/</span>artifactId<span class="token operator">></span></pre></td></tr><tr><td data-num="15"></td><td><pre> <span class="token generics"><span class="token punctuation"><</span>version<span class="token punctuation">></span></span><span class="token number">2.15</span><span class="token number">.2</span><span class="token operator"><</span><span class="token operator">/</span>version<span class="token operator">></span></pre></td></tr><tr><td data-num="16"></td><td><pre><span class="token operator"><</span><span class="token operator">/</span>dependency<span class="token operator">></span></pre></td></tr></table></figure><h6 id="定义注解"><a class="anchor" href="#定义注解">#</a> 定义注解</h6>
<figure class="highlight java"><figcaption data-lang="java"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">enum</span> <span class="token class-name">DicHandleStrategy</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td><pre> replace<span class="token punctuation">,</span></pre></td></tr><tr><td data-num="3"></td><td><pre> add<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token keyword">private</span> <span class="token class-name">DicHandleStrategy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="8"></td><td><pre></pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">com<span class="token punctuation">.</span>fasterxml<span class="token punctuation">.</span>jackson<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">JacksonAnnotationsInside</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">com<span class="token punctuation">.</span>fasterxml<span class="token punctuation">.</span>jackson<span class="token punctuation">.</span>databind<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">JsonSerialize</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">ElementType</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="13"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Retention</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="14"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">RetentionPolicy</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="15"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Target</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="16"></td><td><pre></pre></td></tr><tr><td data-num="17"></td><td><pre><span class="token annotation punctuation">@Target</span><span class="token punctuation">(</span><span class="token punctuation">{</span><span class="token class-name">ElementType</span><span class="token punctuation">.</span><span class="token constant">FIELD</span><span class="token punctuation">,</span> <span class="token class-name">ElementType</span><span class="token punctuation">.</span><span class="token constant">METHOD</span><span class="token punctuation">}</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="18"></td><td><pre><span class="token annotation punctuation">@Retention</span><span class="token punctuation">(</span><span class="token class-name">RetentionPolicy</span><span class="token punctuation">.</span><span class="token constant">RUNTIME</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="19"></td><td><pre><span class="token annotation punctuation">@JacksonAnnotationsInside</span></pre></td></tr><tr><td data-num="20"></td><td><pre><span class="token annotation punctuation">@JsonSerialize</span><span class="token punctuation">(</span>using <span class="token operator">=</span> <span class="token class-name">JsonDicHandle</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="21"></td><td><pre><span class="token keyword">public</span> <span class="token annotation punctuation">@interface</span> <span class="token class-name">JsonDicField</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="22"></td><td><pre></pre></td></tr><tr><td data-num="23"></td><td><pre> <span class="token comment">/**</pre></td></tr><tr><td data-num="24"></td><td><pre> * 业务表名</pre></td></tr><tr><td data-num="25"></td><td><pre> * @return</pre></td></tr><tr><td data-num="26"></td><td><pre> */</span></pre></td></tr><tr><td data-num="27"></td><td><pre> <span class="token class-name">String</span> <span class="token function">tableName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">default</span> <span class="token string">""</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="28"></td><td><pre></pre></td></tr><tr><td data-num="29"></td><td><pre> <span class="token comment">/**</pre></td></tr><tr><td data-num="30"></td><td><pre> * 业务字段名</pre></td></tr><tr><td data-num="31"></td><td><pre> * @return</pre></td></tr><tr><td data-num="32"></td><td><pre> */</span></pre></td></tr><tr><td data-num="33"></td><td><pre> <span class="token class-name">String</span> <span class="token function">fieldName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">default</span> <span class="token string">""</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="34"></td><td><pre></pre></td></tr><tr><td data-num="35"></td><td><pre> <span class="token comment">/**</pre></td></tr><tr><td data-num="36"></td><td><pre> * 默认增加一个对应属性名加_dic 的新属性(如 type_dic)* newFieldName 为空的情况下</pre></td></tr><tr><td data-num="37"></td><td><pre> * @return</pre></td></tr><tr><td data-num="38"></td><td><pre> */</span></pre></td></tr><tr><td data-num="39"></td><td><pre> <span class="token class-name">DicHandleStrategy</span> <span class="token function">strategy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">default</span> <span class="token class-name">DicHandleStrategy</span><span class="token punctuation">.</span>add<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="40"></td><td><pre></pre></td></tr><tr><td data-num="41"></td><td><pre> <span class="token comment">/**</pre></td></tr><tr><td data-num="42"></td><td><pre> * 字典属性名称(如不指定,并且 strategy 为 add 的情况下则字典名称默认为原属性加_dic)</pre></td></tr><tr><td data-num="43"></td><td><pre> * @return</pre></td></tr><tr><td data-num="44"></td><td><pre> */</span></pre></td></tr><tr><td data-num="45"></td><td><pre> <span class="token class-name">String</span> <span class="token function">newFieldName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">default</span> <span class="token string">""</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="46"></td><td><pre></pre></td></tr><tr><td data-num="47"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><h6 id="注解处理"><a class="anchor" href="#注解处理">#</a> 注解处理</h6>
<figure class="highlight java"><figcaption data-lang="java"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span></span><span class="token class-name">BeansException</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span></span><span class="token class-name">NoSuchBeanDefinitionException</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span></span><span class="token class-name">ApplicationContext</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span></span><span class="token class-name">ApplicationContextAware</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Timer</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">TimerTask</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre></pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SpringContextUtil</span> <span class="token keyword">implements</span> <span class="token class-name">ApplicationContextAware</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token class-name">ApplicationContext</span> applicationContext<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setApplicationContext</span><span class="token punctuation">(</span><span class="token class-name">ApplicationContext</span> applicationContext<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token class-name">SpringContextUtil</span><span class="token punctuation">.</span>applicationContext <span class="token operator">=</span> applicationContext<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="15"></td><td><pre></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">ApplicationContext</span> <span class="token function">getApplicationContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token keyword">return</span> applicationContext<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="19"></td><td><pre></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">Object</span> <span class="token function">getBean</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token keyword">return</span> applicationContext<span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="23"></td><td><pre></pre></td></tr><tr><td data-num="24"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">Object</span> <span class="token function">getBean</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">,</span> <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation"><</span><span class="token operator">?</span><span class="token punctuation">></span></span> requiredType<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="25"></td><td><pre> <span class="token keyword">return</span> applicationContext<span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> requiredType<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="26"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="27"></td><td><pre></pre></td></tr><tr><td data-num="28"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">Object</span> <span class="token function">getBean</span><span class="token punctuation">(</span><span class="token class-name">Class</span><span class="token generics"><span class="token punctuation"><</span><span class="token operator">?</span><span class="token punctuation">></span></span> requiredType<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">BeansException</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="29"></td><td><pre> <span class="token keyword">return</span> applicationContext<span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span>requiredType<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="30"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="31"></td><td><pre></pre></td></tr><tr><td data-num="32"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">boolean</span> <span class="token function">containsBean</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="33"></td><td><pre> <span class="token keyword">return</span> applicationContext<span class="token punctuation">.</span><span class="token function">containsBean</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="34"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="35"></td><td><pre></pre></td></tr><tr><td data-num="36"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">boolean</span> <span class="token function">isSingleton</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">NoSuchBeanDefinitionException</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="37"></td><td><pre> <span class="token keyword">return</span> applicationContext<span class="token punctuation">.</span><span class="token function">isSingleton</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="38"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="39"></td><td><pre></pre></td></tr><tr><td data-num="40"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation"><</span><span class="token operator">?</span><span class="token punctuation">></span></span> <span class="token function">getType</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">NoSuchBeanDefinitionException</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="41"></td><td><pre> <span class="token keyword">return</span> applicationContext<span class="token punctuation">.</span><span class="token function">getType</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="42"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="43"></td><td><pre></pre></td></tr><tr><td data-num="44"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token function">getAliases</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">NoSuchBeanDefinitionException</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="45"></td><td><pre> <span class="token keyword">return</span> applicationContext<span class="token punctuation">.</span><span class="token function">getAliases</span><span class="token punctuation">(</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="46"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="47"></td><td><pre><span class="token punctuation">}</span></pre></td></tr><tr><td data-num="48"></td><td><pre></pre></td></tr><tr><td data-num="49"></td><td><pre></pre></td></tr><tr><td data-num="50"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">com<span class="token punctuation">.</span>fasterxml<span class="token punctuation">.</span>jackson<span class="token punctuation">.</span>core<span class="token punctuation">.</span></span><span class="token class-name">JsonGenerator</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="51"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">com<span class="token punctuation">.</span>fasterxml<span class="token punctuation">.</span>jackson<span class="token punctuation">.</span>databind<span class="token punctuation">.</span></span><span class="token class-name">BeanProperty</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="52"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">com<span class="token punctuation">.</span>fasterxml<span class="token punctuation">.</span>jackson<span class="token punctuation">.</span>databind<span class="token punctuation">.</span></span><span class="token class-name">JsonMappingException</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="53"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">com<span class="token punctuation">.</span>fasterxml<span class="token punctuation">.</span>jackson<span class="token punctuation">.</span>databind<span class="token punctuation">.</span></span><span class="token class-name">JsonSerializer</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="54"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">com<span class="token punctuation">.</span>fasterxml<span class="token punctuation">.</span>jackson<span class="token punctuation">.</span>databind<span class="token punctuation">.</span></span><span class="token class-name">SerializerProvider</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="55"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">com<span class="token punctuation">.</span>fasterxml<span class="token punctuation">.</span>jackson<span class="token punctuation">.</span>databind<span class="token punctuation">.</span>ser<span class="token punctuation">.</span></span><span class="token class-name">ContextualSerializer</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="56"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">com<span class="token punctuation">.</span>ys<span class="token punctuation">.</span>szygl<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">SpringContextUtil</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="57"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>commons<span class="token punctuation">.</span>collections<span class="token punctuation">.</span></span><span class="token class-name">CollectionUtils</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="58"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>commons<span class="token punctuation">.</span>collections<span class="token punctuation">.</span></span><span class="token class-name">MapUtils</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="59"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>apache<span class="token punctuation">.</span>commons<span class="token punctuation">.</span>lang3<span class="token punctuation">.</span></span><span class="token class-name">StringUtils</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="60"></td><td><pre></pre></td></tr><tr><td data-num="61"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span><span class="token class-name">IOException</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="62"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token operator">*</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="63"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>stream<span class="token punctuation">.</span></span><span class="token class-name">Collectors</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="64"></td><td><pre></pre></td></tr><tr><td data-num="65"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">JsonDicHandle</span> <span class="token keyword">extends</span> <span class="token class-name">JsonSerializer</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Object</span><span class="token punctuation">></span></span> <span class="token keyword">implements</span> <span class="token class-name">ContextualSerializer</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="66"></td><td><pre></pre></td></tr><tr><td data-num="67"></td><td><pre> <span class="token keyword">final</span> <span class="token class-name">String</span> <span class="token constant">DIC_FIELD_SUFFIX</span> <span class="token operator">=</span> <span class="token string">"_dic"</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="68"></td><td><pre></pre></td></tr><tr><td data-num="69"></td><td><pre> <span class="token class-name">String</span> tableName <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="70"></td><td><pre></pre></td></tr><tr><td data-num="71"></td><td><pre> <span class="token class-name">String</span> fieldName <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="72"></td><td><pre></pre></td></tr><tr><td data-num="73"></td><td><pre> <span class="token class-name">DicHandleStrategy</span> strategy <span class="token operator">=</span> <span class="token class-name">DicHandleStrategy</span><span class="token punctuation">.</span>add<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="74"></td><td><pre></pre></td></tr><tr><td data-num="75"></td><td><pre> <span class="token class-name">String</span> newFieldName <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="76"></td><td><pre></pre></td></tr><tr><td data-num="77"></td><td><pre> <span class="token class-name">String</span> propertyName <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="78"></td><td><pre></pre></td></tr><tr><td data-num="79"></td><td><pre> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">IDicService</span> iDicService <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">IDicService</span><span class="token punctuation">)</span><span class="token class-name">SpringContextUtil</span><span class="token punctuation">.</span><span class="token function">getBean</span><span class="token punctuation">(</span><span class="token class-name">IDicService</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="80"></td><td><pre></pre></td></tr><tr><td data-num="81"></td><td><pre> <span class="token keyword">public</span> <span class="token class-name">JsonDicHandle</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="82"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="83"></td><td><pre></pre></td></tr><tr><td data-num="84"></td><td><pre> <span class="token keyword">public</span> <span class="token class-name">JsonDicHandle</span><span class="token punctuation">(</span><span class="token class-name">String</span> tableName<span class="token punctuation">,</span> <span class="token class-name">String</span> fieldName<span class="token punctuation">,</span> <span class="token class-name">DicHandleStrategy</span> strategy<span class="token punctuation">,</span> <span class="token class-name">String</span> newFieldName<span class="token punctuation">,</span> <span class="token class-name">String</span> propertyName<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="85"></td><td><pre> <span class="token keyword">this</span><span class="token punctuation">.</span>tableName <span class="token operator">=</span> tableName<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="86"></td><td><pre> <span class="token keyword">this</span><span class="token punctuation">.</span>fieldName <span class="token operator">=</span> fieldName<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="87"></td><td><pre> <span class="token keyword">this</span><span class="token punctuation">.</span>strategy <span class="token operator">=</span> strategy<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="88"></td><td><pre> <span class="token keyword">this</span><span class="token punctuation">.</span>newFieldName <span class="token operator">=</span> newFieldName<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="89"></td><td><pre> <span class="token keyword">this</span><span class="token punctuation">.</span>propertyName <span class="token operator">=</span> propertyName<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="90"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="91"></td><td><pre></pre></td></tr><tr><td data-num="92"></td><td><pre> <span class="token annotation punctuation">@Override</span></pre></td></tr><tr><td data-num="93"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">serialize</span><span class="token punctuation">(</span><span class="token class-name">Object</span> value<span class="token punctuation">,</span> <span class="token class-name">JsonGenerator</span> gen<span class="token punctuation">,</span> <span class="token class-name">SerializerProvider</span> serializers<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="94"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">isBlank</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>newFieldName<span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">isNotBlank</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>propertyName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="95"></td><td><pre> <span class="token keyword">this</span><span class="token punctuation">.</span>newFieldName <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>propertyName <span class="token operator">+</span> <span class="token constant">DIC_FIELD_SUFFIX</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="96"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="97"></td><td><pre> <span class="token class-name">String</span> dicValue <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="98"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">nonNull</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="99"></td><td><pre> dicValue <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getDicValue</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>tableName<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>fieldName<span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="100"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">DicHandleStrategy</span><span class="token punctuation">.</span>replace<span class="token punctuation">.</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>strategy<span class="token punctuation">.</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="101"></td><td><pre> gen<span class="token punctuation">.</span><span class="token function">writeObject</span><span class="token punctuation">(</span>dicValue<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="102"></td><td><pre> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="103"></td><td><pre> gen<span class="token punctuation">.</span><span class="token function">writeObject</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="104"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="105"></td><td><pre> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="106"></td><td><pre> gen<span class="token punctuation">.</span><span class="token function">writeObject</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="107"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="108"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">DicHandleStrategy</span><span class="token punctuation">.</span>add<span class="token punctuation">.</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>strategy<span class="token punctuation">.</span><span class="token function">name</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token class-name">StringUtils</span><span class="token punctuation">.</span><span class="token function">isNotBlank</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>newFieldName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="109"></td><td><pre> gen<span class="token punctuation">.</span><span class="token function">writeStringField</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>newFieldName<span class="token punctuation">,</span> dicValue<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="110"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="111"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="112"></td><td><pre></pre></td></tr><tr><td data-num="113"></td><td><pre> <span class="token annotation punctuation">@Override</span></pre></td></tr><tr><td data-num="114"></td><td><pre> <span class="token keyword">public</span> <span class="token class-name">JsonSerializer</span><span class="token generics"><span class="token punctuation"><</span><span class="token operator">?</span><span class="token punctuation">></span></span> <span class="token function">createContextual</span><span class="token punctuation">(</span><span class="token class-name">SerializerProvider</span> prov<span class="token punctuation">,</span> <span class="token class-name">BeanProperty</span> property<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">JsonMappingException</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="115"></td><td><pre> <span class="token class-name">JsonDicField</span> annotation <span class="token operator">=</span> property<span class="token punctuation">.</span><span class="token function">getAnnotation</span><span class="token punctuation">(</span><span class="token class-name">JsonDicField</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="116"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">nonNull</span><span class="token punctuation">(</span>annotation<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="117"></td><td><pre> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">JsonDicHandle</span><span class="token punctuation">(</span>annotation<span class="token punctuation">.</span><span class="token function">tableName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> annotation<span class="token punctuation">.</span><span class="token function">fieldName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> annotation<span class="token punctuation">.</span><span class="token function">strategy</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="118"></td><td><pre> annotation<span class="token punctuation">.</span><span class="token function">newFieldName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> property<span class="token punctuation">.</span><span class="token function">getName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="119"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="120"></td><td><pre> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">JsonDicHandle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="121"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="122"></td><td><pre></pre></td></tr><tr><td data-num="123"></td><td><pre> <span class="token comment">/**</pre></td></tr><tr><td data-num="124"></td><td><pre> * 把值转为字典值</pre></td></tr><tr><td data-num="125"></td><td><pre> * @param value</pre></td></tr><tr><td data-num="126"></td><td><pre> * @return</pre></td></tr><tr><td data-num="127"></td><td><pre> */</span></pre></td></tr><tr><td data-num="128"></td><td><pre> <span class="token keyword">private</span> <span class="token class-name">String</span> <span class="token function">getDicValue</span><span class="token punctuation">(</span><span class="token class-name">String</span> tableName<span class="token punctuation">,</span> <span class="token class-name">String</span> fieldName<span class="token punctuation">,</span> <span class="token class-name">String</span> value<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="129"></td><td><pre> <span class="token class-name">String</span> dicValue <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="130"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">nonNull</span><span class="token punctuation">(</span>iDicService<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="131"></td><td><pre> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">></span></span> dicMap <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>iDicService<span class="token punctuation">.</span><span class="token function">getDicMapFromCatch</span><span class="token punctuation">(</span>tableName<span class="token punctuation">,</span> fieldName<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="132"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">MapUtils</span><span class="token punctuation">.</span><span class="token function">isNotEmpty</span><span class="token punctuation">(</span>dicMap<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="133"></td><td><pre> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">></span></span> dicValues <span class="token operator">=</span> <span class="token class-name">Arrays</span><span class="token punctuation">.</span><span class="token function">stream</span><span class="token punctuation">(</span>value<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>s <span class="token operator">-></span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="134"></td><td><pre> <span class="token keyword">return</span> <span class="token class-name">Optional</span><span class="token punctuation">.</span><span class="token function">ofNullable</span><span class="token punctuation">(</span>dicMap<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token operator">::</span><span class="token function">valueOf</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">orElse</span><span class="token punctuation">(</span><span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="135"></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">collect</span><span class="token punctuation">(</span><span class="token class-name">Collectors</span><span class="token punctuation">.</span><span class="token function">toList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="136"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">CollectionUtils</span><span class="token punctuation">.</span><span class="token function">isNotEmpty</span><span class="token punctuation">(</span>dicValues<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="137"></td><td><pre> dicValue <span class="token operator">=</span> <span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token string">","</span><span class="token punctuation">,</span> dicValues<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="138"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="139"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="140"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="141"></td><td><pre> <span class="token keyword">return</span> dicValue<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="142"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="143"></td><td><pre></pre></td></tr><tr><td data-num="144"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><h6 id="其它"><a class="anchor" href="#其它">#</a> 其它</h6>
<blockquote>
<p>IDicService 是自己的字典缓存服务,利用 tableName 和 fieldName 来定位属性的对应字典名称。请根据自己的业务逻辑进行修改。</p>
</blockquote>
2024-08-21T02:00:00.000Z
https://hitoli.com/2024/06/25/idea-%E4%B8%BB%E9%A2%98-%E4%BB%A3%E7%A0%81%E9%A2%9C%E8%89%B2-%E4%BB%A3%E7%A0%81%E5%8C%BA%E8%83%8C%E6%99%AF-%E8%A1%8C%E5%8F%B7%E8%83%8C%E6%99%AF-%E6%B3%A8%E9%87%8A%E9%A2%9C%E8%89%B2%E4%BF%AE%E6%94%B9/
idea 主题 代码颜色 代码区背景 行号背景 注释颜色修改
<h4 id="简介"><a class="anchor" href="#简介">#</a> 简介</h4>
<blockquote>
<p>最近写代码眼睛总是看的不舒服,想着换一个主题,但是换了主题,代码的颜色显示和之前又不一样了,接下来就是修改主题,但是代码颜色仍然保持 Darcula 主题的颜色。</p>
</blockquote>
<h4 id="修改主题"><a class="anchor" href="#修改主题">#</a> 修改主题</h4>
<p>我这里用的是 <span class="red">One Dark theme</span> 可以直接去下载这个插件<br />
<img data-src="https://npic.hitoli.com:8443/images/2024/06/25/c4ad60fe33ac.png" alt="" /></p>
<h4 id="修改代码颜色与背景"><a class="anchor" href="#修改代码颜色与背景">#</a> 修改代码颜色与背景</h4>
<ol>
<li>代码颜色<br />
这里只修改代码颜色的话,idea 整体背景将不统一,看着非常难受,因此不仅要修改代码颜色,还要修改与当前主题相同的背景颜色。<br />
<img data-src="https://npic.hitoli.com:8443/images/2024/06/25/18141ff20abc.png" alt="" /><br />
这里直接修改为 Darcula ,那么整体的代码颜色风格都会变成 Darcula,但是代码区域的背景颜色也会变成 Darcula ,使得 idea 背景一体性破坏。</li>
<li>代码区背景<br />
<img data-src="https://npic.hitoli.com:8443/images/2024/06/25/b70f144b887f.png" alt="" /><br />
这里如果你用的跟我一样的 One Dark theme ,那么你就可以修改颜色为 21252B 这样代码区颜色就会和主题相一致,但是到这里你会发现,行号区域的颜色又不一样了。</li>
</ol>
<h4 id="修改行号背景"><a class="anchor" href="#修改行号背景">#</a> 修改行号背景</h4>
<p><img data-src="https://npic.hitoli.com:8443/images/2024/06/25/89836b9fdd65.png" alt="" /><br />
这里按照相同的方法修改,即可达到整体的一致性。</p>
<h4 id="修改注释颜色"><a class="anchor" href="#修改注释颜色">#</a> 修改注释颜色</h4>
<p>这里就是个人习惯了,我习惯注释都是绿色的,清晰明了。<br />
<img data-src="https://npic.hitoli.com:8443/images/2024/06/25/974673f11984.png" alt="" /><br />
这里提供一个参考 629755 ,我个人比较喜欢这个颜色。</p>
<h4 id="鼠标悬停代码提示框背景修改"><a class="anchor" href="#鼠标悬停代码提示框背景修改">#</a> 鼠标悬停代码提示框背景修改</h4>
<p><img data-src="https://npic.hitoli.com:8443/images/2024/06/25/f9dc4b6e63ce.png" alt="" /><br />
<img data-src="https://npic.hitoli.com:8443/images/2024/06/25/5b1ec78282db.png" alt="" /></p>
<h4 id="代码快捷提示框背景颜色修改"><a class="anchor" href="#代码快捷提示框背景颜色修改">#</a> 代码快捷提示框背景颜色修改</h4>
<p><img data-src="https://npic.hitoli.com:8443/images/2024/06/25/af59bb847efd.png" alt="" /><br />
<img data-src="https://npic.hitoli.com:8443/images/2024/06/25/31b7512149f7.png" alt="" /></p>
2024-06-25T08:03:00.000Z
https://hitoli.com/2024/05/22/%E5%AF%B9XML%E6%A0%BC%E5%BC%8F%E7%9A%84Word%E6%A8%A1%E6%9D%BF%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%A4%84%E7%90%86/
对XML格式的Word模板格式化处理
<h4 id="简介"><a class="anchor" href="#简介">#</a> 简介</h4>
<blockquote>
<p>生成复杂的 word 文档需要使用 xml 格式的 word 模板,但是另存为 xml 文件的 word 文件格式比较杂乱。现提供一个格式化 xml 的工具类,代码如下:</p>
</blockquote>
<figure class="highlight java"><figcaption data-lang="java"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">package</span> <span class="token namespace">xxx<span class="token punctuation">.</span>util</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="2"></td><td><pre></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">cn<span class="token punctuation">.</span>hutool<span class="token punctuation">.</span>core<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span><span class="token class-name">FileUtil</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">cn<span class="token punctuation">.</span>hutool<span class="token punctuation">.</span>core<span class="token punctuation">.</span>io<span class="token punctuation">.</span>file<span class="token punctuation">.</span></span><span class="token class-name">FileAppender</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">cn<span class="token punctuation">.</span>hutool<span class="token punctuation">.</span>core<span class="token punctuation">.</span>io<span class="token punctuation">.</span>file<span class="token punctuation">.</span></span><span class="token class-name">FileReader</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre></pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">List</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre></pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">WordConvertXmlHandle</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="10"></td><td><pre></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token comment">// 文件读取 - FileReader</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token comment">// 默认 UTF-8 编码,可以在构造中传入第二个参数作为编码</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token class-name">FileReader</span> fileReader <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileReader</span><span class="token punctuation">(</span><span class="token string">"D:\\mb.xml"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="15"></td><td><pre> <span class="token comment">// 从文件中读取每一行数据</span></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">></span></span> strings <span class="token operator">=</span> fileReader<span class="token punctuation">.</span><span class="token function">readLines</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token comment">// 文件追加 - FileAppender</span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token comment">//destFile – 目标文件</span></pre></td></tr><tr><td data-num="19"></td><td><pre> <span class="token comment">//capacity – 当行数积累多少条时刷入到文件</span></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token comment">//isNewLineMode – 追加内容是否为新行</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token class-name">FileAppender</span> appender <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileAppender</span><span class="token punctuation">(</span><span class="token class-name">FileUtil</span><span class="token punctuation">.</span><span class="token function">newFile</span><span class="token punctuation">(</span><span class="token string">"D:\\mb.ftl"</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">16</span><span class="token punctuation">,</span> <span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token comment">// 遍历得到每一行数据</span></pre></td></tr><tr><td data-num="23"></td><td><pre> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">String</span> string <span class="token operator">:</span> strings<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="24"></td><td><pre> <span class="token comment">// 判断每一行数据中不包含 '$' 的数据先添加进新文件</span></pre></td></tr><tr><td data-num="25"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>string<span class="token punctuation">.</span><span class="token function">contains</span><span class="token punctuation">(</span><span class="token string">"$"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="26"></td><td><pre> appender<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>string<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="27"></td><td><pre> <span class="token keyword">continue</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="28"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="29"></td><td><pre> <span class="token comment">// 如果一行数据中包含 '$' 变量符将替换为 '#$'</span></pre></td></tr><tr><td data-num="30"></td><td><pre> string <span class="token operator">=</span> string<span class="token punctuation">.</span><span class="token function">replaceAll</span><span class="token punctuation">(</span><span class="token string">"\\$"</span><span class="token punctuation">,</span> <span class="token string">"#\\$"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="31"></td><td><pre> <span class="token comment">// 然后以 '#' 切割成每一行(数组), 这样一来 '$' 都将在每一行的开头</span></pre></td></tr><tr><td data-num="32"></td><td><pre> <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> ss <span class="token operator">=</span> string<span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">"#"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="33"></td><td><pre> <span class="token comment">// 同一行的数据写到同一行,文件追加自动换行了 (最后的完整数据)</span></pre></td></tr><tr><td data-num="34"></td><td><pre> <span class="token class-name">StringBuilder</span> sb <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">StringBuilder</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="35"></td><td><pre> <span class="token comment">// 遍历每一行(数组 ss)</span></pre></td></tr><tr><td data-num="36"></td><td><pre> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> ss<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="37"></td><td><pre> <span class="token comment">// 暂存数据</span></pre></td></tr><tr><td data-num="38"></td><td><pre> <span class="token class-name">String</span> s1 <span class="token operator">=</span> ss<span class="token punctuation">[</span>i<span class="token punctuation">]</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="39"></td><td><pre> <span class="token comment">// 将不是以 '$' 开头的行数据放进 StringBuilder</span></pre></td></tr><tr><td data-num="40"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>s1<span class="token punctuation">.</span><span class="token function">startsWith</span><span class="token punctuation">(</span><span class="token string">"$"</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="41"></td><td><pre> sb<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>s1<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="42"></td><td><pre> <span class="token keyword">continue</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="43"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="44"></td><td><pre> <span class="token comment">// 被分离的数据一般都是 '${' 这样被分开</span></pre></td></tr><tr><td data-num="45"></td><td><pre> <span class="token comment">// 匹配以 '$' 开头的变量找到 '}' 得到索引位置</span></pre></td></tr><tr><td data-num="46"></td><td><pre> <span class="token keyword">int</span> i1 <span class="token operator">=</span> s1<span class="token punctuation">.</span><span class="token function">lastIndexOf</span><span class="token punctuation">(</span><span class="token string">"}"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="47"></td><td><pre> <span class="token comment">// 先切割得到这个完整体</span></pre></td></tr><tr><td data-num="48"></td><td><pre> <span class="token class-name">String</span> substr <span class="token operator">=</span> s1<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> i1 <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="49"></td><td><pre> <span class="token comment">// 把变量追加到 StringBuilder</span></pre></td></tr><tr><td data-num="50"></td><td><pre> sb<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>substr<span class="token punctuation">.</span><span class="token function">replaceAll</span><span class="token punctuation">(</span><span class="token string">"<[^>]+>"</span><span class="token punctuation">,</span> <span class="token string">""</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="51"></td><td><pre> <span class="token comment">// 再将标签数据追加到 StringBuilder 包裹变量</span></pre></td></tr><tr><td data-num="52"></td><td><pre> sb<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>s1<span class="token punctuation">.</span><span class="token function">substring</span><span class="token punctuation">(</span>i1 <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="53"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="54"></td><td><pre> appender<span class="token punctuation">.</span><span class="token function">append</span><span class="token punctuation">(</span>sb<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="55"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="56"></td><td><pre> appender<span class="token punctuation">.</span><span class="token function">flush</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="57"></td><td><pre> appender<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="58"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="59"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure>
2024-05-22T07:43:00.000Z
https://hitoli.com/2024/05/10/MySQL%E8%A1%A8%E5%88%86%E5%8C%BA/
MySQL表分区
<h4 id="简介"><a class="anchor" href="#简介">#</a> 简介</h4>
<blockquote>
<p>当单表数据量过大时,就需要考虑对表进行分表或者分区了。分表和分区都是用来解决数据库中大量数据存储和查询效率的问题,但它们的实现方式和解决的问题有所不同。</p>
</blockquote>
<blockquote>
<p>分表(Sharding):</p>
</blockquote>
<ul>
<li>分表是将一个大表按照某种规则拆分成多个较小的表,每个小表称为一个分表,这些分表可以分布在不同的数据库实例中。</li>
<li>分表通常基于某种规则进行拆分,例如按照用户 ID、地理位置等进行拆分。</li>
<li>分表的主要目的是解决单个表过大的问题,提高查询效率和并发能力。</li>
</ul>
<blockquote>
<p>分区(Partitioning):</p>
</blockquote>
<ul>
<li>分区是将一个表按照某种规则拆分成多个逻辑上的部分,每个部分称为一个分区,但这些分区仍然属于同一个表。</li>
<li>分区通常基于某种规则进行拆分,例如按照时间、范围、哈希值等进行拆分。</li>
<li>分区的主要目的是提高数据的管理和查询效率,通过将数据分散到不同的分区中,可以提高查询性能和管理灵活性。</li>
</ul>
<blockquote>
<p>区别:</p>
</blockquote>
<ul>
<li>实现方式:分表是将一个表拆分成多个子表,每个子表都是一个独立的表;而分区是将一个表按照某种规则拆分成多个逻辑上的部分,这些部分仍然属于同一个表。</li>
<li>解决的问题:分表主要解决单个表过大的问题,提高查询效率和并发能力;而分区主要提高数据的管理和查询效率,通过将数据分散到不同的分区中,可以提高查询性能和管理灵活性。</li>
<li>适用场景:分表适用于单表数据量巨大的情况,例如大型电商平台的订单表;而分区适用于需要根据某种规则对数据进行划分管理的情况,例如按照时间对日志表进行分区。</li>
</ul>
<h4 id="实现细节"><a class="anchor" href="#实现细节">#</a> 实现细节</h4>
<blockquote>
<p>本文章介绍的是如何对单表进行分区。</p>
</blockquote>
<h6 id="给表添加分区"><a class="anchor" href="#给表添加分区">#</a> 给表添加分区</h6>
<figure class="highlight sql"><figcaption data-lang="SQL"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">ALTER</span> <span class="token keyword">TABLE</span> 表名(字段)</pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token keyword">PARTITION</span> <span class="token keyword">BY</span> RANGE <span class="token keyword">COLUMNS</span> <span class="token punctuation">(</span>时间字段名<span class="token punctuation">)</span> <span class="token punctuation">(</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token comment">-- 分区条件(时间小于 2022-02-01 的数据放入 p202201 分区中)</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token keyword">PARTITION</span> p202201 <span class="token keyword">VALUES</span> LESS THAN <span class="token punctuation">(</span><span class="token string">'2022-02-01'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token keyword">PARTITION</span> p202202 <span class="token keyword">VALUES</span> LESS THAN <span class="token punctuation">(</span><span class="token string">'2022-03-01'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token keyword">PARTITION</span> p202203 <span class="token keyword">VALUES</span> LESS THAN <span class="token punctuation">(</span><span class="token string">'2022-04-01'</span><span class="token punctuation">)</span><span class="token punctuation">,</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token comment">-- 继续定义更多的分区...</span></pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr></table></figure><h6 id="按指定表名创建当前年月的分区"><a class="anchor" href="#按指定表名创建当前年月的分区">#</a> 按指定表名创建当前年月的分区</h6>
<figure class="highlight sql"><figcaption data-lang="SQL"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">CREATE</span> <span class="token keyword">PROCEDURE</span> create_monthly_partition<span class="token punctuation">(</span><span class="token operator">IN</span> tableName <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token keyword">BEGIN</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token keyword">DECLARE</span> currentYear <span class="token keyword">INT</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token keyword">DECLARE</span> currentMonth <span class="token keyword">INT</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token keyword">DECLARE</span> nextYear <span class="token keyword">INT</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token keyword">DECLARE</span> nextMonth <span class="token keyword">INT</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token keyword">DECLARE</span> partitionName <span class="token keyword">VARCHAR</span><span class="token punctuation">(</span><span class="token number">255</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token keyword">SET</span> currentYear <span class="token operator">=</span> <span class="token keyword">YEAR</span><span class="token punctuation">(</span><span class="token keyword">CURRENT_DATE</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token keyword">SET</span> currentMonth <span class="token operator">=</span> <span class="token keyword">MONTH</span><span class="token punctuation">(</span><span class="token keyword">CURRENT_DATE</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token comment">-- 计算下一个月的年份和月份</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token keyword">IF</span> currentMonth <span class="token operator">=</span> <span class="token number">12</span> <span class="token keyword">THEN</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token keyword">SET</span> nextYear <span class="token operator">=</span> currentYear <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token keyword">SET</span> nextMonth <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token keyword">ELSE</span></pre></td></tr><tr><td data-num="15"></td><td><pre> <span class="token keyword">SET</span> nextYear <span class="token operator">=</span> currentYear<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token keyword">SET</span> nextMonth <span class="token operator">=</span> currentMonth <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token keyword">END</span> <span class="token keyword">IF</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token keyword">SET</span> partitionName <span class="token operator">=</span> CONCAT<span class="token punctuation">(</span><span class="token string">'p'</span><span class="token punctuation">,</span> currentYear<span class="token punctuation">,</span> LPAD<span class="token punctuation">(</span>currentMonth<span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="19"></td><td><pre> <span class="token keyword">SET</span> <span class="token variable">@sql</span> <span class="token operator">=</span> CONCAT<span class="token punctuation">(</span><span class="token string">'ALTER TABLE '</span><span class="token punctuation">,</span> tableName<span class="token punctuation">,</span> </pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token string">' ADD PARTITION (PARTITION '</span><span class="token punctuation">,</span> partitionName<span class="token punctuation">,</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token string">' VALUES LESS THAN (\''</span><span class="token punctuation">,</span> nextYear<span class="token punctuation">,</span> <span class="token string">'-'</span><span class="token punctuation">,</span> LPAD<span class="token punctuation">(</span>nextMonth<span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'-01\''</span><span class="token punctuation">,</span> <span class="token string">'))'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token keyword">PREPARE</span> stmt <span class="token keyword">FROM</span> <span class="token variable">@sql</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="23"></td><td><pre> <span class="token keyword">EXECUTE</span> stmt<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="24"></td><td><pre> <span class="token keyword">DEALLOCATE</span> <span class="token keyword">PREPARE</span> stmt<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="25"></td><td><pre><span class="token keyword">END</span></pre></td></tr></table></figure><h6 id="调用创建新分区"><a class="anchor" href="#调用创建新分区">#</a> 调用创建新分区</h6>
<figure class="highlight sql"><figcaption data-lang="SQL"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">CALL</span> create_monthly_partition<span class="token punctuation">(</span><span class="token string">'表名'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr></table></figure><h6 id="删除指定分区"><a class="anchor" href="#删除指定分区">#</a> 删除指定分区</h6>
<figure class="highlight sql"><figcaption data-lang="SQL"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">ALTER</span> <span class="token keyword">TABLE</span> 表名 <span class="token keyword">drop</span> <span class="token keyword">PARTITION</span> 分区名<span class="token punctuation">;</span></pre></td></tr></table></figure><h6 id="每月执行一次调用指定表添加新分区"><a class="anchor" href="#每月执行一次调用指定表添加新分区">#</a> 每月执行一次调用指定表添加新分区</h6>
<figure class="highlight sql"><figcaption data-lang="SQL"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">CREATE</span> EVENT create_monthly_partition_event</pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token keyword">ON</span> SCHEDULE EVERY <span class="token number">1</span> <span class="token keyword">MONTH</span></pre></td></tr><tr><td data-num="3"></td><td><pre>STARTS <span class="token string">'2024-01-01 00:00:00.000'</span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token keyword">ON</span> COMPLETION <span class="token operator">NOT</span> PRESERVE</pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token keyword">ENABLE</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token keyword">DO</span> <span class="token keyword">begin</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token keyword">DECLARE</span> <span class="token keyword">CONTINUE</span> <span class="token keyword">HANDLER</span> <span class="token keyword">FOR</span> SQLEXCEPTION</pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token keyword">BEGIN</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token comment">-- 捕获异常,记录错误信息,然后继续执行</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token keyword">SET</span> <span class="token variable">@error_message</span> <span class="token operator">=</span> CONCAT<span class="token punctuation">(</span><span class="token string">'Error occurred while processing table: '</span><span class="token punctuation">,</span> <span class="token variable">@tableName</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token comment">-- 可以将错误信息插入到日志表,或者使用 SELECT 输出错误信息</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token keyword">SELECT</span> <span class="token variable">@error_message</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token keyword">END</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token comment">-- 定义需要分区的表名列表</span></pre></td></tr><tr><td data-num="15"></td><td><pre> <span class="token keyword">SET</span> <span class="token variable">@tables</span> <span class="token operator">=</span> <span class="token string">'表名1,表名2'</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token comment">-- 遍历表名列表并为每个表创建分区</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token keyword">WHILE</span> CHAR_LENGTH<span class="token punctuation">(</span><span class="token variable">@tables</span><span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">0</span> <span class="token keyword">DO</span></pre></td></tr><tr><td data-num="18"></td><td><pre> <span class="token keyword">SET</span> <span class="token variable">@tableName</span> <span class="token operator">=</span> SUBSTRING_INDEX<span class="token punctuation">(</span><span class="token variable">@tables</span><span class="token punctuation">,</span> <span class="token string">','</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="19"></td><td><pre> <span class="token keyword">SET</span> <span class="token variable">@tables</span> <span class="token operator">=</span> SUBSTRING<span class="token punctuation">(</span><span class="token variable">@tables</span><span class="token punctuation">,</span> CHAR_LENGTH<span class="token punctuation">(</span><span class="token variable">@tableName</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token keyword">CALL</span> create_monthly_partition<span class="token punctuation">(</span><span class="token variable">@tableName</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token keyword">END</span> <span class="token keyword">WHILE</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="22"></td><td><pre><span class="token keyword">end</span></pre></td></tr></table></figure>
2024-05-10T09:09:00.000Z
https://hitoli.com/2024/04/30/Java%E5%90%8E%E7%AB%AF%E7%A6%81%E6%AD%A2%E6%8E%A5%E5%8F%A3%E7%9E%AC%E6%97%B6%E9%87%8D%E5%A4%8D%E8%B0%83%E7%94%A8/
Java后端禁止接口瞬时重复调用
<h4 id="简介"><a class="anchor" href="#简介">#</a> 简介</h4>
<p>由于前端会莫名其妙的对同一接口请求多次,从而占用后端资源造成浪费。所以采用了后端拦截相关重复请求的方案。此方案会将请求用户 id 加接口 url 加参数作为 key,请求时间作为 value,使用 ConcurrentHashMap 进行缓存。如果下次相同的请求和上次请求的时间在指定的范围内则认为此请求属于重复请求。</p>
<h4 id="实现细节"><a class="anchor" href="#实现细节">#</a> 实现细节</h4>
<h6 id="自定义可重复读request"><a class="anchor" href="#自定义可重复读request">#</a> 自定义可重复读 Request</h6>
<p>request 的 body 只能读取一次,所以对其进行封装。</p>
<figure class="highlight java"><figcaption data-lang="java"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">package</span> <span class="token namespace">xxx<span class="token punctuation">.</span>support</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="2"></td><td><pre></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">com<span class="token punctuation">.</span>alibaba<span class="token punctuation">.</span>fastjson<span class="token punctuation">.</span></span><span class="token class-name">JSON</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">lombok<span class="token punctuation">.</span>extern<span class="token punctuation">.</span>slf4j<span class="token punctuation">.</span></span><span class="token class-name">Slf4j</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">javax<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span></span><span class="token class-name">ReadListener</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">javax<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span></span><span class="token class-name">ServletInputStream</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">javax<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span>http<span class="token punctuation">.</span></span><span class="token class-name">HttpServletRequest</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">javax<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span>http<span class="token punctuation">.</span></span><span class="token class-name">HttpServletRequestWrapper</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span><span class="token operator">*</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>nio<span class="token punctuation">.</span>charset<span class="token punctuation">.</span></span><span class="token class-name">StandardCharsets</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Enumeration</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="13"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Map</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="14"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Objects</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="15"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">TreeMap</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="16"></td><td><pre></pre></td></tr><tr><td data-num="17"></td><td><pre><span class="token annotation punctuation">@Slf4j</span></pre></td></tr><tr><td data-num="18"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">RepeatableReadHttpServletRequestWrapper</span> <span class="token keyword">extends</span> <span class="token class-name">HttpServletRequestWrapper</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="19"></td><td><pre></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> requestBody<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="21"></td><td><pre></pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token keyword">public</span> <span class="token class-name">RepeatableReadHttpServletRequestWrapper</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="23"></td><td><pre> <span class="token keyword">super</span><span class="token punctuation">(</span>request<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="24"></td><td><pre> <span class="token keyword">this</span><span class="token punctuation">.</span>requestBody <span class="token operator">=</span> <span class="token function">readRequestBody</span><span class="token punctuation">(</span>request<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="25"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="26"></td><td><pre></pre></td></tr><tr><td data-num="27"></td><td><pre> <span class="token keyword">private</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token function">readRequestBody</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="28"></td><td><pre> <span class="token keyword">try</span> <span class="token punctuation">(</span><span class="token class-name">InputStream</span> inputStream <span class="token operator">=</span> request<span class="token punctuation">.</span><span class="token function">getInputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="29"></td><td><pre> <span class="token class-name">ByteArrayOutputStream</span> result <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ByteArrayOutputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="30"></td><td><pre></pre></td></tr><tr><td data-num="31"></td><td><pre> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token punctuation">]</span> buffer <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">byte</span><span class="token punctuation">[</span><span class="token number">1024</span><span class="token punctuation">]</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="32"></td><td><pre> <span class="token keyword">int</span> length<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="33"></td><td><pre> <span class="token keyword">while</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>length <span class="token operator">=</span> inputStream<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span>buffer<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">!=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="34"></td><td><pre> result<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span>buffer<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> length<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="35"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="36"></td><td><pre></pre></td></tr><tr><td data-num="37"></td><td><pre> <span class="token keyword">return</span> result<span class="token punctuation">.</span><span class="token function">toByteArray</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="38"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="39"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="40"></td><td><pre></pre></td></tr><tr><td data-num="41"></td><td><pre> <span class="token annotation punctuation">@Override</span></pre></td></tr><tr><td data-num="42"></td><td><pre> <span class="token keyword">public</span> <span class="token class-name">ServletInputStream</span> <span class="token function">getInputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="43"></td><td><pre> <span class="token comment">// 直接使用 ByteArrayInputStream,它提供可重复读取的输入流</span></pre></td></tr><tr><td data-num="44"></td><td><pre> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">ServletInputStream</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="45"></td><td><pre> <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">ByteArrayInputStream</span> byteArrayInputStream <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ByteArrayInputStream</span><span class="token punctuation">(</span>requestBody<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="46"></td><td><pre></pre></td></tr><tr><td data-num="47"></td><td><pre> <span class="token annotation punctuation">@Override</span></pre></td></tr><tr><td data-num="48"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="49"></td><td><pre> <span class="token keyword">return</span> byteArrayInputStream<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="50"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="51"></td><td><pre></pre></td></tr><tr><td data-num="52"></td><td><pre> <span class="token annotation punctuation">@Override</span></pre></td></tr><tr><td data-num="53"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">isFinished</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="54"></td><td><pre> <span class="token keyword">return</span> byteArrayInputStream<span class="token punctuation">.</span><span class="token function">available</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="55"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="56"></td><td><pre></pre></td></tr><tr><td data-num="57"></td><td><pre> <span class="token annotation punctuation">@Override</span></pre></td></tr><tr><td data-num="58"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">isReady</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="59"></td><td><pre> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="60"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="61"></td><td><pre></pre></td></tr><tr><td data-num="62"></td><td><pre> <span class="token annotation punctuation">@Override</span></pre></td></tr><tr><td data-num="63"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">setReadListener</span><span class="token punctuation">(</span><span class="token class-name">ReadListener</span> readListener<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="64"></td><td><pre> <span class="token comment">// 不需要实现,可以留空</span></pre></td></tr><tr><td data-num="65"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="66"></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="67"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="68"></td><td><pre></pre></td></tr><tr><td data-num="69"></td><td><pre> <span class="token annotation punctuation">@Override</span></pre></td></tr><tr><td data-num="70"></td><td><pre> <span class="token keyword">public</span> <span class="token class-name">BufferedReader</span> <span class="token function">getReader</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="71"></td><td><pre> <span class="token comment">// 使用 InputStreamReader 包装 ByteArrayInputStream,提供可重复读取的字符流</span></pre></td></tr><tr><td data-num="72"></td><td><pre> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">BufferedReader</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">InputStreamReader</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">ByteArrayInputStream</span><span class="token punctuation">(</span>requestBody<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="73"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="74"></td><td><pre></pre></td></tr><tr><td data-num="75"></td><td><pre> <span class="token comment">/**</pre></td></tr><tr><td data-num="76"></td><td><pre> * 获取 json 格式的参数</pre></td></tr><tr><td data-num="77"></td><td><pre> * @return</pre></td></tr><tr><td data-num="78"></td><td><pre> */</span></pre></td></tr><tr><td data-num="79"></td><td><pre> <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">getParamsToJSONString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="80"></td><td><pre> <span class="token class-name">String</span> jsonStr <span class="token operator">=</span> <span class="token string">""</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="81"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token string">"POST"</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">toUpperCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">isJsonRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="82"></td><td><pre> <span class="token keyword">try</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="83"></td><td><pre> jsonStr <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">readJsonData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="84"></td><td><pre> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="85"></td><td><pre> log<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span>e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="86"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="87"></td><td><pre> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="88"></td><td><pre> <span class="token class-name">Enumeration</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">></span></span> parameterNames <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getParameterNames</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="89"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">nonNull</span><span class="token punctuation">(</span>parameterNames<span class="token punctuation">)</span> <span class="token operator">&&</span> parameterNames<span class="token punctuation">.</span><span class="token function">hasMoreElements</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="90"></td><td><pre> <span class="token comment">// 将参数排序后转为 json</span></pre></td></tr><tr><td data-num="91"></td><td><pre> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">></span></span> paramsMap <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">TreeMap</span><span class="token generics"><span class="token punctuation"><</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="92"></td><td><pre> <span class="token keyword">while</span> <span class="token punctuation">(</span>parameterNames<span class="token punctuation">.</span><span class="token function">hasMoreElements</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="93"></td><td><pre> <span class="token class-name">String</span> paramName <span class="token operator">=</span> parameterNames<span class="token punctuation">.</span><span class="token function">nextElement</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="94"></td><td><pre> paramsMap<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>paramName<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getParameter</span><span class="token punctuation">(</span>paramName<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="95"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="96"></td><td><pre> jsonStr <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">toJSONString</span><span class="token punctuation">(</span>paramsMap<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="97"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="98"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="99"></td><td><pre> <span class="token keyword">return</span> jsonStr<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="100"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="101"></td><td><pre></pre></td></tr><tr><td data-num="102"></td><td><pre> <span class="token comment">/**</pre></td></tr><tr><td data-num="103"></td><td><pre> * 判断是否 json 请求</pre></td></tr><tr><td data-num="104"></td><td><pre> * @return</pre></td></tr><tr><td data-num="105"></td><td><pre> */</span></pre></td></tr><tr><td data-num="106"></td><td><pre> <span class="token keyword">private</span> <span class="token keyword">boolean</span> <span class="token function">isJsonRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="107"></td><td><pre> <span class="token class-name">String</span> contentType <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getContentType</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="108"></td><td><pre> <span class="token keyword">return</span> contentType <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">&&</span> contentType<span class="token punctuation">.</span><span class="token function">toLowerCase</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">contains</span><span class="token punctuation">(</span><span class="token string">"application/json"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="109"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="110"></td><td><pre></pre></td></tr><tr><td data-num="111"></td><td><pre> <span class="token comment">/**</pre></td></tr><tr><td data-num="112"></td><td><pre> * 获取 json 格式的参数</pre></td></tr><tr><td data-num="113"></td><td><pre> * @return</pre></td></tr><tr><td data-num="114"></td><td><pre> * @throws IOException</pre></td></tr><tr><td data-num="115"></td><td><pre> */</span></pre></td></tr><tr><td data-num="116"></td><td><pre> <span class="token keyword">private</span> <span class="token class-name">String</span> <span class="token function">readJsonData</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="117"></td><td><pre> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">readRequestBody</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">StandardCharsets</span><span class="token punctuation">.</span><span class="token constant">UTF_8</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="118"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="119"></td><td><pre></pre></td></tr><tr><td data-num="120"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><h6 id="重复请求过滤器"><a class="anchor" href="#重复请求过滤器">#</a> 重复请求过滤器</h6>
<figure class="highlight java"><figcaption data-lang="java"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">package</span> <span class="token namespace">xxx<span class="token punctuation">.</span>filter</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="2"></td><td><pre></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">cn<span class="token punctuation">.</span>hutool<span class="token punctuation">.</span>core<span class="token punctuation">.</span>collection<span class="token punctuation">.</span></span><span class="token class-name">CollectionUtil</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">xxx<span class="token punctuation">.</span></span><span class="token class-name">RepeatableReadHttpServletRequestWrapper</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>boot<span class="token punctuation">.</span>actuate<span class="token punctuation">.</span>endpoint<span class="token punctuation">.</span>web<span class="token punctuation">.</span></span><span class="token class-name">WebEndpointResponse</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>web<span class="token punctuation">.</span>util<span class="token punctuation">.</span>matcher<span class="token punctuation">.</span></span><span class="token class-name">RequestMatcher</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter<span class="token punctuation">.</span></span><span class="token class-name">OncePerRequestFilter</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre></pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">javax<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span></span><span class="token class-name">FilterChain</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">javax<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span></span><span class="token class-name">ServletException</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">javax<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span>http<span class="token punctuation">.</span></span><span class="token class-name">HttpServletRequest</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">javax<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span>http<span class="token punctuation">.</span></span><span class="token class-name">HttpServletResponse</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="13"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>io<span class="token punctuation">.</span></span><span class="token class-name">IOException</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="14"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">List</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="15"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Map</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="16"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Objects</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="17"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>concurrent<span class="token punctuation">.</span></span><span class="token class-name">ConcurrentHashMap</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="18"></td><td><pre></pre></td></tr><tr><td data-num="19"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DuplicateRequestFilter</span> <span class="token keyword">extends</span> <span class="token class-name">OncePerRequestFilter</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="20"></td><td><pre> <span class="token comment">// 是否启用</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token keyword">private</span> <span class="token class-name">Boolean</span> duplicateRequestFilter<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token comment">// 间隔时间(毫秒)</span></pre></td></tr><tr><td data-num="23"></td><td><pre> <span class="token keyword">private</span> <span class="token class-name">Long</span> intervalTime<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="24"></td><td><pre> <span class="token comment">// 清除缓存时间(毫秒)</span></pre></td></tr><tr><td data-num="25"></td><td><pre> <span class="token keyword">private</span> <span class="token class-name">Long</span> clearCachetime<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="26"></td><td><pre> <span class="token comment">// 放行 url</span></pre></td></tr><tr><td data-num="27"></td><td><pre> <span class="token keyword">private</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">RequestMatcher</span><span class="token punctuation">></span></span> permitAll<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="28"></td><td><pre></pre></td></tr><tr><td data-num="29"></td><td><pre> <span class="token keyword">public</span> <span class="token class-name">DuplicateRequestFilter</span><span class="token punctuation">(</span><span class="token class-name">Boolean</span> duplicateRequestFilter<span class="token punctuation">,</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">RequestMatcher</span><span class="token punctuation">></span></span> permitAll<span class="token punctuation">,</span> <span class="token class-name">Long</span> intervalTime<span class="token punctuation">,</span></pre></td></tr><tr><td data-num="30"></td><td><pre> <span class="token class-name">Long</span> clearCachetime<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="31"></td><td><pre> <span class="token keyword">this</span><span class="token punctuation">.</span>duplicateRequestFilter <span class="token operator">=</span> duplicateRequestFilter<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="32"></td><td><pre> <span class="token keyword">this</span><span class="token punctuation">.</span>permitAll <span class="token operator">=</span> permitAll<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="33"></td><td><pre> <span class="token keyword">this</span><span class="token punctuation">.</span>intervalTime <span class="token operator">=</span> intervalTime<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="34"></td><td><pre> <span class="token keyword">this</span><span class="token punctuation">.</span>clearCachetime <span class="token operator">=</span> clearCachetime<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="35"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="36"></td><td><pre></pre></td></tr><tr><td data-num="37"></td><td><pre> <span class="token comment">// 存储参数和请求时间</span></pre></td></tr><tr><td data-num="38"></td><td><pre> <span class="token keyword">private</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">String</span><span class="token punctuation">,</span> <span class="token class-name">Long</span><span class="token punctuation">></span></span> requestCache <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ConcurrentHashMap</span><span class="token generics"><span class="token punctuation"><</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="39"></td><td><pre></pre></td></tr><tr><td data-num="40"></td><td><pre> <span class="token annotation punctuation">@Override</span></pre></td></tr><tr><td data-num="41"></td><td><pre> <span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">doFilterInternal</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> request<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> response<span class="token punctuation">,</span> <span class="token class-name">FilterChain</span> filterChain<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="42"></td><td><pre> <span class="token keyword">throws</span> <span class="token class-name">ServletException</span><span class="token punctuation">,</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="43"></td><td><pre> <span class="token keyword">boolean</span> doFilter <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="44"></td><td><pre> <span class="token comment">// 使用 ContentCachingRequestWrapper 包装原始请求</span></pre></td></tr><tr><td data-num="45"></td><td><pre> <span class="token class-name">RepeatableReadHttpServletRequestWrapper</span> wrappedRequest <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="46"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>duplicateRequestFilter<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="47"></td><td><pre> <span class="token comment">// 判断请求路径是否需要放行</span></pre></td></tr><tr><td data-num="48"></td><td><pre> <span class="token keyword">boolean</span> permit <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="49"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">CollectionUtil</span><span class="token punctuation">.</span><span class="token function">isNotEmpty</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>permitAll<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="50"></td><td><pre> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">RequestMatcher</span> matcher<span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>permitAll<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="51"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>matcher<span class="token punctuation">.</span><span class="token function">matches</span><span class="token punctuation">(</span>request<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="52"></td><td><pre> permit <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="53"></td><td><pre> <span class="token keyword">break</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="54"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="55"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="56"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="57"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>permit<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="58"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>request <span class="token keyword">instanceof</span> <span class="token class-name">RepeatableReadHttpServletRequestWrapper</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="59"></td><td><pre> wrappedRequest <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">RepeatableReadHttpServletRequestWrapper</span><span class="token punctuation">)</span> request<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="60"></td><td><pre> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="61"></td><td><pre> wrappedRequest <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">RepeatableReadHttpServletRequestWrapper</span><span class="token punctuation">(</span>request<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="62"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="63"></td><td><pre> doFilter <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">isValid</span><span class="token punctuation">(</span>wrappedRequest<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="64"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="65"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="66"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>doFilter<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="67"></td><td><pre> <span class="token comment">// 继续处理请求</span></pre></td></tr><tr><td data-num="68"></td><td><pre> filterChain<span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">nonNull</span><span class="token punctuation">(</span>wrappedRequest<span class="token punctuation">)</span> <span class="token operator">?</span> wrappedRequest <span class="token operator">:</span> request<span class="token punctuation">,</span> response<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="69"></td><td><pre> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="70"></td><td><pre> response<span class="token punctuation">.</span><span class="token function">setContentType</span><span class="token punctuation">(</span><span class="token string">"application/json"</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="71"></td><td><pre> response<span class="token punctuation">.</span><span class="token function">setStatus</span><span class="token punctuation">(</span><span class="token class-name">WebEndpointResponse</span><span class="token punctuation">.</span><span class="token constant">STATUS_TOO_MANY_REQUESTS</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="72"></td><td><pre><span class="token comment">// response.setStatus(HttpServletResponse.SC_OK);</span></pre></td></tr><tr><td data-num="73"></td><td><pre><span class="token comment">// ObjectMapper mapper = new ObjectMapper();</span></pre></td></tr><tr><td data-num="74"></td><td><pre><span class="token comment">// mapper.writeValue (response.getOutputStream (), R.error (WebEndpointResponse.STATUS_TOO_MANY_REQUESTS, "重复的请求"));</span></pre></td></tr><tr><td data-num="75"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="76"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="77"></td><td><pre></pre></td></tr><tr><td data-num="78"></td><td><pre> <span class="token comment">/**</pre></td></tr><tr><td data-num="79"></td><td><pre> * 验证请求的有效性(判断是否重复请求)</pre></td></tr><tr><td data-num="80"></td><td><pre> * @param request</pre></td></tr><tr><td data-num="81"></td><td><pre> * @return</pre></td></tr><tr><td data-num="82"></td><td><pre> */</span></pre></td></tr><tr><td data-num="83"></td><td><pre> <span class="token keyword">private</span> <span class="token keyword">boolean</span> <span class="token function">isValid</span><span class="token punctuation">(</span><span class="token class-name">RepeatableReadHttpServletRequestWrapper</span> request<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="84"></td><td><pre> <span class="token keyword">boolean</span> valid <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="85"></td><td><pre> <span class="token comment">// 缓存的 key</span></pre></td></tr><tr><td data-num="86"></td><td><pre> <span class="token class-name">String</span> key <span class="token operator">=</span> <span class="token class-name">TokenUtil</span><span class="token punctuation">.</span><span class="token function">getUidByToken</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"_"</span> <span class="token operator">+</span> request<span class="token punctuation">.</span><span class="token function">getServletPath</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"_"</span> <span class="token operator">+</span> request<span class="token punctuation">.</span><span class="token function">getParamsToJSONString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="87"></td><td><pre> <span class="token comment">// 获取之前的请求时间</span></pre></td></tr><tr><td data-num="88"></td><td><pre> <span class="token class-name">Long</span> previousRequestTime <span class="token operator">=</span> requestCache<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="89"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>previousRequestTime <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="90"></td><td><pre> <span class="token comment">// 如果距离上次请求时间很短(例如 1 秒),则拒绝当前请求</span></pre></td></tr><tr><td data-num="91"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> previousRequestTime <span class="token operator"><</span> <span class="token keyword">this</span><span class="token punctuation">.</span>intervalTime<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="92"></td><td><pre> valid <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="93"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="94"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="95"></td><td><pre> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">clearOldRequests</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="96"></td><td><pre> <span class="token comment">// 缓存当前请求时间</span></pre></td></tr><tr><td data-num="97"></td><td><pre> requestCache<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>key<span class="token punctuation">,</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="98"></td><td><pre> <span class="token keyword">return</span> valid<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="99"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="100"></td><td><pre></pre></td></tr><tr><td data-num="101"></td><td><pre> <span class="token comment">// 用于清除缓存中的旧请求数据,防止缓存无限增长</span></pre></td></tr><tr><td data-num="102"></td><td><pre> <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">clearOldRequests</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="103"></td><td><pre> requestCache<span class="token punctuation">.</span><span class="token function">entrySet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">removeIf</span><span class="token punctuation">(</span>entry <span class="token operator">-></span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span> entry<span class="token punctuation">.</span><span class="token function">getValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">></span> <span class="token keyword">this</span><span class="token punctuation">.</span>clearCachetime<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="104"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="105"></td><td><pre></pre></td></tr><tr><td data-num="106"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure><h6 id="配置oauth2资源"><a class="anchor" href="#配置oauth2资源">#</a> 配置 OAuth2 资源</h6>
<figure class="highlight java"><figcaption data-lang="java"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">package</span> <span class="token namespace">xxx<span class="token punctuation">.</span>config</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="2"></td><td><pre></pre></td></tr><tr><td data-num="3"></td><td><pre></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">xxx<span class="token punctuation">.</span></span><span class="token class-name">AuthExceptionEntryPoint</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">xxx<span class="token punctuation">.</span></span><span class="token class-name">CustomAccessDeniedHandler</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">xxx<span class="token punctuation">.</span></span><span class="token class-name">DuplicateRequestFilter</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>slf4j<span class="token punctuation">.</span></span><span class="token class-name">Logger</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>slf4j<span class="token punctuation">.</span></span><span class="token class-name">LoggerFactory</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="9"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Autowired</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="10"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Qualifier</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="11"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Value</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Bean</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="13"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Configuration</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="14"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>config<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>web<span class="token punctuation">.</span>builders<span class="token punctuation">.</span></span><span class="token class-name">HttpSecurity</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="15"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>oauth2<span class="token punctuation">.</span>config<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>web<span class="token punctuation">.</span>configuration<span class="token punctuation">.</span></span><span class="token class-name">EnableResourceServer</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="16"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>oauth2<span class="token punctuation">.</span>config<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>web<span class="token punctuation">.</span>configuration<span class="token punctuation">.</span></span><span class="token class-name">ResourceServerConfigurerAdapter</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="17"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>oauth2<span class="token punctuation">.</span>config<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span>web<span class="token punctuation">.</span>configurers<span class="token punctuation">.</span></span><span class="token class-name">ResourceServerSecurityConfigurer</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="18"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>oauth2<span class="token punctuation">.</span>provider<span class="token punctuation">.</span>token<span class="token punctuation">.</span></span><span class="token class-name">TokenStore</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="19"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>web<span class="token punctuation">.</span>authentication<span class="token punctuation">.</span>preauth<span class="token punctuation">.</span></span><span class="token class-name">AbstractPreAuthenticatedProcessingFilter</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="20"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>security<span class="token punctuation">.</span>web<span class="token punctuation">.</span>util<span class="token punctuation">.</span>matcher<span class="token punctuation">.</span></span><span class="token class-name">AntPathRequestMatcher</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="21"></td><td><pre></pre></td></tr><tr><td data-num="22"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">javax<span class="token punctuation">.</span>servlet<span class="token punctuation">.</span></span><span class="token class-name">Filter</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="23"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Arrays</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="24"></td><td><pre><span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>stream<span class="token punctuation">.</span></span><span class="token class-name">Collectors</span></span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="25"></td><td><pre></pre></td></tr><tr><td data-num="26"></td><td><pre><span class="token annotation punctuation">@Configuration</span></pre></td></tr><tr><td data-num="27"></td><td><pre><span class="token annotation punctuation">@EnableResourceServer</span></pre></td></tr><tr><td data-num="28"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ResourceServerConfig</span> <span class="token keyword">extends</span> <span class="token class-name">ResourceServerConfigurerAdapter</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="29"></td><td><pre></pre></td></tr><tr><td data-num="30"></td><td><pre> <span class="token class-name">Logger</span> log <span class="token operator">=</span> <span class="token class-name">LoggerFactory</span><span class="token punctuation">.</span><span class="token function">getLogger</span><span class="token punctuation">(</span><span class="token class-name">ResourceServerConfig</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="31"></td><td><pre></pre></td></tr><tr><td data-num="32"></td><td><pre> <span class="token annotation punctuation">@Autowired</span></pre></td></tr><tr><td data-num="33"></td><td><pre> <span class="token keyword">private</span> <span class="token class-name">TokenStore</span> tokenStore<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="34"></td><td><pre> </pre></td></tr><tr><td data-num="35"></td><td><pre> <span class="token comment">/**</pre></td></tr><tr><td data-num="36"></td><td><pre> * 是否开放所有接口</pre></td></tr><tr><td data-num="37"></td><td><pre> */</span></pre></td></tr><tr><td data-num="38"></td><td><pre> <span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${http.security.permitAll:false}"</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="39"></td><td><pre> <span class="token keyword">private</span> <span class="token class-name">Boolean</span> isPermitAll<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="40"></td><td><pre></pre></td></tr><tr><td data-num="41"></td><td><pre> <span class="token comment">/**</pre></td></tr><tr><td data-num="42"></td><td><pre> * 是否启用重复请求过滤</pre></td></tr><tr><td data-num="43"></td><td><pre> */</span></pre></td></tr><tr><td data-num="44"></td><td><pre> <span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${request.duplicateFilter.enabled:true}"</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="45"></td><td><pre> <span class="token keyword">private</span> <span class="token class-name">Boolean</span> duplicateRequestFilter<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="46"></td><td><pre></pre></td></tr><tr><td data-num="47"></td><td><pre> <span class="token comment">/**</pre></td></tr><tr><td data-num="48"></td><td><pre> * 间隔时间 (毫秒)</pre></td></tr><tr><td data-num="49"></td><td><pre> */</span></pre></td></tr><tr><td data-num="50"></td><td><pre> <span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${request.duplicateFilter.interval_time:1000}"</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="51"></td><td><pre> <span class="token keyword">private</span> <span class="token class-name">Long</span> intervalTime<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="52"></td><td><pre></pre></td></tr><tr><td data-num="53"></td><td><pre> <span class="token comment">/**</pre></td></tr><tr><td data-num="54"></td><td><pre> * 清除缓存时间 (毫秒)</pre></td></tr><tr><td data-num="55"></td><td><pre> */</span></pre></td></tr><tr><td data-num="56"></td><td><pre> <span class="token annotation punctuation">@Value</span><span class="token punctuation">(</span><span class="token string">"${request.duplicateFilter.clear_cache_time:30000}"</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="57"></td><td><pre> <span class="token keyword">private</span> <span class="token class-name">Long</span> clearCachetime<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="58"></td><td><pre></pre></td></tr><tr><td data-num="59"></td><td><pre> <span class="token comment">/**</pre></td></tr><tr><td data-num="60"></td><td><pre> * 不需要验证权限的接口</pre></td></tr><tr><td data-num="61"></td><td><pre> */</span></pre></td></tr><tr><td data-num="62"></td><td><pre> <span class="token keyword">private</span> <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> permitAll <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="63"></td><td><pre> <span class="token string">"/auth/getVCode"</span><span class="token punctuation">,</span> <span class="token string">"/auth/login"</span></pre></td></tr><tr><td data-num="64"></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="65"></td><td><pre></pre></td></tr><tr><td data-num="66"></td><td><pre></pre></td></tr><tr><td data-num="67"></td><td><pre> <span class="token comment">/**</pre></td></tr><tr><td data-num="68"></td><td><pre> * 通行规则</pre></td></tr><tr><td data-num="69"></td><td><pre> * @param http</pre></td></tr><tr><td data-num="70"></td><td><pre> * @throws Exception</pre></td></tr><tr><td data-num="71"></td><td><pre> */</span></pre></td></tr><tr><td data-num="72"></td><td><pre> <span class="token annotation punctuation">@Override</span></pre></td></tr><tr><td data-num="73"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">configure</span><span class="token punctuation">(</span><span class="token class-name">HttpSecurity</span> http<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="74"></td><td><pre> <span class="token class-name">HttpSecurity</span> httpSecurity <span class="token operator">=</span> http<span class="token punctuation">.</span><span class="token function">csrf</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">disable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="75"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>isPermitAll<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="76"></td><td><pre> httpSecurity<span class="token punctuation">.</span><span class="token function">authorizeRequests</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">antMatchers</span><span class="token punctuation">(</span><span class="token string">"/**"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">permitAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="77"></td><td><pre> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="78"></td><td><pre> httpSecurity<span class="token punctuation">.</span><span class="token function">authorizeRequests</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="79"></td><td><pre> <span class="token punctuation">.</span><span class="token function">antMatchers</span><span class="token punctuation">(</span>permitAll<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">permitAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="80"></td><td><pre> <span class="token punctuation">.</span><span class="token function">antMatchers</span><span class="token punctuation">(</span><span class="token string">"/**"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">authenticated</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="81"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="82"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>duplicateRequestFilter<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="83"></td><td><pre> httpSecurity<span class="token punctuation">.</span><span class="token function">addFilterAfter</span><span class="token punctuation">(</span><span class="token function">duplicateRequestFilter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token class-name">AbstractPreAuthenticatedProcessingFilter</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="84"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="85"></td><td><pre> <span class="token comment">// 让 X-frame-options 失效,去除 iframe 限制</span></pre></td></tr><tr><td data-num="86"></td><td><pre> http<span class="token punctuation">.</span><span class="token function">headers</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">frameOptions</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">disable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="87"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="88"></td><td><pre></pre></td></tr><tr><td data-num="89"></td><td><pre> <span class="token annotation punctuation">@Override</span></pre></td></tr><tr><td data-num="90"></td><td><pre> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">configure</span><span class="token punctuation">(</span><span class="token class-name">ResourceServerSecurityConfigurer</span> resources<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="91"></td><td><pre> resources<span class="token punctuation">.</span><span class="token function">tokenStore</span><span class="token punctuation">(</span>tokenStore<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">authenticationEntryPoint</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">AuthExceptionEntryPoint</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="92"></td><td><pre> <span class="token punctuation">.</span><span class="token function">accessDeniedHandler</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">CustomAccessDeniedHandler</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="93"></td><td><pre></pre></td></tr><tr><td data-num="94"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="95"></td><td><pre></pre></td></tr><tr><td data-num="96"></td><td><pre> <span class="token annotation punctuation">@Bean</span></pre></td></tr><tr><td data-num="97"></td><td><pre> <span class="token keyword">public</span> <span class="token class-name">Filter</span> <span class="token function">duplicateRequestFilter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="98"></td><td><pre> <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">DuplicateRequestFilter</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>duplicateRequestFilter<span class="token punctuation">,</span> <span class="token class-name">Arrays</span><span class="token punctuation">.</span><span class="token function">asList</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>permitAll<span class="token punctuation">)</span></pre></td></tr><tr><td data-num="99"></td><td><pre> <span class="token punctuation">.</span><span class="token function">stream</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token class-name">AntPathRequestMatcher</span><span class="token operator">::</span><span class="token keyword">new</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">collect</span><span class="token punctuation">(</span><span class="token class-name">Collectors</span><span class="token punctuation">.</span><span class="token function">toList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">.</span>intervalTime<span class="token punctuation">,</span></pre></td></tr><tr><td data-num="100"></td><td><pre> <span class="token keyword">this</span><span class="token punctuation">.</span>clearCachetime<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="101"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="102"></td><td><pre></pre></td></tr><tr><td data-num="103"></td><td><pre><span class="token punctuation">}</span></pre></td></tr></table></figure>
2024-04-30T03:44:00.000Z
https://hitoli.com/2024/03/03/Docker%E5%AE%B9%E5%99%A8%E7%AE%A1%E7%90%86%E5%B9%B3%E5%8F%B0-Portainer%E5%AE%89%E8%A3%85/
Docker容器管理平台-Portainer安装
<h4 id="简介"><a class="anchor" href="#简介">#</a> 简介</h4>
<p>Portainer 是一款开源的容器管理平台,它提供了易于使用的 Web UI 界面,用于管理和监控容器及容器集群。该软件支持多种容器技术和配置,包括但不限于 Docker、Kubernetes 和 Swarm。</p>
<h4 id="部署"><a class="anchor" href="#部署">#</a> 部署</h4>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment">#原版</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token function">docker</span> run <span class="token parameter variable">-d</span> <span class="token parameter variable">--restart</span><span class="token operator">=</span>always <span class="token parameter variable">--name</span><span class="token operator">=</span><span class="token string">"portainer"</span> <span class="token parameter variable">-p</span> <span class="token number">9000</span>:9000 <span class="token parameter variable">-v</span> /var/run/docker.sock:/var/run/docker.sock <span class="token parameter variable">-v</span> D:<span class="token punctuation">\</span>docker<span class="token punctuation">\</span>portainer<span class="token punctuation">\</span>data:/data portainer/portainer-ce</pre></td></tr><tr><td data-num="3"></td><td><pre></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token comment">#汉化版</span></pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token function">docker</span> run <span class="token parameter variable">-d</span> <span class="token parameter variable">--restart</span><span class="token operator">=</span>always <span class="token parameter variable">--name</span><span class="token operator">=</span><span class="token string">"portainer"</span> <span class="token parameter variable">-p</span> <span class="token number">9000</span>:9000 <span class="token parameter variable">-v</span> /var/run/docker.sock:/var/run/docker.sock <span class="token parameter variable">-v</span> D:<span class="token punctuation">\</span>docker<span class="token punctuation">\</span>portainer<span class="token punctuation">\</span>data:/data <span class="token number">6053537</span>/portainer-ce</pre></td></tr></table></figure><h4 id="登录"><a class="anchor" href="#登录">#</a> 登录</h4>
<p><span class="exturl" data-url="aHR0cDovL2xvY2FsaG9zdDo5MDAwLyMhL2hvbWU=">http://localhost:9000/#!/home</span><br />
<img data-src="https://npic.hitoli.com:8443/images/2024/03/03/923bc8f6ac2a.png" alt="" /></p>
2024-03-03T07:52:00.000Z
https://hitoli.com/2024/01/19/IntellIJ%E5%8F%AA%E7%BC%96%E8%AF%91%E6%89%93%E5%8C%85%E6%8C%87%E5%AE%9A%E7%9A%84%E6%A8%A1%E5%9D%97/
IntellIJ只编译打包指定的模块
<h4 id="新增maven配置"><a class="anchor" href="#新增maven配置">#</a> 新增 Maven 配置</h4>
<p>IntellIJ -》 右侧小锤子旁下拉按钮选择 Edit Configurations -》+ 号按钮 -》Maven</p>
<p><img data-src="https://npic.hitoli.com:8443/images/2024/01/19/58082ccf2487.png" alt="" /></p>
<p><img data-src="https://npic.hitoli.com:8443/images/2024/01/19/3097ede8d80c.png" alt="" /></p>
<p><img data-src="https://npic.hitoli.com:8443/images/2024/01/19/31412cdf03de.png" alt="" /></p>
<h4 id="填写maven命令"><a class="anchor" href="#填写maven命令">#</a> 填写 Maven 命令</h4>
<p>Working directory 选择根目录,命令是基于选中的目录为执行目录,Run 填写以下命令</p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>clean package <span class="token parameter variable">-pl</span> emergency-dzdz/dzdz-yzt <span class="token parameter variable">-am</span> <span class="token parameter variable">-Dmaven.test.skip</span><span class="token operator">=</span>true <span class="token parameter variable">-f</span> pom.xml</pre></td></tr><tr><td data-num="2"></td><td><pre>或者</pre></td></tr><tr><td data-num="3"></td><td><pre>clean <span class="token function">install</span> <span class="token parameter variable">-pl</span> emergency-dzdz/dzdz-yzt <span class="token parameter variable">-am</span> <span class="token parameter variable">-Dmaven.test.skip</span><span class="token operator">=</span>true <span class="token parameter variable">-f</span> pom.xml</pre></td></tr><tr><td data-num="4"></td><td><pre></pre></td></tr><tr><td data-num="5"></td><td><pre>clean: 这个命令会删除目标目录(target),确保每次构建是干净的。</pre></td></tr><tr><td data-num="6"></td><td><pre>install: 这个命令会将项目打包,并安装到本地的 Maven 仓库中。</pre></td></tr><tr><td data-num="7"></td><td><pre><span class="token parameter variable">-pl</span> emergency-dzdz/dzdz-yzt: <span class="token parameter variable">-pl</span> 参数指定要构建的项目模块。dzdz-yzt 是模块的名称。这个参数告诉 Maven 只构建 dzdz-yzt 及其依赖的模块。注意模块路径,此处是构建emergency-dzdz下的dzdz-yzt模块。</pre></td></tr><tr><td data-num="8"></td><td><pre>-am: <span class="token parameter variable">-am</span> 参数与 <span class="token parameter variable">-pl</span> 一起使用,表示还要构建 dzdz-yzt 模块所依赖的所有模块。</pre></td></tr><tr><td data-num="9"></td><td><pre>package: 这个命令会将项目打包为 JAR 文件或 WAR 文件,取决于项目类型。</pre></td></tr><tr><td data-num="10"></td><td><pre><span class="token parameter variable">-f</span> pom.xml: 这个参数指定要使用的 pom.xml 文件。默认情况下,Maven 会在当前目录下查找 pom.xml 文件,但可以通过此参数指定一个不同的位置。</pre></td></tr><tr><td data-num="11"></td><td><pre><span class="token parameter variable">-DskipTests</span><span class="token operator">=</span>true:跳过测试的执行,但会编译测试代码。</pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token parameter variable">-Dmaven.test.skip</span><span class="token operator">=</span>true:跳过测试的编译和执行。</pre></td></tr></table></figure>
2024-01-19T08:06:00.000Z
https://hitoli.com/2024/01/03/%E8%A7%A3%E5%86%B3Nginx%E8%AE%BF%E9%97%AE%E8%87%AA%E7%AD%BEssl%E8%AF%81%E4%B9%A6%E6%8A%A5%E4%B8%8D%E5%AE%89%E5%85%A8%E5%91%8A%E8%AD%A6/
解决Nginx访问自签ssl证书报不安全告警
<h4 id="生成根证书私钥和根证书"><a class="anchor" href="#生成根证书私钥和根证书">#</a> 生成根证书私钥和根证书</h4>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>openssl req <span class="token parameter variable">-x509</span> <span class="token parameter variable">-nodes</span> <span class="token parameter variable">-days</span> <span class="token number">36500</span> <span class="token parameter variable">-newkey</span> rsa:2048 <span class="token parameter variable">-subj</span> <span class="token string">"/C=国家/ST=省/L=市/O=机构"</span> <span class="token parameter variable">-keyout</span> CA-private.key <span class="token parameter variable">-out</span> CA-certificate.crt <span class="token parameter variable">-reqexts</span> v3_req <span class="token parameter variable">-extensions</span> v3_ca</pre></td></tr><tr><td data-num="2"></td><td><pre></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token comment">#示例</span></pre></td></tr><tr><td data-num="4"></td><td><pre>openssl req <span class="token parameter variable">-x509</span> <span class="token parameter variable">-nodes</span> <span class="token parameter variable">-days</span> <span class="token number">36500</span> <span class="token parameter variable">-newkey</span> rsa:2048 <span class="token parameter variable">-subj</span> <span class="token string">"/C=CN/ST=EZ/L=EZ/O=EZ"</span> <span class="token parameter variable">-keyout</span> CA-private.key <span class="token parameter variable">-out</span> CA-certificate.crt <span class="token parameter variable">-reqexts</span> v3_req <span class="token parameter variable">-extensions</span> v3_ca</pre></td></tr></table></figure><h4 id="生成自签名证书私钥"><a class="anchor" href="#生成自签名证书私钥">#</a> 生成自签名证书私钥</h4>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>openssl genrsa <span class="token parameter variable">-out</span> private.key <span class="token number">2048</span></pre></td></tr></table></figure><h4 id="根据自签名证书私钥生成自签名证书申请文件"><a class="anchor" href="#根据自签名证书私钥生成自签名证书申请文件">#</a> 根据自签名证书私钥生成自签名证书申请文件</h4>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>openssl req <span class="token parameter variable">-new</span> <span class="token parameter variable">-key</span> private.key <span class="token parameter variable">-subj</span> <span class="token string">"/C=CN/ST=EZ/L=EZ/O=EZ/CN=192.168.2.117"</span> <span class="token parameter variable">-sha256</span> <span class="token parameter variable">-out</span> private.csr</pre></td></tr></table></figure><h4 id="定义自签名证书扩展文件解决chrome安全告警新建privateext文件并写入以下内容ip为nginx服务器ip同nginxconf中的server_name"><a class="anchor" href="#定义自签名证书扩展文件解决chrome安全告警新建privateext文件并写入以下内容ip为nginx服务器ip同nginxconf中的server_name">#</a> 定义自签名证书扩展文件 (解决 chrome 安全告警),新建 private.ext 文件并写入以下内容(IP 为 nginx 服务器 ip,同 nginx.conf 中的 server_name)</h4>
<figure class="highlight text"><figcaption data-lang="text"></figcaption><table><tr><td data-num="1"></td><td><pre>[ req ]</pre></td></tr><tr><td data-num="2"></td><td><pre>default_bits = 1024</pre></td></tr><tr><td data-num="3"></td><td><pre>distinguished_name = req_distinguished_name</pre></td></tr><tr><td data-num="4"></td><td><pre>req_extensions = san</pre></td></tr><tr><td data-num="5"></td><td><pre>extensions = san</pre></td></tr><tr><td data-num="6"></td><td><pre>[ req_distinguished_name ]</pre></td></tr><tr><td data-num="7"></td><td><pre>countryName = CN</pre></td></tr><tr><td data-num="8"></td><td><pre>stateOrProvinceName = Definesys</pre></td></tr><tr><td data-num="9"></td><td><pre>localityName = Definesys</pre></td></tr><tr><td data-num="10"></td><td><pre>organizationName = Definesys</pre></td></tr><tr><td data-num="11"></td><td><pre>[SAN]</pre></td></tr><tr><td data-num="12"></td><td><pre>authorityKeyIdentifier=keyid,issuer</pre></td></tr><tr><td data-num="13"></td><td><pre>basicConstraints=CA:FALSE</pre></td></tr><tr><td data-num="14"></td><td><pre>keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment</pre></td></tr><tr><td data-num="15"></td><td><pre>subjectAltName = IP:192.168.2.117</pre></td></tr></table></figure><h4 id="生成自签名证书有效期100年"><a class="anchor" href="#生成自签名证书有效期100年">#</a> 生成自签名证书(有效期 100 年)</h4>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>openssl x509 <span class="token parameter variable">-req</span> <span class="token parameter variable">-days</span> <span class="token number">36500</span> <span class="token parameter variable">-in</span> private.csr <span class="token parameter variable">-CA</span> CA-certificate.crt <span class="token parameter variable">-CAkey</span> CA-private.key <span class="token parameter variable">-CAcreateserial</span> <span class="token parameter variable">-sha256</span> <span class="token parameter variable">-out</span> private.crt <span class="token parameter variable">-extfile</span> private.ext <span class="token parameter variable">-extensions</span> SAN</pre></td></tr></table></figure><h4 id="nginx的ssl证书配置"><a class="anchor" href="#nginx的ssl证书配置">#</a> nginx 的 ssl 证书配置</h4>
<figure class="highlight yaml"><figcaption data-lang="YAML"></figcaption><table><tr><td data-num="1"></td><td><pre>ssl_certificate_key /usr/local/nginx/ssl/private.key;</pre></td></tr><tr><td data-num="2"></td><td><pre>ssl_certificate /usr/local/nginx/ssl/private.crt;</pre></td></tr></table></figure><h4 id="证书安装"><a class="anchor" href="#证书安装">#</a> 证书安装</h4>
<p>需要安装 CA-certificate.crt 到受信任的根证书颁发机构下,即可从浏览器正常访问且不会报不安全警告。</p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment">#ssl 测试</span></pre></td></tr><tr><td data-num="2"></td><td><pre>openssl s_client <span class="token parameter variable">-connect</span> localhost:8080</pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token comment">#检查证书格式</span></pre></td></tr><tr><td data-num="4"></td><td><pre>openssl x509 <span class="token parameter variable">-in</span> private.crt <span class="token parameter variable">-text</span> <span class="token parameter variable">-noout</span></pre></td></tr><tr><td data-num="5"></td><td><pre>openssl rsa <span class="token parameter variable">-in</span> private.key <span class="token parameter variable">-check</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token comment">#检查证书是否过期(确保 "notBefore" 小于当前日期,"notAfter" 大于当前日期)</span></pre></td></tr><tr><td data-num="7"></td><td><pre>openssl x509 <span class="token parameter variable">-in</span> private.crt <span class="token parameter variable">-noout</span> <span class="token parameter variable">-dates</span></pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token comment">#查看证书链</span></pre></td></tr><tr><td data-num="9"></td><td><pre>openssl x509 <span class="token parameter variable">-in</span> private.crt <span class="token parameter variable">-noout</span> <span class="token parameter variable">-issuer</span> <span class="token parameter variable">-subject</span></pre></td></tr></table></figure>
2024-01-03T10:01:00.000Z
https://hitoli.com/2024/01/03/Centos7%E7%BC%96%E8%AF%91%E5%8D%87%E7%BA%A7nginx/
Centos7编译升级nginx
<h4 id="配置"><a class="anchor" href="#配置">#</a> 配置</h4>
<p>./configure<br />
# 安装目录<br />
--prefix=/usr/local/nginx<br />
#nginx 运行时的非特权用户<br />
--user=nginx<br />
#nginx 运行时的非特权用户组<br />
--group=nginx<br />
#nginx 运行时 pid 的目录<br />
--pid-path=/var/run/nginx/nginx.pid<br />
# 锁定文件目录,防止误操作,或其他使用<br />
--lock-path=/var/lock/nginx.lock<br />
#nginx 错误日志目录<br />
--error-log-path=/var/log/nginx/error.log<br />
#nginx 运行日志目录<br />
--http-log-path=/var/log/nginx/access.log<br />
# 开启 gz 模块,压缩静态页面<br />
--with-http_gzip_static_module<br />
--with-http_gunzip_module<br />
# 开启 ssl 模块<br />
--with-http_ssl_module<br />
# 开启 http2 模块<br />
--with-http_v2_module<br />
#openssl 目录<br />
--with-openssl=/home/openssl-3.2.0<br />
#nginx 的客户端状态<br />
--with-http_stub_status_module<br />
--with-http_realip_module<br />
# 设定客户端请求的临时目录<br />
--http-client-body-temp-path=/usr/local/nginx/client<br />
# 设定 http 代理临时目录<br />
--http-proxy-temp-path=/usr/local/nginx/proxy<br />
# 设定 fastcgi 临时目录<br />
--http-fastcgi-temp-path=/usr/local/nginx/fastcgi<br />
# 设定 uwsgi 临时目录<br />
--http-uwsgi-temp-path=/usr/local/nginx/uwsgi<br />
# 设定 scgi 临时目录<br />
--http-scgi-temp-path=/usr/local/nginx/scgi</p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>./configure <span class="token parameter variable">--prefix</span><span class="token operator">=</span>/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-openssl<span class="token operator">=</span>/home/openssl-3.2.0</pre></td></tr></table></figure><h4 id="编译"><a class="anchor" href="#编译">#</a> 编译</h4>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>make(不要make install)</pre></td></tr></table></figure><h4 id="备份"><a class="anchor" href="#备份">#</a> 备份</h4>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">cp</span> /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old</pre></td></tr></table></figure><h4 id="更新"><a class="anchor" href="#更新">#</a> 更新</h4>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment">#关闭 nginx</span></pre></td></tr><tr><td data-num="2"></td><td><pre>nginx <span class="token parameter variable">-s</span> stop</pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token comment">#更新 nginx</span></pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token function">cp</span> /root/nginx-1.24.0/objs/nginx /usr/local/nginx/sbin/</pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token comment">#启动 nginx</span></pre></td></tr><tr><td data-num="6"></td><td><pre>nginx</pre></td></tr></table></figure>
2024-01-03T09:40:00.000Z
https://hitoli.com/2023/12/24/Docker-desktop%E9%83%A8%E7%BD%B2nacos/
Docker desktop部署nacos
<h4 id="创建数据库"><a class="anchor" href="#创建数据库">#</a> 创建数据库</h4>
<figure class="highlight sql"><figcaption data-lang="SQL"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">create</span> <span class="token keyword">database</span> nacos</pre></td></tr></table></figure><h4 id="下载初始化脚本"><a class="anchor" href="#下载初始化脚本">#</a> 下载初始化脚本</h4>
<p><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2FsaWJhYmEvbmFjb3MvYmxvYi9tYXN0ZXIvZGlzdHJpYnV0aW9uL2NvbmYvbXlzcWwtc2NoZW1hLnNxbA==">脚本文件</span></p>
<h4 id="以普通模式启动获取数据"><a class="anchor" href="#以普通模式启动获取数据">#</a> 以普通模式启动获取数据</h4>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">docker</span> run <span class="token parameter variable">-d</span> <span class="token parameter variable">--restart</span><span class="token operator">=</span>always <span class="token parameter variable">--name</span><span class="token operator">=</span><span class="token string">"nacos"</span> <span class="token parameter variable">-e</span> <span class="token assign-left variable">MODE</span><span class="token operator">=</span>standalone <span class="token parameter variable">-p</span> <span class="token number">8848</span>:8848 <span class="token parameter variable">-p</span> <span class="token number">9848</span>:9848 nacos/nacos-server:latest</pre></td></tr></table></figure><h4 id="进入容器内修改文件权限"><a class="anchor" href="#进入容器内修改文件权限">#</a> 进入容器内修改文件权限</h4>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">chmod</span> <span class="token number">777</span> /home/nacos/conf</pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token function">chmod</span> <span class="token number">777</span> /home/nacos/data</pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token function">chmod</span> <span class="token number">777</span> /home/nacos/logs</pre></td></tr></table></figure><h4 id="拷贝文件到本地"><a class="anchor" href="#拷贝文件到本地">#</a> 拷贝文件到本地</h4>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">docker</span> <span class="token function">cp</span> nacos:/home/nacos/conf D:<span class="token punctuation">\</span>docker<span class="token punctuation">\</span>nacos<span class="token punctuation">\</span>data<span class="token punctuation">\</span></pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token function">docker</span> <span class="token function">cp</span> nacos:/home/nacos/data D:<span class="token punctuation">\</span>docker<span class="token punctuation">\</span>nacos<span class="token punctuation">\</span>data<span class="token punctuation">\</span></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token function">docker</span> <span class="token function">cp</span> nacos:/home/nacos/logs D:<span class="token punctuation">\</span>docker<span class="token punctuation">\</span>nacos<span class="token punctuation">\</span>data<span class="token punctuation">\</span></pre></td></tr></table></figure><h4 id="创建正式容器"><a class="anchor" href="#创建正式容器">#</a> 创建正式容器</h4>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">docker</span> run <span class="token parameter variable">-d</span> <span class="token parameter variable">--name</span> nacos <span class="token parameter variable">--restart</span><span class="token operator">=</span>always <span class="token parameter variable">--network</span> my-net <span class="token parameter variable">-p</span> <span class="token number">8848</span>:8848 <span class="token parameter variable">-p</span> <span class="token number">9848</span>:9848 <span class="token parameter variable">-p</span> <span class="token number">9849</span>:9849 <span class="token parameter variable">-e</span> <span class="token assign-left variable">MODE</span><span class="token operator">=</span>standalone <span class="token parameter variable">--privileged</span><span class="token operator">=</span>true <span class="token parameter variable">-e</span> <span class="token assign-left variable">SPRING_DATASOURCE_PLATFORM</span><span class="token operator">=</span>mysql <span class="token parameter variable">-e</span> <span class="token assign-left variable">MYSQL_SERVICE_HOST</span><span class="token operator">=</span>mysql地址 <span class="token parameter variable">-e</span> <span class="token assign-left variable">MYSQL_SERVICE_PORT</span><span class="token operator">=</span>mysql端口 <span class="token parameter variable">-e</span> <span class="token assign-left variable">MYSQL_SERVICE_USER</span><span class="token operator">=</span>mysql用户名 <span class="token parameter variable">-e</span> <span class="token assign-left variable">MYSQL_SERVICE_PASSWORD</span><span class="token operator">=</span>mysql密码 <span class="token parameter variable">-e</span> <span class="token assign-left variable">MYSQL_SERVICE_DB_NAME</span><span class="token operator">=</span>nacos <span class="token parameter variable">-e</span> <span class="token assign-left variable">TIME_ZONE</span><span class="token operator">=</span><span class="token string">'Asia/Shanghai'</span> <span class="token parameter variable">-v</span> D:<span class="token punctuation">\</span>docker<span class="token punctuation">\</span>nacos<span class="token punctuation">\</span>data<span class="token punctuation">\</span>logs:/home/nacos/logs <span class="token parameter variable">-v</span> D:<span class="token punctuation">\</span>docker<span class="token punctuation">\</span>nacos<span class="token punctuation">\</span>data<span class="token punctuation">\</span>data:/home/nacos/data <span class="token parameter variable">-v</span> D:<span class="token punctuation">\</span>docker<span class="token punctuation">\</span>nacos<span class="token punctuation">\</span>data<span class="token punctuation">\</span>conf:/home/nacos/conf nacos/nacos-server:latest</pre></td></tr></table></figure>
2023-12-24T13:37:00.000Z
https://hitoli.com/2023/12/02/fastjson%E5%BA%8F%E5%88%97%E5%8C%96%E5%8E%BB%E9%99%A4%E7%A9%BA%E5%AD%97%E7%AC%A6%E4%B8%B2/
fastjson序列化去除空字符串属性
<p>今天在把对象转为 json 时需要去除 key 或者 value 为 null 或空字符串的属性,特此记录一下后续好复用。</p>
<figure class="highlight java"><figcaption data-lang="java"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">String</span> <span class="token function">toJSONString</span><span class="token punctuation">(</span><span class="token class-name">Object</span> object<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="2"></td><td><pre> <span class="token class-name">SerializerFeature</span><span class="token punctuation">[</span><span class="token punctuation">]</span> serializerFeatures <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SerializerFeature</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="3"></td><td><pre> <span class="token comment">// 格式化时间</span></pre></td></tr><tr><td data-num="4"></td><td><pre> <span class="token class-name">SerializerFeature<span class="token punctuation">.</span>WriteDateUseDateFormat</span></pre></td></tr><tr><td data-num="5"></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="6"></td><td><pre> <span class="token keyword">return</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">toJSONString</span><span class="token punctuation">(</span>object<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">ValueFilter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token annotation punctuation">@Override</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">process</span><span class="token punctuation">(</span><span class="token class-name">Object</span> object<span class="token punctuation">,</span> <span class="token class-name">String</span> name<span class="token punctuation">,</span> <span class="token class-name">Object</span> value<span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token comment">// 如果名称或者值为 null 或空字符串,则不序列化该属性</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token keyword">if</span> <span class="token punctuation">(</span>name <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> <span class="token punctuation">(</span>name <span class="token keyword">instanceof</span> <span class="token class-name">String</span> <span class="token operator">&&</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span> name<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">||</span></pre></td></tr><tr><td data-num="11"></td><td><pre> value <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> <span class="token punctuation">(</span>value <span class="token keyword">instanceof</span> <span class="token class-name">String</span> <span class="token operator">&&</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span> value<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></pre></td></tr><tr><td data-num="12"></td><td><pre> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token keyword">return</span> value<span class="token punctuation">;</span></pre></td></tr><tr><td data-num="15"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr><tr><td data-num="16"></td><td><pre> <span class="token punctuation">}</span><span class="token punctuation">,</span> serializerFeatures<span class="token punctuation">)</span><span class="token punctuation">;</span></pre></td></tr><tr><td data-num="17"></td><td><pre> <span class="token punctuation">}</span></pre></td></tr></table></figure>
2023-12-02T13:47:00.000Z
https://hitoli.com/2023/11/03/Linux%E4%B8%8B%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2SpringBoot%E9%A1%B9%E7%9B%AE%E7%9A%84%E8%84%9A%E6%9C%AC/
Linux下快速部署SpringBoot项目的脚本
<h4 id="windows部署脚本"><a class="anchor" href="#windows部署脚本">#</a> Windows 部署脚本</h4>
<p>只需要把 jar 和 yml 跟脚本放在同一目录下即可快速启动。</p>
<div class="note info">
<p>拷贝以下代码放入 txt 文本,<span class="exturl" data-url="aHR0cDovL3huLS1zdGFydC1kcTFoNzE2YXVzOGFldHcuc2g=">然后改为 start.sh</span></p>
</div>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token shebang important">#!/bin/bash</span></pre></td></tr><tr><td data-num="2"></td><td><pre></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token builtin class-name">export</span> <span class="token assign-left variable">CLOUD_HOME</span><span class="token operator">=</span><span class="token variable"><span class="token variable">`</span><span class="token builtin class-name">pwd</span><span class="token variable">`</span></span></pre></td></tr><tr><td data-num="4"></td><td><pre></pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token comment"># 获取当前目录中的第一个 JAR 文件的名称</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token assign-left variable">jar_file</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token function">find</span> <span class="token builtin class-name">.</span> <span class="token parameter variable">-maxdepth</span> <span class="token number">1</span> <span class="token parameter variable">-type</span> f <span class="token parameter variable">-name</span> <span class="token string">"*.jar"</span> <span class="token operator">|</span> <span class="token function">head</span> <span class="token parameter variable">-n</span> <span class="token number">1</span><span class="token variable">)</span></span></pre></td></tr><tr><td data-num="7"></td><td><pre></pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token parameter variable">-n</span> <span class="token string">"<span class="token variable">$jar_file</span>"</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token assign-left variable">jar_file</span><span class="token operator">=</span><span class="token variable">${jar_file<span class="token operator">#</span>.<span class="token operator">/</span>}</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token comment">#echo "JAR 文件的名称是: $jar_file"</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token assign-left variable">jar_file_name</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token function">basename</span> <span class="token string">"<span class="token variable">$jar_file</span>"</span> .jar<span class="token variable">)</span></span></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token keyword">else</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token builtin class-name">echo</span> <span class="token string">"当前目录没有JAR文件."</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token builtin class-name">exit</span></pre></td></tr><tr><td data-num="15"></td><td><pre><span class="token keyword">fi</span></pre></td></tr><tr><td data-num="16"></td><td><pre></pre></td></tr><tr><td data-num="17"></td><td><pre><span class="token comment"># 获取当前目录中的第一个 yml 文件的名称</span></pre></td></tr><tr><td data-num="18"></td><td><pre><span class="token assign-left variable">yml_file</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token function">find</span> <span class="token builtin class-name">.</span> <span class="token parameter variable">-maxdepth</span> <span class="token number">1</span> <span class="token parameter variable">-type</span> f <span class="token parameter variable">-name</span> <span class="token string">"*.yml"</span> <span class="token operator">|</span> <span class="token function">head</span> <span class="token parameter variable">-n</span> <span class="token number">1</span><span class="token variable">)</span></span></pre></td></tr><tr><td data-num="19"></td><td><pre></pre></td></tr><tr><td data-num="20"></td><td><pre><span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token parameter variable">-n</span> <span class="token string">"<span class="token variable">$yml_file</span>"</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token assign-left variable">yml_file</span><span class="token operator">=</span><span class="token variable">${yml_file<span class="token operator">#</span>.<span class="token operator">/</span>}</span></pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token comment">#echo "YML 文件的名称是: $yml_file"</span></pre></td></tr><tr><td data-num="23"></td><td><pre><span class="token keyword">else</span></pre></td></tr><tr><td data-num="24"></td><td><pre> <span class="token builtin class-name">echo</span> <span class="token string">"当前目录中没有YML文件."</span></pre></td></tr><tr><td data-num="25"></td><td><pre><span class="token keyword">fi</span></pre></td></tr><tr><td data-num="26"></td><td><pre></pre></td></tr><tr><td data-num="27"></td><td><pre><span class="token assign-left variable">pids</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token function">ps</span> <span class="token parameter variable">-ef</span> <span class="token operator">|</span> <span class="token function">grep</span> <span class="token function">java</span> <span class="token operator">|</span> <span class="token function">grep</span> $jar_file_name <span class="token operator">|</span> <span class="token function">grep</span> <span class="token parameter variable">-v</span> <span class="token function">grep</span> <span class="token operator">|</span> <span class="token function">awk</span> <span class="token string">'{print $2}'</span><span class="token variable">)</span></span></pre></td></tr><tr><td data-num="28"></td><td><pre></pre></td></tr><tr><td data-num="29"></td><td><pre><span class="token keyword">for</span> <span class="token for-or-select variable">pid</span> <span class="token keyword">in</span> <span class="token variable">$pids</span><span class="token punctuation">;</span> <span class="token keyword">do</span></pre></td></tr><tr><td data-num="30"></td><td><pre> <span class="token builtin class-name">echo</span> <span class="token string">"<span class="token variable">$jar_file_name</span> is running, pid="</span><span class="token variable">$pid</span></pre></td></tr><tr><td data-num="31"></td><td><pre> <span class="token builtin class-name">exit</span> <span class="token number">0</span></pre></td></tr><tr><td data-num="32"></td><td><pre><span class="token keyword">done</span></pre></td></tr><tr><td data-num="33"></td><td><pre></pre></td></tr><tr><td data-num="34"></td><td><pre><span class="token builtin class-name">echo</span> <span class="token string">"<span class="token variable">$jar_file_name</span> is pedding..."</span></pre></td></tr><tr><td data-num="35"></td><td><pre></pre></td></tr><tr><td data-num="36"></td><td><pre><span class="token function">sleep</span> <span class="token number">3</span></pre></td></tr><tr><td data-num="37"></td><td><pre></pre></td></tr><tr><td data-num="38"></td><td><pre><span class="token assign-left variable">JAVA_OPTS</span><span class="token operator">=</span><span class="token string">"-Djava.security.egd=file:/dev/./urandom -Dfile.encoding=UTF8"</span></pre></td></tr><tr><td data-num="39"></td><td><pre><span class="token assign-left variable">JAVA_OPTS</span><span class="token operator">=</span><span class="token string">"<span class="token variable">$JAVA_OPTS</span> -Dsun.jnu.encoding=UTF8 -Xms512m -Xmx1024m"</span></pre></td></tr><tr><td data-num="40"></td><td><pre><span class="token assign-left variable">JAVA_OPTS</span><span class="token operator">=</span><span class="token string">"<span class="token variable">$JAVA_OPTS</span> -Dpid.path=<span class="token variable">$CLOUD_HOME</span>/temp -Dspring.config.additional-location=<span class="token variable">$CLOUD_HOME</span>/<span class="token variable">$yml_file</span>"</span></pre></td></tr><tr><td data-num="41"></td><td><pre><span class="token assign-left variable">JAVA_OPTS</span><span class="token operator">=</span><span class="token string">"<span class="token variable">$JAVA_OPTS</span> -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5007"</span></pre></td></tr><tr><td data-num="42"></td><td><pre></pre></td></tr><tr><td data-num="43"></td><td><pre><span class="token function">nohup</span> <span class="token function">java</span> <span class="token variable">$JAVA_OPTS</span> <span class="token parameter variable">-jar</span> <span class="token variable">$CLOUD_HOME</span>/<span class="token variable">$jar_file</span> <span class="token operator">></span>/dev/null <span class="token operator"><span class="token file-descriptor important">2</span>></span> <span class="token variable">$CLOUD_HOME</span>/<span class="token variable">$jar_file_name</span>.run <span class="token operator">&</span></pre></td></tr><tr><td data-num="44"></td><td><pre><span class="token comment">#nohup java $JAVA_OPTS -jar $CLOUD_HOME/$jar_file > $CLOUD_HOME/$jar_file_name.run 2>&1 &</span></pre></td></tr><tr><td data-num="45"></td><td><pre></pre></td></tr><tr><td data-num="46"></td><td><pre><span class="token builtin class-name">echo</span> <span class="token string">"<span class="token variable">$jar_file_name</span> started."</span></pre></td></tr></table></figure><div class="note info">
<p>拷贝以下代码放入 txt 文本,<span class="exturl" data-url="aHR0cDovL3huLS1zdG9wLXVoNWZ0MjJhOWs1YXBidS5zaA==">然后改为 stop.sh</span></p>
</div>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token shebang important">#!/bin/bash</span></pre></td></tr><tr><td data-num="2"></td><td><pre></pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token builtin class-name">export</span> <span class="token assign-left variable">CLOUD_HOME</span><span class="token operator">=</span><span class="token variable"><span class="token variable">`</span><span class="token builtin class-name">pwd</span><span class="token variable">`</span></span></pre></td></tr><tr><td data-num="4"></td><td><pre></pre></td></tr><tr><td data-num="5"></td><td><pre><span class="token comment"># 获取当前目录中的第一个 JAR 文件的名称</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token assign-left variable">jar_file</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token function">find</span> <span class="token builtin class-name">.</span> <span class="token parameter variable">-maxdepth</span> <span class="token number">1</span> <span class="token parameter variable">-type</span> f <span class="token parameter variable">-name</span> <span class="token string">"*.jar"</span> <span class="token operator">|</span> <span class="token function">head</span> <span class="token parameter variable">-n</span> <span class="token number">1</span><span class="token variable">)</span></span></pre></td></tr><tr><td data-num="7"></td><td><pre></pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token parameter variable">-n</span> <span class="token string">"<span class="token variable">$jar_file</span>"</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span></pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token assign-left variable">jar_file</span><span class="token operator">=</span><span class="token variable">${jar_file<span class="token operator">#</span>.<span class="token operator">/</span>}</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token comment">#echo "JAR 文件的名称是: $jar_file"</span></pre></td></tr><tr><td data-num="11"></td><td><pre> <span class="token assign-left variable">jar_file_name</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token function">basename</span> <span class="token string">"<span class="token variable">$jar_file</span>"</span> .jar<span class="token variable">)</span></span></pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token keyword">else</span></pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token builtin class-name">echo</span> <span class="token string">"当前目录没有JAR文件."</span></pre></td></tr><tr><td data-num="14"></td><td><pre> <span class="token builtin class-name">exit</span></pre></td></tr><tr><td data-num="15"></td><td><pre><span class="token keyword">fi</span></pre></td></tr><tr><td data-num="16"></td><td><pre></pre></td></tr><tr><td data-num="17"></td><td><pre><span class="token comment"># 获取当前目录中的第一个 yml 文件的名称</span></pre></td></tr><tr><td data-num="18"></td><td><pre><span class="token assign-left variable">yml_file</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token function">find</span> <span class="token builtin class-name">.</span> <span class="token parameter variable">-maxdepth</span> <span class="token number">1</span> <span class="token parameter variable">-type</span> f <span class="token parameter variable">-name</span> <span class="token string">"*.yml"</span> <span class="token operator">|</span> <span class="token function">head</span> <span class="token parameter variable">-n</span> <span class="token number">1</span><span class="token variable">)</span></span></pre></td></tr><tr><td data-num="19"></td><td><pre></pre></td></tr><tr><td data-num="20"></td><td><pre><span class="token keyword">if</span> <span class="token punctuation">[</span> <span class="token parameter variable">-n</span> <span class="token string">"<span class="token variable">$yml_file</span>"</span> <span class="token punctuation">]</span><span class="token punctuation">;</span> <span class="token keyword">then</span></pre></td></tr><tr><td data-num="21"></td><td><pre> <span class="token assign-left variable">yml_file</span><span class="token operator">=</span><span class="token variable">${yml_file<span class="token operator">#</span>.<span class="token operator">/</span>}</span></pre></td></tr><tr><td data-num="22"></td><td><pre> <span class="token comment">#echo "YML 文件的名称是: $yml_file"</span></pre></td></tr><tr><td data-num="23"></td><td><pre><span class="token keyword">else</span></pre></td></tr><tr><td data-num="24"></td><td><pre> <span class="token builtin class-name">echo</span> <span class="token string">"当前目录中没有YML文件."</span></pre></td></tr><tr><td data-num="25"></td><td><pre><span class="token keyword">fi</span></pre></td></tr><tr><td data-num="26"></td><td><pre></pre></td></tr><tr><td data-num="27"></td><td><pre><span class="token assign-left variable">pids</span><span class="token operator">=</span><span class="token variable"><span class="token variable">$(</span><span class="token function">ps</span> <span class="token parameter variable">-ef</span> <span class="token operator">|</span> <span class="token function">grep</span> <span class="token function">java</span> <span class="token operator">|</span> <span class="token function">grep</span> $jar_file_name <span class="token operator">|</span> <span class="token function">grep</span> <span class="token parameter variable">-v</span> <span class="token function">grep</span> <span class="token operator">|</span> <span class="token function">awk</span> <span class="token string">'{print $2}'</span><span class="token variable">)</span></span></pre></td></tr><tr><td data-num="28"></td><td><pre></pre></td></tr><tr><td data-num="29"></td><td><pre><span class="token keyword">for</span> <span class="token for-or-select variable">pid</span> <span class="token keyword">in</span> <span class="token variable">$pids</span><span class="token punctuation">;</span> <span class="token keyword">do</span></pre></td></tr><tr><td data-num="30"></td><td><pre> <span class="token function">kill</span> <span class="token parameter variable">-9</span> <span class="token variable">$pid</span></pre></td></tr><tr><td data-num="31"></td><td><pre><span class="token keyword">done</span></pre></td></tr><tr><td data-num="32"></td><td><pre></pre></td></tr><tr><td data-num="33"></td><td><pre><span class="token builtin class-name">echo</span> <span class="token string">"<span class="token variable">$jar_file_name</span> is stopping..."</span></pre></td></tr><tr><td data-num="34"></td><td><pre></pre></td></tr><tr><td data-num="35"></td><td><pre><span class="token function">sleep</span> <span class="token number">5</span></pre></td></tr><tr><td data-num="36"></td><td><pre></pre></td></tr><tr><td data-num="37"></td><td><pre><span class="token builtin class-name">echo</span> <span class="token string">"<span class="token variable">$jar_file_name</span> stopped."</span></pre></td></tr></table></figure>
2023-11-03T13:35:00.000Z
https://hitoli.com/2023/10/29/%E7%BB%99%E6%88%91%E7%9A%84%E8%80%81%E7%AC%94%E8%AE%B0%E6%9C%AC%E6%B8%85%E7%90%86%E7%81%B0%E5%B0%98/
给我的老笔记本清理灰尘
<p>今天闲着无事就把我的老笔记本拆了,清理了一下灰尘。笔记本已经 10 多年了,中间加过内存,换过固态硬盘。清理一下还能发挥它的余热!<br />
<img data-src="https://npic.hitoli.com:8443/images/2023/10/29/c7b84a3d703a.jpg" alt="" /><br />
<img data-src="https://npic.hitoli.com:8443/images/2023/10/29/fd2e099d875d.jpg" alt="" /><br />
<img data-src="https://npic.hitoli.com:8443/images/2023/10/29/0fea7641ccde.jpg" alt="" /><br />
<img data-src="https://npic.hitoli.com:8443/images/2023/10/29/73c63c1438a8.jpg" alt="" /><br />
<img data-src="https://npic.hitoli.com:8443/images/2023/10/29/4c5d526af3e7.jpg" alt="" /><br />
<img data-src="https://npic.hitoli.com:8443/images/2023/10/29/4b9bcbecbca3.jpg" alt="" /><br />
<img data-src="https://npic.hitoli.com:8443/images/2023/10/29/38ffc2e9639f.jpg" alt="" /></p>
2023-10-29T12:41:00.000Z
https://hitoli.com/2023/10/28/Windows%E4%B8%8B%E5%BF%AB%E9%80%9F%E9%83%A8%E7%BD%B2SpringBoot%E9%A1%B9%E7%9B%AE%E7%9A%84%E6%89%B9%E5%A4%84%E7%90%86/
Windows下快速部署SpringBoot项目的批处理
<h4 id="windows部署脚本"><a class="anchor" href="#windows部署脚本">#</a> Windows 部署脚本</h4>
<p>只需要把 jar 和 yml 跟批处理放在同一目录下即可点击快速启动。启动后再次点击会关闭上次启动的窗口并重新启动。</p>
<div class="note info">
<p>拷贝以下代码放入 txt 文本,然后改为 start.bat</p>
</div>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>@ECHO OFF</pre></td></tr><tr><td data-num="2"></td><td><pre>setlocal enabledelayedexpansion</pre></td></tr><tr><td data-num="3"></td><td><pre></pre></td></tr><tr><td data-num="4"></td><td><pre>REM 关闭上次进程</pre></td></tr><tr><td data-num="5"></td><td><pre>SET <span class="token string">"pidFile=pid.txt"</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token keyword">if</span> exist <span class="token string">"%pidFile%"</span> <span class="token punctuation">(</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token keyword">for</span> /f <span class="token string">"usebackq"</span> %%a <span class="token keyword">in</span> <span class="token punctuation">(</span><span class="token string">"pid.txt"</span><span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token punctuation">(</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token builtin class-name">set</span> <span class="token assign-left variable">PID</span><span class="token operator">=</span>%%a</pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token punctuation">)</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token keyword">if</span> not <span class="token string">"!PID!"</span><span class="token operator">==</span><span class="token string">""</span> <span class="token punctuation">(</span></pre></td></tr><tr><td data-num="11"></td><td><pre> taskkill /F /T /PID <span class="token operator">!</span>pid<span class="token operator">!</span></pre></td></tr><tr><td data-num="12"></td><td><pre> del pid.txt</pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token punctuation">)</span></pre></td></tr><tr><td data-num="14"></td><td><pre><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="15"></td><td><pre></pre></td></tr><tr><td data-num="16"></td><td><pre>REM 存储当前进程</pre></td></tr><tr><td data-num="17"></td><td><pre><span class="token keyword">for</span> /f %%i <span class="token keyword">in</span> <span class="token punctuation">(</span><span class="token string">'wmic process where "name='</span>cmd.exe<span class="token string">' and CommandLine like '</span>%%<span class="token operator"><</span>scriptname<span class="token operator">></span>.bat%%<span class="token string">'" get ParentProcessId ^| findstr /r "[0-9]"'</span><span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token builtin class-name">set</span> <span class="token assign-left variable">pid</span><span class="token operator">=</span>%%i</pre></td></tr><tr><td data-num="18"></td><td><pre><span class="token builtin class-name">echo</span> %PID% <span class="token operator">></span> pid.txt</pre></td></tr><tr><td data-num="19"></td><td><pre></pre></td></tr><tr><td data-num="20"></td><td><pre>REM 设置title</pre></td></tr><tr><td data-num="21"></td><td><pre><span class="token keyword">for</span> /f <span class="token string">"tokens=2"</span> %%i <span class="token keyword">in</span> <span class="token punctuation">(</span><span class="token string">'chcp'</span><span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token builtin class-name">set</span> <span class="token assign-left variable">codepage</span><span class="token operator">=</span>%%i</pre></td></tr><tr><td data-num="22"></td><td><pre>chcp <span class="token number">65001</span> <span class="token operator">></span> nul</pre></td></tr><tr><td data-num="23"></td><td><pre>title 我的SpringBoot项目</pre></td></tr><tr><td data-num="24"></td><td><pre>chcp %codepage% <span class="token operator">></span> nul</pre></td></tr><tr><td data-num="25"></td><td><pre></pre></td></tr><tr><td data-num="26"></td><td><pre><span class="token builtin class-name">cd</span> %~dp0</pre></td></tr><tr><td data-num="27"></td><td><pre></pre></td></tr><tr><td data-num="28"></td><td><pre>REM 获取jar</pre></td></tr><tr><td data-num="29"></td><td><pre><span class="token builtin class-name">set</span> <span class="token string">"jarFile="</span></pre></td></tr><tr><td data-num="30"></td><td><pre><span class="token keyword">for</span> %%i <span class="token keyword">in</span> <span class="token punctuation">(</span>*.jar<span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token punctuation">(</span></pre></td></tr><tr><td data-num="31"></td><td><pre> <span class="token keyword">if</span> not defined jarFile <span class="token punctuation">(</span></pre></td></tr><tr><td data-num="32"></td><td><pre> <span class="token builtin class-name">set</span> <span class="token string">"jarFile=%%i"</span></pre></td></tr><tr><td data-num="33"></td><td><pre> <span class="token punctuation">)</span></pre></td></tr><tr><td data-num="34"></td><td><pre><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="35"></td><td><pre></pre></td></tr><tr><td data-num="36"></td><td><pre><span class="token keyword">if</span> not defined jarFile <span class="token punctuation">(</span></pre></td></tr><tr><td data-num="37"></td><td><pre> <span class="token builtin class-name">echo</span> not <span class="token function">find</span> jar</pre></td></tr><tr><td data-num="38"></td><td><pre> pause</pre></td></tr><tr><td data-num="39"></td><td><pre> <span class="token builtin class-name">exit</span></pre></td></tr><tr><td data-num="40"></td><td><pre><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="41"></td><td><pre></pre></td></tr><tr><td data-num="42"></td><td><pre>SET <span class="token assign-left variable">JAVA_OPTS</span><span class="token operator">=</span>-Djava.security.egd<span class="token operator">=</span>file:/dev/./urandom <span class="token parameter variable">-Dfile.encoding</span><span class="token operator">=</span>UTF-8</pre></td></tr><tr><td data-num="43"></td><td><pre><span class="token builtin class-name">set</span> <span class="token assign-left variable">JAVA_OPTS</span><span class="token operator">=</span>%JAVA_OPTS% <span class="token parameter variable">-Dsun.jnu.encoding</span><span class="token operator">=</span>UTF8 <span class="token parameter variable">-Xms512m</span> <span class="token parameter variable">-Xmx1024m</span></pre></td></tr><tr><td data-num="44"></td><td><pre><span class="token builtin class-name">set</span> <span class="token assign-left variable">JAVA_OPTS</span><span class="token operator">=</span>%JAVA_OPTS% <span class="token parameter variable">-agentlib:jdwp</span><span class="token operator">=</span>transport<span class="token operator">=</span>dt_socket,server<span class="token operator">=</span>y,suspend<span class="token operator">=</span>n,address<span class="token operator">=</span><span class="token number">5007</span></pre></td></tr><tr><td data-num="45"></td><td><pre><span class="token builtin class-name">set</span> <span class="token assign-left variable">JAVA_OPTS</span><span class="token operator">=</span>%JAVA_OPTS% <span class="token parameter variable">-Dpid.path</span><span class="token operator">=</span>./temp</pre></td></tr><tr><td data-num="46"></td><td><pre></pre></td></tr><tr><td data-num="47"></td><td><pre>REM 获取yml</pre></td></tr><tr><td data-num="48"></td><td><pre><span class="token builtin class-name">set</span> <span class="token string">"ymlFile="</span></pre></td></tr><tr><td data-num="49"></td><td><pre><span class="token keyword">for</span> %%i <span class="token keyword">in</span> <span class="token punctuation">(</span>*.yml<span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token punctuation">(</span></pre></td></tr><tr><td data-num="50"></td><td><pre> <span class="token keyword">if</span> not defined ymlFile <span class="token punctuation">(</span></pre></td></tr><tr><td data-num="51"></td><td><pre> <span class="token builtin class-name">set</span> <span class="token string">"ymlFile=%%i"</span></pre></td></tr><tr><td data-num="52"></td><td><pre> <span class="token punctuation">)</span></pre></td></tr><tr><td data-num="53"></td><td><pre><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="54"></td><td><pre></pre></td></tr><tr><td data-num="55"></td><td><pre><span class="token keyword">if</span> defined ymlFile <span class="token punctuation">(</span></pre></td></tr><tr><td data-num="56"></td><td><pre> <span class="token builtin class-name">set</span> <span class="token assign-left variable">JAVA_OPTS</span><span class="token operator">=</span>%JAVA_OPTS% -Dspring.config.additional-location<span class="token operator">=</span><span class="token operator">!</span>ymlFile<span class="token operator">!</span></pre></td></tr><tr><td data-num="57"></td><td><pre><span class="token punctuation">)</span> <span class="token keyword">else</span> <span class="token punctuation">(</span></pre></td></tr><tr><td data-num="58"></td><td><pre> <span class="token builtin class-name">echo</span> not <span class="token function">find</span> yml</pre></td></tr><tr><td data-num="59"></td><td><pre><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="60"></td><td><pre></pre></td></tr><tr><td data-num="61"></td><td><pre>REM 启动服务</pre></td></tr><tr><td data-num="62"></td><td><pre><span class="token function">java</span> %JAVA_OPTS% <span class="token parameter variable">-jar</span> <span class="token operator">!</span>jarFile<span class="token operator">!</span></pre></td></tr><tr><td data-num="63"></td><td><pre>pause</pre></td></tr></table></figure><div class="note info">
<p>拷贝以下代码放入 txt 文本,然后改为 stop.bat</p>
</div>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>@ECHO OFF</pre></td></tr><tr><td data-num="2"></td><td><pre>setlocal enabledelayedexpansion</pre></td></tr><tr><td data-num="3"></td><td><pre></pre></td></tr><tr><td data-num="4"></td><td><pre>REM 关闭上次进程</pre></td></tr><tr><td data-num="5"></td><td><pre>SET <span class="token string">"pidFile=pid.txt"</span></pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token keyword">if</span> exist <span class="token string">"%pidFile%"</span> <span class="token punctuation">(</span></pre></td></tr><tr><td data-num="7"></td><td><pre> <span class="token keyword">for</span> /f <span class="token string">"usebackq"</span> %%a <span class="token keyword">in</span> <span class="token punctuation">(</span><span class="token string">"pid.txt"</span><span class="token punctuation">)</span> <span class="token keyword">do</span> <span class="token punctuation">(</span></pre></td></tr><tr><td data-num="8"></td><td><pre> <span class="token builtin class-name">set</span> <span class="token assign-left variable">PID</span><span class="token operator">=</span>%%a</pre></td></tr><tr><td data-num="9"></td><td><pre> <span class="token punctuation">)</span></pre></td></tr><tr><td data-num="10"></td><td><pre> <span class="token keyword">if</span> not <span class="token string">"!PID!"</span><span class="token operator">==</span><span class="token string">""</span> <span class="token punctuation">(</span></pre></td></tr><tr><td data-num="11"></td><td><pre> taskkill /F /T /PID <span class="token operator">!</span>pid<span class="token operator">!</span></pre></td></tr><tr><td data-num="12"></td><td><pre> del pid.txt</pre></td></tr><tr><td data-num="13"></td><td><pre> <span class="token punctuation">)</span></pre></td></tr><tr><td data-num="14"></td><td><pre><span class="token punctuation">)</span></pre></td></tr><tr><td data-num="15"></td><td><pre></pre></td></tr><tr><td data-num="16"></td><td><pre><span class="token builtin class-name">exit</span></pre></td></tr></table></figure>
2023-10-28T11:56:00.000Z
https://hitoli.com/2023/10/28/Centos%E6%8C%82%E8%BD%BD%E6%96%B0%E7%A1%AC%E7%9B%98/
Centos挂载新硬盘
<h4 id="查看磁盘信息"><a class="anchor" href="#查看磁盘信息">#</a> 查看磁盘信息</h4>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">fdisk</span> <span class="token parameter variable">-l</span> 查看当前磁盘的分区情况</pre></td></tr></table></figure><p><img data-src="https://npic.hitoli.com:8443/images/2023/10/28/4dc953fc5a5e.png" alt="" /><br />
可从图中获取以下信息:<br />
/dev/vdb 数据盘容量为 60GB,包含 MBR 分区 /dev/vdb1,容量为 50GB。<br />
/dev/vdc 数据盘容量为 60GB,包含 GPT 分区 /dev/vdc1,容量为 50GB。</p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">df</span> <span class="token parameter variable">-TH</span> 分区的文件系统类型</pre></td></tr></table></figure><p><img data-src="https://npic.hitoli.com:8443/images/2023/10/28/8996c9620632.png" alt="" /><br />
可从图中获取以下信息:<br />
/dev/vdb1 文件系统类型为 ext4,已挂载至 /mnt/disk1。<br />
/dev/vdc1 文件系统类型为 xfs,已挂载至 /mnt/disk2。</p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">fdisk</span> /dev/vdb 查看新磁盘情况</pre></td></tr></table></figure><p><img data-src="https://npic.hitoli.com:8443/images/2023/10/28/0f1237aef57b.png" alt="" /></p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>lsbl 查看分区情况</pre></td></tr></table></figure><p><img data-src="https://npic.hitoli.com:8443/images/2023/10/28/8071a3832e29.png" alt="" /></p>
<h4 id="挂载新硬盘"><a class="anchor" href="#挂载新硬盘">#</a> 挂载新硬盘</h4>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>mkfs.ext4 /dev/vdb 格式化磁盘</pre></td></tr></table></figure><p><img data-src="https://npic.hitoli.com:8443/images/2023/10/28/9353dd85579f.png" alt="" /></p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token builtin class-name">cd</span> /mnt</pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token function">mkdir</span> data 新建挂载点</pre></td></tr><tr><td data-num="3"></td><td><pre><span class="token function">mount</span> /dev/vdb /mnt/data 挂载</pre></td></tr></table></figure><figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">df</span> <span class="token parameter variable">-h</span> 查看挂载情况</pre></td></tr></table></figure><p><img data-src="https://npic.hitoli.com:8443/images/2023/10/28/ead4f7b1323f.png" alt="" /><br />
查看 UUID 有三种方式:</p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>blkid</pre></td></tr></table></figure><p><img data-src="https://npic.hitoli.com:8443/images/2023/10/28/236412bc1e3f.png" alt="" /></p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>lsblk <span class="token parameter variable">-f</span></pre></td></tr></table></figure><p><img data-src="https://npic.hitoli.com:8443/images/2023/10/28/35d7182c5647.png" alt="" /></p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>ll /dev/disk/by-uuid/</pre></td></tr></table></figure><p><img data-src="https://npic.hitoli.com:8443/images/2023/10/28/3f9d4f69d8ea.png" alt="" /></p>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>设置自动挂载:</pre></td></tr><tr><td data-num="2"></td><td><pre><span class="token builtin class-name">echo</span> <span class="token string">"UUID=c8ac09ca-fd4d-4511-bd2c-4fdf96f08168 /data ext4 defaults 0 0"</span> <span class="token operator">>></span> /etc/fstab</pre></td></tr><tr><td data-num="3"></td><td><pre>自动挂载/etc/fstab里面的东西</pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token function">mount</span> <span class="token parameter variable">-a</span></pre></td></tr></table></figure><h4 id="临时卸载"><a class="anchor" href="#临时卸载">#</a> 临时卸载</h4>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">umount</span> /dev/vdb 重启机器之后又恢复到挂载状态</pre></td></tr></table></figure><h4 id="永久卸载"><a class="anchor" href="#永久卸载">#</a> 永久卸载</h4>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">vim</span> /etc/fstab 把添加的磁盘信息删除即可。</pre></td></tr></table></figure>
2023-10-28T11:26:00.000Z
https://hitoli.com/2023/09/09/squid-stunnel-%E7%A7%91%E5%AD%A6%E4%B8%8A%E7%BD%91/
squid+stunnel 科学上网
<h4 id="前言"><a class="anchor" href="#前言">#</a> 前言</h4>
<p>科学上网的方法有多种,有很多第三方提供的免费方案,这些方案优缺点暂时不予讨论。实际工作生活中还是会有需要自己搭建的情况,这次介绍的是使用 squid+stunnel 方案进行搭建。</p>
<h4 id="准备"><a class="anchor" href="#准备">#</a> 准备</h4>
<p>一台可以访问外网的服务器,如香港的云主机并安装 Ubuntu 系统。</p>
<h5 id="squid部分"><a class="anchor" href="#squid部分">#</a> squid 部分</h5>
<ul>
<li>1、安装</li>
</ul>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">apt-get</span> <span class="token function">install</span> <span class="token parameter variable">-y</span> squid</pre></td></tr></table></figure><ul>
<li>2、配置</li>
</ul>
<div class="note info">
<p>生成用户文件</p>
</div>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">apt-get</span> <span class="token function">install</span> apache2-utils</pre></td></tr><tr><td data-num="2"></td><td><pre>htpasswd <span class="token parameter variable">-c</span> /etc/squid/squid_user.txt 用户名</pre></td></tr></table></figure><div class="note info">
<p>修改 squid 配置<br />
1、直接修改 /etc/squid/squid.conf 文件<br />
2、修改 /etc/squid/conf.d/debian.conf 文件<br />
两种方式都一样,在底部加入以下代码</p>
</div>
<figure class="highlight yaml"><figcaption data-lang="YAML"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token comment">#dns 服务器地址</span></pre></td></tr><tr><td data-num="2"></td><td><pre>dns_nameservers 8.8.8.8 8.8.4.4</pre></td></tr><tr><td data-num="3"></td><td><pre>dns_v4_first on</pre></td></tr><tr><td data-num="4"></td><td><pre><span class="token comment"># 监听端口</span></pre></td></tr><tr><td data-num="5"></td><td><pre>http_port 3128</pre></td></tr><tr><td data-num="6"></td><td><pre><span class="token comment"># 定义 squid 密码文件与 ncsa_auth 文件位置</span></pre></td></tr><tr><td data-num="7"></td><td><pre>auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/squid_user.txt</pre></td></tr><tr><td data-num="8"></td><td><pre><span class="token comment"># 认证进程的数量</span></pre></td></tr><tr><td data-num="9"></td><td><pre>auth_param basic children 15</pre></td></tr><tr><td data-num="10"></td><td><pre><span class="token comment"># 认证对话框显示提示信息</span></pre></td></tr><tr><td data-num="11"></td><td><pre>auth_param basic realm Squid proxy<span class="token punctuation">-</span>caching web server</pre></td></tr><tr><td data-num="12"></td><td><pre><span class="token comment"># 认证有效期</span></pre></td></tr><tr><td data-num="13"></td><td><pre>auth_param basic credentialsttl 24 hours</pre></td></tr><tr><td data-num="14"></td><td><pre><span class="token comment"># 是否区分用户名大小,off 为不区分</span></pre></td></tr><tr><td data-num="15"></td><td><pre>auth_param basic casesensitive off</pre></td></tr><tr><td data-num="16"></td><td><pre><span class="token comment"># 对定义的 squid_user 文件内的用户开启认证访问</span></pre></td></tr><tr><td data-num="17"></td><td><pre>acl 用户名 proxy_auth REQUIRED</pre></td></tr><tr><td data-num="18"></td><td><pre><span class="token comment"># 允许 squid_user 文件内用户进行代理</span></pre></td></tr><tr><td data-num="19"></td><td><pre>http_access allow 用户名</pre></td></tr><tr><td data-num="20"></td><td><pre><span class="token comment"># 顺序匹配,最后添加拒绝所有未允许的规则。不添加会发现,未匹配到的规则会被放行</span></pre></td></tr><tr><td data-num="21"></td><td><pre>http_access deny all</pre></td></tr><tr><td data-num="22"></td><td><pre><span class="token comment"># 缓存设置</span></pre></td></tr><tr><td data-num="23"></td><td><pre>cache_dir ufs /var/spool/squid 100 16 256 read<span class="token punctuation">-</span>only</pre></td></tr><tr><td data-num="24"></td><td><pre>cache_mem 0 MB</pre></td></tr><tr><td data-num="25"></td><td><pre>coredump_dir /var/spool/squid</pre></td></tr><tr><td data-num="26"></td><td><pre><span class="token comment"># 配置高匿,不允许设置任何多余头信息,保持原请求 header。</span></pre></td></tr><tr><td data-num="27"></td><td><pre>header_access Via deny all</pre></td></tr><tr><td data-num="28"></td><td><pre>header_access X<span class="token punctuation">-</span>Forwarded<span class="token punctuation">-</span>For deny all</pre></td></tr><tr><td data-num="29"></td><td><pre>header_access Server deny all</pre></td></tr><tr><td data-num="30"></td><td><pre>header_access X<span class="token punctuation">-</span>Cache deny all</pre></td></tr><tr><td data-num="31"></td><td><pre>header_access X<span class="token punctuation">-</span>Cache<span class="token punctuation">-</span>Lookup deny all</pre></td></tr><tr><td data-num="32"></td><td><pre>forwarded_for off</pre></td></tr><tr><td data-num="33"></td><td><pre>via off</pre></td></tr><tr><td data-num="34"></td><td><pre></pre></td></tr><tr><td data-num="35"></td><td><pre><span class="token comment"># logs 相关配置</span></pre></td></tr><tr><td data-num="36"></td><td><pre>emulate_httpd_log on</pre></td></tr><tr><td data-num="37"></td><td><pre>logformat squid %<span class="token punctuation">{</span>X<span class="token punctuation">-</span>Forwarded<span class="token punctuation">-</span>For<span class="token punctuation">}</span><span class="token punctuation">></span>h %ui %un <span class="token punctuation">[</span>%tl<span class="token punctuation">]</span> "%rm %ru HTTP/%rv" %Hs %<st "%<span class="token punctuation">{</span>Referer<span class="token punctuation">}</span><span class="token punctuation">></span>h" "%<span class="token punctuation">{</span>User<span class="token punctuation">-</span>Agent<span class="token punctuation">}</span><span class="token punctuation">></span>h" %Ss<span class="token punctuation">:</span>%Sh</pre></td></tr><tr><td data-num="38"></td><td><pre>access_log /var/log/squid/access.log squid</pre></td></tr><tr><td data-num="39"></td><td><pre>cache_log /var/log/squid/cache.log</pre></td></tr><tr><td data-num="40"></td><td><pre>cache_store_log /var/log/squid/store.log</pre></td></tr><tr><td data-num="41"></td><td><pre>logfile_rotate 20</pre></td></tr><tr><td data-num="42"></td><td><pre></pre></td></tr><tr><td data-num="43"></td><td><pre><span class="token comment">######## 新版 ########</span></pre></td></tr><tr><td data-num="44"></td><td><pre><span class="token comment">#Hide client ip</span></pre></td></tr><tr><td data-num="45"></td><td><pre>forwarded_for delete</pre></td></tr><tr><td data-num="46"></td><td><pre></pre></td></tr><tr><td data-num="47"></td><td><pre><span class="token comment">#Turn off via header</span></pre></td></tr><tr><td data-num="48"></td><td><pre>via off</pre></td></tr><tr><td data-num="49"></td><td><pre></pre></td></tr><tr><td data-num="50"></td><td><pre><span class="token comment">#Deny request for original source of a request</span></pre></td></tr><tr><td data-num="51"></td><td><pre>follow_x_forwarded_for deny all</pre></td></tr><tr><td data-num="52"></td><td><pre></pre></td></tr><tr><td data-num="53"></td><td><pre><span class="token comment">#See below</span></pre></td></tr><tr><td data-num="54"></td><td><pre>request_header_access X<span class="token punctuation">-</span>Forwarded<span class="token punctuation">-</span>For deny all</pre></td></tr><tr><td data-num="55"></td><td><pre><span class="token comment">######## 新版 ########</span></pre></td></tr></table></figure><div class="note primary">
<p>至次已经可以通过填写安装 squid 的服务器 ip 加端口 3128 加用户名密码进行代理访问了(通过访问<span class="blue"><span class="exturl" data-url="aHR0cHM6Ly93d3cuaXAuY24v"> https://www.ip.cn/</span></span> 查看 ip 就会发现自己的出口 ip 已经变成了 squid 服务器的 ip 了)。但是要想科学上网还必须对代理的数据进行加密,否则访问外网还是会被我国的长城防火墙阻挡,所以还需要安装 stunnel 来实现此目的。</p>
</div>
<h5 id="stunnel服务端部分"><a class="anchor" href="#stunnel服务端部分">#</a> stunnel 服务端部分</h5>
<ul>
<li>1、安装(和 squid 装在一起)</li>
</ul>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token function">apt-get</span> <span class="token function">install</span> <span class="token parameter variable">-y</span> stunnel</pre></td></tr></table></figure><ul>
<li>2、生成 TLS/SSL 证书</li>
</ul>
<figure class="highlight bash"><figcaption data-lang="bash"></figcaption><table><tr><td data-num="1"></td><td><pre>openssl req <span class="token parameter variable">-new</span> <span class="token parameter variable">-x509</span> <span class="token parameter variable">-days</span> <span class="token number">3650</span> <span class="token parameter variable">-nodes</span> <span class="token parameter variable">-out</span> stunnel.pem <span class="token parameter variable">-keyout</span> stunnel.pem</pre></td></tr></table></figure><ul>
<li>
<p>3、将证书 stunnel.pem 放到 /etc/stunnel/ 目录下</p>
</li>
<li>
<p>4、修改 stunnel 配置 (/etc/stunnle/stunnle.conf)</p>
</li>
</ul>
<figure class="highlight yaml"><figcaption data-lang="YAML"></figcaption><table><tr><td data-num="1"></td><td><pre>; 设置stunnel的pid文件路径</pre></td></tr><tr><td data-num="2"></td><td><pre>pid = /etc/stunnel/stunnel.pid</pre></td></tr><tr><td data-num="3"></td><td><pre>; 设置stunnel工作的用户(组)</pre></td></tr><tr><td data-num="4"></td><td><pre>setuid = root</pre></td></tr><tr><td data-num="5"></td><td><pre>setgid = root</pre></td></tr><tr><td data-num="6"></td><td><pre></pre></td></tr><tr><td data-num="7"></td><td><pre>; 开启日志等级:emerg (0)<span class="token punctuation">,</span> alert (1)<span class="token punctuation">,</span> crit (2)<span class="token punctuation">,</span> err (3)<span class="token punctuation">,</span> warning (4)<span class="token punctuation">,</span> notice (5)<span class="token punctuation">,</span> info (6)<span class="token punctuation">,</span> or debug (7)</pre></td></tr><tr><td data-num="8"></td><td><pre>debug = 7</pre></td></tr><tr><td data-num="9"></td><td><pre>; 日志文件路径</pre></td></tr><tr><td data-num="10"></td><td><pre>output = /etc/stunnel/stunnel.log</pre></td></tr><tr><td data-num="11"></td><td><pre></pre></td></tr><tr><td data-num="12"></td><td><pre>; 证书文件</pre></td></tr><tr><td data-num="13"></td><td><pre>cert = /etc/stunnel/stunnel.pem</pre></td></tr><tr><td data-num="14"></td><td><pre>; 私钥文件</pre></td></tr><tr><td data-num="15"></td><td><pre>key = /etc/stunnel/stunnel.pem</pre></td></tr><tr><td data-num="16"></td><td><pre></pre></td></tr><tr><td data-num="17"></td><td><pre>; 自定义服务名squid<span class="token punctuation">-</span>proxy</pre></td></tr><tr><td data-num="18"></td><td><pre><span class="token punctuation">[</span>squid<span class="token punctuation">-</span>proxy<span class="token punctuation">]</span></pre></td></tr><tr><td data-num="19"></td><td><pre>; 服务监听的端口,client要连接这个端口与server通信</pre></td></tr><tr><td data-num="20"></td><td><pre>accept = 1234(自定义)</pre></td></tr><tr><td data-num="21"></td><td><pre>; 服务要连接的端口,连接到squid的3128端口,将数据发给squid</pre></td></tr><tr><td data-num="22"></td><td><pre>connect = 3128</pre></td></tr></table></figure><h5 id="stunnel客户端部分"><a class="anchor" href="#stunnel客户端部分">#</a> stunnel 客户端部分</h5>
<div class="note info">
<p>可以安装在要代理的机器上,在需要代理的情况下再开启(代理地址填 127.0.0.1 加客户端监听端口)。也可以安装在国内的服务器上一直保持连接(代理信息填国内服务器 ip 加客户端监听端口)。本示例客户端为 windows 系统</p>
</div>
<ul>
<li>1、下载地址</li>
</ul>
<p><span class="blue"><span class="exturl" data-url="aHR0cHM6Ly93d3cuc3R1bm5lbC5vcmcvZG93bmxvYWRzLmh0bWw=">https://www.stunnel.org/downloads.html</span></span></p>
<ul>
<li>2、修改配置(C:\Program Files (x86)\stunnel\config\stunnel.conf)</li>
</ul>
<figure class="highlight yaml"><figcaption data-lang="YAML"></figcaption><table><tr><td data-num="1"></td><td><pre><span class="token punctuation">[</span>squid<span class="token punctuation">-</span>proxy<span class="token punctuation">]</span></pre></td></tr><tr><td data-num="2"></td><td><pre>client = yes</pre></td></tr><tr><td data-num="3"></td><td><pre>; 监听3128端口,那么用户浏览器的代理设置就是 stunnel<span class="token punctuation">-</span>client<span class="token punctuation">-</span>ip<span class="token punctuation">:</span><span class="token number">3128</span></pre></td></tr><tr><td data-num="4"></td><td><pre>accept = 3128</pre></td></tr><tr><td data-num="5"></td><td><pre>; 要连接到的stunnel server的ip与端口</pre></td></tr><tr><td data-num="6"></td><td><pre>connect = stunnel服务端ip<span class="token punctuation">:</span>1234(服务端自定义端口)</pre></td></tr><tr><td data-num="7"></td><td><pre></pre></td></tr><tr><td data-num="8"></td><td><pre>; 需要验证对方发过来的证书</pre></td></tr><tr><td data-num="9"></td><td><pre>verify = 2</pre></td></tr><tr><td data-num="10"></td><td><pre>; 用来进行证书验证的文件(stunnel服务端生成的证书复制到以下目录并改名为stunnel<span class="token punctuation">-</span>server.pem)</pre></td></tr><tr><td data-num="11"></td><td><pre>CAfile = C<span class="token punctuation">:</span>\Program Files (x86)\stunnel\config\stunnel<span class="token punctuation">-</span>server.pem</pre></td></tr></table></figure><div class="note primary">
<p>至次配置好代理 ip 为 stunnel 客户端 ip 加端口 3128 就可以正式科学上网了。如果只想对需要科学的 url 进行代理,可以通过安装 Proxy SwitchyOmega 插件实现(规则地址可通过<span class="blue"><span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2dmd2xpc3QvZ2Z3bGlzdA=="> https://github.com/gfwlist/gfwlist</span></span> 获取)。</p>
</div>
<p><img data-src="https://npic.hitoli.com:8443/images/2023/09/09/6a38fcb32752.png" alt="" /><br />
<img data-src="https://npic.hitoli.com:8443/images/2023/09/09/72892168bfeb.png" alt="" /></p>
2023-09-09T08:48:00.000Z