https://hitoli.com
涛声依旧
天下事有难易乎?为之,则难者亦易矣
https://hitoli.com/images/favicon.ico
Hito Li
2024-05-22T07:43: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>
<p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> xxx.util;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.io.FileUtil;</span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.io.file.FileAppender;</span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.io.file.FileReader;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WordConvertXmlHandle</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> <span class="comment">//文件读取-FileReader</span></span><br><span class="line"> <span class="comment">//默认UTF-8编码,可以在构造中传入第二个参数作为编码</span></span><br><span class="line"> <span class="type">FileReader</span> <span class="variable">fileReader</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileReader</span>(<span class="string">"D:\\mb.xml"</span>);</span><br><span class="line"> <span class="comment">//从文件中读取每一行数据</span></span><br><span class="line"> List<String> strings = fileReader.readLines();</span><br><span class="line"> <span class="comment">//文件追加-FileAppender</span></span><br><span class="line"> <span class="comment">//destFile – 目标文件</span></span><br><span class="line"> <span class="comment">//capacity – 当行数积累多少条时刷入到文件</span></span><br><span class="line"> <span class="comment">//isNewLineMode – 追加内容是否为新行</span></span><br><span class="line"> <span class="type">FileAppender</span> <span class="variable">appender</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileAppender</span>(FileUtil.newFile(<span class="string">"D:\\mb.ftl"</span>), <span class="number">16</span>, <span class="literal">true</span>);</span><br><span class="line"> <span class="comment">//遍历得到每一行数据</span></span><br><span class="line"> <span class="keyword">for</span> (String string : strings) {</span><br><span class="line"> <span class="comment">//判断每一行数据中不包含'$'的数据先添加进新文件</span></span><br><span class="line"> <span class="keyword">if</span> (!string.contains(<span class="string">"$"</span>)) {</span><br><span class="line"> appender.append(string);</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//如果一行数据中包含'$'变量符将替换为'#$'</span></span><br><span class="line"> string = string.replaceAll(<span class="string">"\\$"</span>, <span class="string">"#\\$"</span>);</span><br><span class="line"> <span class="comment">//然后以'#'切割成每一行(数组),这样一来'$'都将在每一行的开头</span></span><br><span class="line"> String[] ss = string.split(<span class="string">"#"</span>);</span><br><span class="line"> <span class="comment">// 同一行的数据写到同一行,文件追加自动换行了(最后的完整数据)</span></span><br><span class="line"> <span class="type">StringBuilder</span> <span class="variable">sb</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringBuilder</span>();</span><br><span class="line"> <span class="comment">//遍历每一行(数组ss)</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < ss.length; i++) {</span><br><span class="line"> <span class="comment">//暂存数据</span></span><br><span class="line"> <span class="type">String</span> <span class="variable">s1</span> <span class="operator">=</span> ss[i];</span><br><span class="line"> <span class="comment">//将不是以'$'开头的行数据放进StringBuilder</span></span><br><span class="line"> <span class="keyword">if</span> (!s1.startsWith(<span class="string">"$"</span>)) {</span><br><span class="line"> sb.append(s1);</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//被分离的数据一般都是'${'这样被分开</span></span><br><span class="line"> <span class="comment">//匹配以'$'开头的变量找到'}' 得到索引位置</span></span><br><span class="line"> <span class="type">int</span> <span class="variable">i1</span> <span class="operator">=</span> s1.lastIndexOf(<span class="string">"}"</span>);</span><br><span class="line"> <span class="comment">//先切割得到这个完整体</span></span><br><span class="line"> <span class="type">String</span> <span class="variable">substr</span> <span class="operator">=</span> s1.substring(<span class="number">0</span>, i1 + <span class="number">1</span>);</span><br><span class="line"> <span class="comment">//把变量追加到StringBuilder</span></span><br><span class="line"> sb.append(substr.replaceAll(<span class="string">"<[^>]+>"</span>, <span class="string">""</span>));</span><br><span class="line"> <span class="comment">//再将标签数据追加到StringBuilder包裹变量</span></span><br><span class="line"> sb.append(s1.substring(i1 + <span class="number">1</span>));</span><br><span class="line"> }</span><br><span class="line"> appender.append(sb.toString());</span><br><span class="line"> }</span><br><span class="line"> appender.flush();</span><br><span class="line"> appender.toString();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
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>
<blockquote>
<p>本文章介绍的是如何对单表进行分区。</p>
</blockquote>
<h6 id="给表添加分区"><a class="anchor" href="#给表添加分区">#</a> 给表添加分区</h6>
<p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ALTER</span> <span class="keyword">TABLE</span> 表名</span><br><span class="line"><span class="keyword">PARTITION</span> <span class="keyword">BY</span> <span class="keyword">RANGE</span> COLUMNS (时间字段名) (</span><br><span class="line"> <span class="comment">-- 分区条件(时间小于2022-02-01的数据放入p202201分区中)</span></span><br><span class="line"> <span class="keyword">PARTITION</span> p202201 <span class="keyword">VALUES</span> LESS THAN (<span class="string">'2022-02-01'</span>),</span><br><span class="line"> <span class="keyword">PARTITION</span> p202202 <span class="keyword">VALUES</span> LESS THAN (<span class="string">'2022-03-01'</span>),</span><br><span class="line"> <span class="keyword">PARTITION</span> p202203 <span class="keyword">VALUES</span> LESS THAN (<span class="string">'2022-04-01'</span>),</span><br><span class="line"> <span class="comment">-- 继续定义更多的分区...</span></span><br><span class="line">);</span><br></pre></td></tr></table></figure></p>
<h6 id="按指定表名创建当前年月的分区"><a class="anchor" href="#按指定表名创建当前年月的分区">#</a> 按指定表名创建当前年月的分区</h6>
<p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">PROCEDURE</span> create_monthly_partition(<span class="keyword">IN</span> tableName <span class="type">VARCHAR</span>(<span class="number">255</span>))</span><br><span class="line"><span class="keyword">BEGIN</span></span><br><span class="line"> <span class="keyword">DECLARE</span> currentYear <span class="type">INT</span>;</span><br><span class="line"> <span class="keyword">DECLARE</span> currentMonth <span class="type">INT</span>;</span><br><span class="line"> <span class="keyword">DECLARE</span> nextYear <span class="type">INT</span>;</span><br><span class="line"> <span class="keyword">DECLARE</span> nextMonth <span class="type">INT</span>;</span><br><span class="line"> <span class="keyword">DECLARE</span> partitionName <span class="type">VARCHAR</span>(<span class="number">255</span>);</span><br><span class="line"> <span class="keyword">SET</span> currentYear <span class="operator">=</span> <span class="keyword">YEAR</span>(<span class="built_in">CURRENT_DATE</span>);</span><br><span class="line"> <span class="keyword">SET</span> currentMonth <span class="operator">=</span> <span class="keyword">MONTH</span>(<span class="built_in">CURRENT_DATE</span>);</span><br><span class="line"> <span class="comment">-- 计算下一个月的年份和月份</span></span><br><span class="line"> IF currentMonth <span class="operator">=</span> <span class="number">12</span> <span class="keyword">THEN</span></span><br><span class="line"> <span class="keyword">SET</span> nextYear <span class="operator">=</span> currentYear <span class="operator">+</span> <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">SET</span> nextMonth <span class="operator">=</span> <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">ELSE</span></span><br><span class="line"> <span class="keyword">SET</span> nextYear <span class="operator">=</span> currentYear;</span><br><span class="line"> <span class="keyword">SET</span> nextMonth <span class="operator">=</span> currentMonth <span class="operator">+</span> <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">END</span> IF;</span><br><span class="line"> <span class="keyword">SET</span> partitionName <span class="operator">=</span> CONCAT(<span class="string">'p'</span>, currentYear, LPAD(currentMonth, <span class="number">2</span>, <span class="number">0</span>));</span><br><span class="line"> <span class="keyword">SET</span> <span class="variable">@sql</span> <span class="operator">=</span> CONCAT(<span class="string">'ALTER TABLE '</span>, tableName, </span><br><span class="line"> <span class="string">' ADD PARTITION (PARTITION '</span>, partitionName,</span><br><span class="line"> <span class="string">' VALUES LESS THAN (\'', nextYear, '</span><span class="operator">-</span><span class="string">', LPAD(nextMonth, 2, 0), '</span><span class="number">-01</span>\<span class="string">''</span>, <span class="string">'))'</span>);</span><br><span class="line"> <span class="keyword">PREPARE</span> stmt <span class="keyword">FROM</span> <span class="variable">@sql</span>;</span><br><span class="line"> <span class="keyword">EXECUTE</span> stmt;</span><br><span class="line"> <span class="keyword">DEALLOCATE</span> <span class="keyword">PREPARE</span> stmt;</span><br><span class="line"><span class="keyword">END</span></span><br></pre></td></tr></table></figure></p>
<h6 id="调用创建新分区"><a class="anchor" href="#调用创建新分区">#</a> 调用创建新分区</h6>
<p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CALL</span> create_monthly_partition(<span class="string">'表名'</span>);</span><br></pre></td></tr></table></figure></p>
<h6 id="删除指定分区"><a class="anchor" href="#删除指定分区">#</a> 删除指定分区</h6>
<p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">ALTER</span> <span class="keyword">TABLE</span> dmpdb.stll_monitdata <span class="keyword">drop</span> <span class="keyword">PARTITION</span> 分区名;</span><br></pre></td></tr></table></figure></p>
<h6 id="每月执行一次调用指定表添加新分区"><a class="anchor" href="#每月执行一次调用指定表添加新分区">#</a> 每月执行一次调用指定表添加新分区</h6>
<p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> EVENT create_monthly_partition_event</span><br><span class="line"><span class="keyword">ON</span> SCHEDULE <span class="keyword">EVERY</span> <span class="number">1</span> <span class="keyword">MONTH</span> </span><br><span class="line">STARTS <span class="string">'2024-01-01 00:00:00'</span></span><br><span class="line">DO</span><br><span class="line"><span class="keyword">BEGIN</span></span><br><span class="line"> <span class="comment">-- 定义需要分区的表名列表</span></span><br><span class="line"> <span class="keyword">SET</span> <span class="variable">@tables</span> <span class="operator">=</span> <span class="string">'表名1,表名2'</span>;</span><br><span class="line"> <span class="comment">-- 遍历表名列表并为每个表创建分区</span></span><br><span class="line"> WHILE <span class="keyword">CHAR_LENGTH</span>(<span class="variable">@tables</span>) <span class="operator">></span> <span class="number">0</span> DO</span><br><span class="line"> <span class="keyword">SET</span> <span class="variable">@tableName</span> <span class="operator">=</span> SUBSTRING_INDEX(<span class="variable">@tables</span>, <span class="string">','</span>, <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">SET</span> <span class="variable">@tables</span> <span class="operator">=</span> <span class="built_in">SUBSTRING</span>(<span class="variable">@tables</span>, <span class="keyword">CHAR_LENGTH</span>(<span class="variable">@tableName</span>) <span class="operator">+</span> <span class="number">2</span>);</span><br><span class="line"> <span class="keyword">CALL</span> create_monthly_partition(<span class="variable">@tableName</span>);</span><br><span class="line"> <span class="keyword">END</span> WHILE;</span><br><span class="line"><span class="keyword">END</span></span><br></pre></td></tr></table></figure></p>
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后端禁止接口瞬时重复调用
<h6 id="简介"><a class="anchor" href="#简介">#</a> 简介</h6>
<p>由于前端会莫名其妙的对同一接口请求多次,从而占用后端资源造成浪费。所以采用了后端拦截相关重复请求的方案。此方案会将请求用户 id 加接口 url 加参数作为 key,请求时间作为 value,使用 ConcurrentHashMap 进行缓存。如果下次相同的请求和上次请求的时间在指定的范围内则认为此请求属于重复请求。</p>
<h6 id="自定义可重复读request"><a class="anchor" href="#自定义可重复读request">#</a> 自定义可重复读 Request</h6>
<p>request 的 body 只能读取一次,所以对其进行封装。<br />
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> xxx.support;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.alibaba.fastjson.JSON;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.servlet.ReadListener;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.ServletInputStream;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.http.HttpServletRequest;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.http.HttpServletRequestWrapper;</span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.nio.charset.StandardCharsets;</span><br><span class="line"><span class="keyword">import</span> java.util.Enumeration;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"><span class="keyword">import</span> java.util.Objects;</span><br><span class="line"><span class="keyword">import</span> java.util.TreeMap;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RepeatableReadHttpServletRequestWrapper</span> <span class="keyword">extends</span> <span class="title class_">HttpServletRequestWrapper</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="type">byte</span>[] requestBody;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">RepeatableReadHttpServletRequestWrapper</span><span class="params">(HttpServletRequest request)</span> <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="built_in">super</span>(request);</span><br><span class="line"> <span class="built_in">this</span>.requestBody = readRequestBody(request);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="type">byte</span>[] readRequestBody(HttpServletRequest request) <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="keyword">try</span> (<span class="type">InputStream</span> <span class="variable">inputStream</span> <span class="operator">=</span> request.getInputStream();</span><br><span class="line"> <span class="type">ByteArrayOutputStream</span> <span class="variable">result</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayOutputStream</span>()) {</span><br><span class="line"></span><br><span class="line"> <span class="type">byte</span>[] buffer = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">1024</span>];</span><br><span class="line"> <span class="type">int</span> length;</span><br><span class="line"> <span class="keyword">while</span> ((length = inputStream.read(buffer)) != -<span class="number">1</span>) {</span><br><span class="line"> result.write(buffer, <span class="number">0</span>, length);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> result.toByteArray();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> ServletInputStream <span class="title function_">getInputStream</span><span class="params">()</span> <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="comment">// 直接使用 ByteArrayInputStream,它提供可重复读取的输入流</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ServletInputStream</span>() {</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="type">ByteArrayInputStream</span> <span class="variable">byteArrayInputStream</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayInputStream</span>(requestBody);</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">read</span><span class="params">()</span> <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="keyword">return</span> byteArrayInputStream.read();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isFinished</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> byteArrayInputStream.available() == <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isReady</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setReadListener</span><span class="params">(ReadListener readListener)</span> {</span><br><span class="line"> <span class="comment">// 不需要实现,可以留空</span></span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> BufferedReader <span class="title function_">getReader</span><span class="params">()</span> <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="comment">// 使用 InputStreamReader 包装 ByteArrayInputStream,提供可重复读取的字符流</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">BufferedReader</span>(<span class="keyword">new</span> <span class="title class_">InputStreamReader</span>(<span class="keyword">new</span> <span class="title class_">ByteArrayInputStream</span>(requestBody)));</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 获取json格式的参数</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> String <span class="title function_">getParamsToJSONString</span><span class="params">()</span> {</span><br><span class="line"> <span class="type">String</span> <span class="variable">jsonStr</span> <span class="operator">=</span> <span class="string">""</span>;</span><br><span class="line"> <span class="keyword">if</span> (<span class="string">"POST"</span>.equals(<span class="built_in">this</span>.getMethod().toUpperCase()) && <span class="built_in">this</span>.isJsonRequest()) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> jsonStr = <span class="built_in">this</span>.readJsonData();</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> log.error(e.getMessage());</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> Enumeration<String> parameterNames = <span class="built_in">this</span>.getParameterNames();</span><br><span class="line"> <span class="keyword">if</span> (Objects.nonNull(parameterNames) && parameterNames.hasMoreElements()) {</span><br><span class="line"> <span class="comment">// 将参数排序后转为json</span></span><br><span class="line"> Map<String, String> paramsMap = <span class="keyword">new</span> <span class="title class_">TreeMap</span><>();</span><br><span class="line"> <span class="keyword">while</span> (parameterNames.hasMoreElements()) {</span><br><span class="line"> <span class="type">String</span> <span class="variable">paramName</span> <span class="operator">=</span> parameterNames.nextElement();</span><br><span class="line"> paramsMap.put(paramName, <span class="built_in">this</span>.getParameter(paramName));</span><br><span class="line"> }</span><br><span class="line"> jsonStr = JSON.toJSONString(paramsMap);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> jsonStr;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 判断是否json请求</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="type">boolean</span> <span class="title function_">isJsonRequest</span><span class="params">()</span> {</span><br><span class="line"> <span class="type">String</span> <span class="variable">contentType</span> <span class="operator">=</span> <span class="built_in">this</span>.getContentType();</span><br><span class="line"> <span class="keyword">return</span> contentType != <span class="literal">null</span> && contentType.toLowerCase().contains(<span class="string">"application/json"</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 获取json格式的参数</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> IOException</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> String <span class="title function_">readJsonData</span><span class="params">()</span> <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">String</span>(<span class="built_in">this</span>.readRequestBody(<span class="built_in">this</span>), StandardCharsets.UTF_8);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<h6 id="重复请求过滤器"><a class="anchor" href="#重复请求过滤器">#</a> 重复请求过滤器</h6>
<p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> xxx.filter;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.collection.CollectionUtil;</span><br><span class="line"><span class="keyword">import</span> xxx.RepeatableReadHttpServletRequestWrapper;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.actuate.endpoint.web.WebEndpointResponse;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.web.util.matcher.RequestMatcher;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.filter.OncePerRequestFilter;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.servlet.FilterChain;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.ServletException;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.http.HttpServletRequest;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.http.HttpServletResponse;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"><span class="keyword">import</span> java.util.Objects;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ConcurrentHashMap;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DuplicateRequestFilter</span> <span class="keyword">extends</span> <span class="title class_">OncePerRequestFilter</span> {</span><br><span class="line"> <span class="comment">// 是否启用</span></span><br><span class="line"> <span class="keyword">private</span> Boolean duplicateRequestFilter;</span><br><span class="line"> <span class="comment">// 间隔时间(毫秒)</span></span><br><span class="line"> <span class="keyword">private</span> Long intervalTime;</span><br><span class="line"> <span class="comment">// 清除缓存时间(毫秒)</span></span><br><span class="line"> <span class="keyword">private</span> Long clearCachetime;</span><br><span class="line"> <span class="comment">// 放行url</span></span><br><span class="line"> <span class="keyword">private</span> List<RequestMatcher> permitAll;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">DuplicateRequestFilter</span><span class="params">(Boolean duplicateRequestFilter, List<RequestMatcher> permitAll, Long intervalTime,</span></span><br><span class="line"><span class="params"> Long clearCachetime)</span> {</span><br><span class="line"> <span class="built_in">this</span>.duplicateRequestFilter = duplicateRequestFilter;</span><br><span class="line"> <span class="built_in">this</span>.permitAll = permitAll;</span><br><span class="line"> <span class="built_in">this</span>.intervalTime = intervalTime;</span><br><span class="line"> <span class="built_in">this</span>.clearCachetime = clearCachetime;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 存储参数和请求时间</span></span><br><span class="line"> <span class="keyword">private</span> Map<String, Long> requestCache = <span class="keyword">new</span> <span class="title class_">ConcurrentHashMap</span><>();</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">doFilterInternal</span><span class="params">(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)</span></span><br><span class="line"> <span class="keyword">throws</span> ServletException, IOException {</span><br><span class="line"> <span class="type">boolean</span> <span class="variable">doFilter</span> <span class="operator">=</span> <span class="literal">true</span>;</span><br><span class="line"> <span class="comment">// 使用 ContentCachingRequestWrapper 包装原始请求</span></span><br><span class="line"> <span class="type">RepeatableReadHttpServletRequestWrapper</span> <span class="variable">wrappedRequest</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">this</span>.duplicateRequestFilter) {</span><br><span class="line"> <span class="comment">// 判断请求路径是否需要放行</span></span><br><span class="line"> <span class="type">boolean</span> <span class="variable">permit</span> <span class="operator">=</span> <span class="literal">false</span>;</span><br><span class="line"> <span class="keyword">if</span> (CollectionUtil.isNotEmpty(<span class="built_in">this</span>.permitAll)) {</span><br><span class="line"> <span class="keyword">for</span> (RequestMatcher matcher: <span class="built_in">this</span>.permitAll) {</span><br><span class="line"> <span class="keyword">if</span> (matcher.matches(request)) {</span><br><span class="line"> permit = <span class="literal">true</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (!permit) {</span><br><span class="line"> <span class="keyword">if</span> (request <span class="keyword">instanceof</span> RepeatableReadHttpServletRequestWrapper) {</span><br><span class="line"> wrappedRequest = (RepeatableReadHttpServletRequestWrapper) request;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> wrappedRequest = <span class="keyword">new</span> <span class="title class_">RepeatableReadHttpServletRequestWrapper</span>(request);</span><br><span class="line"> }</span><br><span class="line"> doFilter = <span class="built_in">this</span>.isValid(wrappedRequest);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (doFilter) {</span><br><span class="line"> <span class="comment">// 继续处理请求</span></span><br><span class="line"> filterChain.doFilter(Objects.nonNull(wrappedRequest) ? wrappedRequest : request, response);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> response.setContentType(<span class="string">"application/json"</span>);</span><br><span class="line"> response.setStatus(WebEndpointResponse.STATUS_TOO_MANY_REQUESTS);</span><br><span class="line"><span class="comment">// response.setStatus(HttpServletResponse.SC_OK);</span></span><br><span class="line"><span class="comment">// ObjectMapper mapper = new ObjectMapper();</span></span><br><span class="line"><span class="comment">// mapper.writeValue(response.getOutputStream(), R.error(WebEndpointResponse.STATUS_TOO_MANY_REQUESTS, "重复的请求"));</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 验证请求的有效性(判断是否重复请求)</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> request</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="type">boolean</span> <span class="title function_">isValid</span><span class="params">(RepeatableReadHttpServletRequestWrapper request)</span> {</span><br><span class="line"> <span class="type">boolean</span> <span class="variable">valid</span> <span class="operator">=</span> <span class="literal">true</span>;</span><br><span class="line"> <span class="comment">// 缓存的key</span></span><br><span class="line"> <span class="type">String</span> <span class="variable">key</span> <span class="operator">=</span> TokenUtil.getUidByToken() + <span class="string">"_"</span> + request.getServletPath() + <span class="string">"_"</span> + request.getParamsToJSONString();</span><br><span class="line"> <span class="comment">// 获取之前的请求时间</span></span><br><span class="line"> <span class="type">Long</span> <span class="variable">previousRequestTime</span> <span class="operator">=</span> requestCache.get(key);</span><br><span class="line"> <span class="keyword">if</span> (previousRequestTime != <span class="literal">null</span>) {</span><br><span class="line"> <span class="comment">// 如果距离上次请求时间很短(例如1秒),则拒绝当前请求</span></span><br><span class="line"> <span class="keyword">if</span> (System.currentTimeMillis() - previousRequestTime < <span class="built_in">this</span>.intervalTime) {</span><br><span class="line"> valid = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">this</span>.clearOldRequests();</span><br><span class="line"> <span class="comment">// 缓存当前请求时间</span></span><br><span class="line"> requestCache.put(key, System.currentTimeMillis());</span><br><span class="line"> <span class="keyword">return</span> valid;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 用于清除缓存中的旧请求数据,防止缓存无限增长</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">clearOldRequests</span><span class="params">()</span> {</span><br><span class="line"> requestCache.entrySet().removeIf(entry -> System.currentTimeMillis() - entry.getValue() > <span class="built_in">this</span>.clearCachetime);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<h6 id="配置oauth2资源"><a class="anchor" href="#配置oauth2资源">#</a> 配置 OAuth2 资源</h6>
<p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> xxx.config;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> xxx.AuthExceptionEntryPoint;</span><br><span class="line"><span class="keyword">import</span> xxx.CustomAccessDeniedHandler;</span><br><span class="line"><span class="keyword">import</span> xxx.DuplicateRequestFilter;</span><br><span class="line"><span class="keyword">import</span> org.slf4j.Logger;</span><br><span class="line"><span class="keyword">import</span> org.slf4j.LoggerFactory;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Qualifier;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.annotation.Value;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Bean;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.annotation.Configuration;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.config.annotation.web.builders.HttpSecurity;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.oauth2.provider.token.TokenStore;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.web.util.matcher.AntPathRequestMatcher;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.servlet.Filter;</span><br><span class="line"><span class="keyword">import</span> java.util.Arrays;</span><br><span class="line"><span class="keyword">import</span> java.util.stream.Collectors;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@EnableResourceServer</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ResourceServerConfig</span> <span class="keyword">extends</span> <span class="title class_">ResourceServerConfigurerAdapter</span> {</span><br><span class="line"></span><br><span class="line"> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(ResourceServerConfig.class);</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Autowired</span></span><br><span class="line"> <span class="keyword">private</span> TokenStore tokenStore;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 是否开放所有接口</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Value("${http.security.permitAll:false}")</span></span><br><span class="line"> <span class="keyword">private</span> Boolean isPermitAll;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 是否启用重复请求过滤</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Value("${request.duplicateFilter.enabled:true}")</span></span><br><span class="line"> <span class="keyword">private</span> Boolean duplicateRequestFilter;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 间隔时间(毫秒)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Value("${request.duplicateFilter.interval_time:1000}")</span></span><br><span class="line"> <span class="keyword">private</span> Long intervalTime;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 清除缓存时间(毫秒)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Value("${request.duplicateFilter.clear_cache_time:30000}")</span></span><br><span class="line"> <span class="keyword">private</span> Long clearCachetime;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 不需要验证权限的接口</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">private</span> String[] permitAll = <span class="keyword">new</span> <span class="title class_">String</span>[] {</span><br><span class="line"> <span class="string">"/auth/getVCode"</span>, <span class="string">"/auth/login"</span></span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 通行规则</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> http</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@throws</span> Exception</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">configure</span><span class="params">(HttpSecurity http)</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"> <span class="type">HttpSecurity</span> <span class="variable">httpSecurity</span> <span class="operator">=</span> http.csrf().disable();</span><br><span class="line"> <span class="keyword">if</span> (isPermitAll) {</span><br><span class="line"> httpSecurity.authorizeRequests().antMatchers(<span class="string">"/**"</span>).permitAll();</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> httpSecurity.authorizeRequests()</span><br><span class="line"> .antMatchers(permitAll).permitAll()</span><br><span class="line"> .antMatchers(<span class="string">"/**"</span>).authenticated();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (<span class="built_in">this</span>.duplicateRequestFilter) {</span><br><span class="line"> httpSecurity.addFilterAfter(duplicateRequestFilter(), AbstractPreAuthenticatedProcessingFilter.class);</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//让X-frame-options失效,去除iframe限制</span></span><br><span class="line"> http.headers().frameOptions().disable();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">configure</span><span class="params">(ResourceServerSecurityConfigurer resources)</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"> resources.tokenStore(tokenStore).authenticationEntryPoint(<span class="keyword">new</span> <span class="title class_">AuthExceptionEntryPoint</span>())</span><br><span class="line"> .accessDeniedHandler(<span class="keyword">new</span> <span class="title class_">CustomAccessDeniedHandler</span>());</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="keyword">public</span> Filter <span class="title function_">duplicateRequestFilter</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">DuplicateRequestFilter</span>(<span class="built_in">this</span>.duplicateRequestFilter, Arrays.asList(<span class="built_in">this</span>.permitAll)</span><br><span class="line"> .stream().map(AntPathRequestMatcher::<span class="keyword">new</span>).collect(Collectors.toList()), <span class="built_in">this</span>.intervalTime,</span><br><span class="line"> <span class="built_in">this</span>.clearCachetime);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
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>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#原版</span></span><br><span class="line">docker run -d --restart=always --name=<span class="string">"portainer"</span> -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v D:\docker\portainer\data:/data portainer/portainer-ce</span><br><span class="line"></span><br><span class="line"><span class="comment">#汉化版</span></span><br><span class="line">docker run -d --restart=always --name=<span class="string">"portainer"</span> -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v D:\docker\portainer\data:/data 6053537/portainer-ce</span><br></pre></td></tr></table></figure></p>
<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://nas.hitoli.com:18014/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://nas.hitoli.com:18014/images/2024/01/19/58082ccf2487.png" alt="" /></p>
<p><img data-src="https://nas.hitoli.com:18014/images/2024/01/19/3097ede8d80c.png" alt="" /></p>
<p><img data-src="https://nas.hitoli.com:18014/images/2024/01/19/31412cdf03de.png" alt="" /></p>
<h4 id="填写maven命令"><a class="anchor" href="#填写maven命令">#</a> 填写 Maven 命令</h4>
<p>Working directory 选择根目录,命令是基于选中的目录为执行目录,Run 填写以下命令</p>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">clean package -pl emergency-dzdz/dzdz-yzt -am -Dmaven.test.skip=<span class="literal">true</span> -f pom.xml</span><br><span class="line">或者</span><br><span class="line">clean install -pl emergency-dzdz/dzdz-yzt -am -Dmaven.test.skip=<span class="literal">true</span> -f pom.xml</span><br><span class="line"></span><br><span class="line">clean: 这个命令会删除目标目录(target),确保每次构建是干净的。</span><br><span class="line">install: 这个命令会将项目打包,并安装到本地的 Maven 仓库中。</span><br><span class="line">-pl emergency-dzdz/dzdz-yzt: -pl 参数指定要构建的项目模块。dzdz-yzt 是模块的名称。这个参数告诉 Maven 只构建 dzdz-yzt 及其依赖的模块。注意模块路径,此处是构建emergency-dzdz下的dzdz-yzt模块。</span><br><span class="line">-am: -am 参数与 -pl 一起使用,表示还要构建 dzdz-yzt 模块所依赖的所有模块。</span><br><span class="line">package: 这个命令会将项目打包为 JAR 文件或 WAR 文件,取决于项目类型。</span><br><span class="line">-f pom.xml: 这个参数指定要使用的 pom.xml 文件。默认情况下,Maven 会在当前目录下查找 pom.xml 文件,但可以通过此参数指定一个不同的位置。</span><br><span class="line">-DskipTests=<span class="literal">true</span>:跳过测试的执行,但会编译测试代码。</span><br><span class="line">-Dmaven.test.skip=<span class="literal">true</span>:跳过测试的编译和执行。</span><br></pre></td></tr></table></figure></p>
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>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">openssl req -x509 -nodes -days 36500 -newkey rsa:2048 -subj <span class="string">"/C=国家/ST=省/L=市/O=机构"</span> -keyout CA-private.key -out CA-certificate.crt -reqexts v3_req -extensions v3_ca</span><br><span class="line"></span><br><span class="line"><span class="comment">#示例</span></span><br><span class="line">openssl req -x509 -nodes -days 36500 -newkey rsa:2048 -subj <span class="string">"/C=CN/ST=EZ/L=EZ/O=EZ"</span> -keyout CA-private.key -out CA-certificate.crt -reqexts v3_req -extensions v3_ca</span><br></pre></td></tr></table></figure></p>
<h4 id="生成自签名证书私钥"><a class="anchor" href="#生成自签名证书私钥">#</a> 生成自签名证书私钥</h4>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openssl genrsa -out private.key 2048</span><br></pre></td></tr></table></figure></p>
<h4 id="根据自签名证书私钥生成自签名证书申请文件"><a class="anchor" href="#根据自签名证书私钥生成自签名证书申请文件">#</a> 根据自签名证书私钥生成自签名证书申请文件</h4>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openssl req -new -key private.key -subj <span class="string">"/C=CN/ST=EZ/L=EZ/O=EZ/CN=192.168.2.117"</span> -sha256 -out private.csr</span><br></pre></td></tr></table></figure></p>
<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>
<p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">[ req ]</span><br><span class="line">default_bits = 1024</span><br><span class="line">distinguished_name = req_distinguished_name</span><br><span class="line">req_extensions = san</span><br><span class="line">extensions = san</span><br><span class="line">[ req_distinguished_name ]</span><br><span class="line">countryName = CN</span><br><span class="line">stateOrProvinceName = Definesys</span><br><span class="line">localityName = Definesys</span><br><span class="line">organizationName = Definesys</span><br><span class="line">[SAN]</span><br><span class="line">authorityKeyIdentifier=keyid,issuer</span><br><span class="line">basicConstraints=CA:FALSE</span><br><span class="line">keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment</span><br><span class="line">subjectAltName = IP:192.168.2.117</span><br></pre></td></tr></table></figure></p>
<h4 id="生成自签名证书有效期100年"><a class="anchor" href="#生成自签名证书有效期100年">#</a> 生成自签名证书(有效期 100 年)</h4>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openssl x509 -req -days 36500 -<span class="keyword">in</span> private.csr -CA CA-certificate.crt -CAkey CA-private.key -CAcreateserial -sha256 -out private.crt -extfile private.ext -extensions SAN</span><br></pre></td></tr></table></figure></p>
<h4 id="nginx的ssl证书配置"><a class="anchor" href="#nginx的ssl证书配置">#</a> nginx 的 ssl 证书配置</h4>
<p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">ssl_certificate_key</span> <span class="string">/usr/local/nginx/ssl/private.key;</span></span><br><span class="line"><span class="string">ssl_certificate</span> <span class="string">/usr/local/nginx/ssl/private.crt;</span></span><br></pre></td></tr></table></figure></p>
<h4 id="证书安装"><a class="anchor" href="#证书安装">#</a> 证书安装</h4>
<p>需要安装 CA-certificate.crt 到受信任的根证书颁发机构下,即可从浏览器正常访问且不会报不安全警告。</p>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#ssl测试</span></span><br><span class="line">openssl s_client -connect localhost:8080</span><br><span class="line"><span class="comment">#检查证书格式</span></span><br><span class="line">openssl x509 -<span class="keyword">in</span> private.crt -text -noout</span><br><span class="line">openssl rsa -<span class="keyword">in</span> private.key -check</span><br><span class="line"><span class="comment">#检查证书是否过期(确保 "notBefore" 小于当前日期,"notAfter" 大于当前日期)</span></span><br><span class="line">openssl x509 -<span class="keyword">in</span> private.crt -noout -dates</span><br><span class="line"><span class="comment">#查看证书链</span></span><br><span class="line">openssl x509 -<span class="keyword">in</span> private.crt -noout -issuer -subject</span><br></pre></td></tr></table></figure></p>
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<br />
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module --with-openssl=/home/openssl-3.2.0</span><br></pre></td></tr></table></figure></p>
<h4 id="编译"><a class="anchor" href="#编译">#</a> 编译</h4>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">make(不要make install)</span><br></pre></td></tr></table></figure></p>
<h4 id="备份"><a class="anchor" href="#备份">#</a> 备份</h4>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cp</span> /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old</span><br></pre></td></tr></table></figure></p>
<h4 id="更新"><a class="anchor" href="#更新">#</a> 更新</h4>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#关闭nginx</span></span><br><span class="line">nginx -s stop</span><br><span class="line"><span class="comment">#更新nginx</span></span><br><span class="line"><span class="built_in">cp</span> /root/nginx-1.24.0/objs/nginx /usr/local/nginx/sbin/</span><br><span class="line"><span class="comment">#启动nginx</span></span><br><span class="line">nginx</span><br></pre></td></tr></table></figure></p>
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>
<p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">create</span> database nacos</span><br></pre></td></tr></table></figure></p>
<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>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -d --restart=always --name=<span class="string">"nacos"</span> -e MODE=standalone -p 8848:8848 -p 9848:9848 nacos/nacos-server:latest</span><br></pre></td></tr></table></figure></p>
<h4 id="进入容器内修改文件权限"><a class="anchor" href="#进入容器内修改文件权限">#</a> 进入容器内修改文件权限</h4>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">chmod</span> 777 /home/nacos/conf</span><br><span class="line"><span class="built_in">chmod</span> 777 /home/nacos/data</span><br><span class="line"><span class="built_in">chmod</span> 777 /home/nacos/logs</span><br></pre></td></tr></table></figure></p>
<h4 id="拷贝文件到本地"><a class="anchor" href="#拷贝文件到本地">#</a> 拷贝文件到本地</h4>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">docker <span class="built_in">cp</span> nacos:/home/nacos/conf D:\docker\nacos\data\</span><br><span class="line">docker <span class="built_in">cp</span> nacos:/home/nacos/data D:\docker\nacos\data\</span><br><span class="line">docker <span class="built_in">cp</span> nacos:/home/nacos/logs D:\docker\nacos\data\</span><br></pre></td></tr></table></figure></p>
<h4 id="创建正式容器"><a class="anchor" href="#创建正式容器">#</a> 创建正式容器</h4>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -d --name nacos --restart=always --network my-net -p 8848:8848 -p 9848:9848 -p 9849:9849 -e MODE=standalone --privileged=<span class="literal">true</span> -e SPRING_DATASOURCE_PLATFORM=mysql -e MYSQL_SERVICE_HOST=mysql地址 -e MYSQL_SERVICE_PORT=mysql端口 -e MYSQL_SERVICE_USER=mysql用户名 -e MYSQL_SERVICE_PASSWORD=mysql密码 -e MYSQL_SERVICE_DB_NAME=nacos -e TIME_ZONE=<span class="string">'Asia/Shanghai'</span> -v D:\docker\nacos\data\logs:/home/nacos/logs -v D:\docker\nacos\data\data:/home/nacos/data -v D:\docker\nacos\data\conf:/home/nacos/conf nacos/nacos-server:latest</span><br></pre></td></tr></table></figure></p>
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 或空字符串的属性,特此记录一下后续好复用。<br />
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> String <span class="title function_">toJSONString</span><span class="params">(Object object)</span> {</span><br><span class="line"> SerializerFeature[] serializerFeatures = <span class="keyword">new</span> <span class="title class_">SerializerFeature</span>[] {</span><br><span class="line"> <span class="comment">//格式化时间</span></span><br><span class="line"> SerializerFeature.WriteDateUseDateFormat</span><br><span class="line"> };</span><br><span class="line"> <span class="keyword">return</span> JSON.toJSONString(object, <span class="keyword">new</span> <span class="title class_">ValueFilter</span>() {</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> Object <span class="title function_">process</span><span class="params">(Object object, String name, Object value)</span> {</span><br><span class="line"> <span class="comment">// 如果名称或者值为null或空字符串,则不序列化该属性</span></span><br><span class="line"> <span class="keyword">if</span> (name == <span class="literal">null</span> || (name <span class="keyword">instanceof</span> String && ((String) name).isEmpty()) ||</span><br><span class="line"> value == <span class="literal">null</span> || (value <span class="keyword">instanceof</span> String && ((String) value).isEmpty())) {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> value;</span><br><span class="line"> }</span><br><span class="line"> }, serializerFeatures);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></p>
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>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">export</span> CLOUD_HOME=`<span class="built_in">pwd</span>`</span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取当前目录中的第一个JAR文件的名称</span></span><br><span class="line">jar_file=$(find . -maxdepth 1 -<span class="built_in">type</span> f -name <span class="string">"*.jar"</span> | <span class="built_in">head</span> -n 1)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$jar_file</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> jar_file=<span class="variable">${jar_file#./}</span></span><br><span class="line"> <span class="comment">#echo "JAR文件的名称是: $jar_file"</span></span><br><span class="line"> jar_file_name=$(<span class="built_in">basename</span> <span class="string">"<span class="variable">$jar_file</span>"</span> .jar)</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"当前目录没有JAR文件."</span></span><br><span class="line"> <span class="built_in">exit</span></span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取当前目录中的第一个yml文件的名称</span></span><br><span class="line">yml_file=$(find . -maxdepth 1 -<span class="built_in">type</span> f -name <span class="string">"*.yml"</span> | <span class="built_in">head</span> -n 1)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$yml_file</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> yml_file=<span class="variable">${yml_file#./}</span></span><br><span class="line"> <span class="comment">#echo "YML文件的名称是: $yml_file"</span></span><br><span class="line"><span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"当前目录中没有YML文件."</span></span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line">pids=$(ps -ef | grep java | grep <span class="variable">$jar_file_name</span> | grep -v grep | awk <span class="string">'{print $2}'</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> pid <span class="keyword">in</span> <span class="variable">$pids</span>; <span class="keyword">do</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"<span class="variable">$jar_file_name</span> is running, pid="</span><span class="variable">$pid</span></span><br><span class="line"> <span class="built_in">exit</span> 0</span><br><span class="line"><span class="keyword">done</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"<span class="variable">$jar_file_name</span> is pedding..."</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">sleep</span> 3</span><br><span class="line"></span><br><span class="line">JAVA_OPTS=<span class="string">"-Djava.security.egd=file:/dev/./urandom -Dfile.encoding=UTF8"</span></span><br><span class="line">JAVA_OPTS=<span class="string">"<span class="variable">$JAVA_OPTS</span> -Dsun.jnu.encoding=UTF8 -Xms512m -Xmx1024m"</span></span><br><span class="line">JAVA_OPTS=<span class="string">"<span class="variable">$JAVA_OPTS</span> -Dpid.path=<span class="variable">$CLOUD_HOME</span>/temp -Dspring.config.additional-location=<span class="variable">$CLOUD_HOME</span>/<span class="variable">$yml_file</span>"</span></span><br><span class="line">JAVA_OPTS=<span class="string">"<span class="variable">$JAVA_OPTS</span> -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5007"</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">nohup</span> java <span class="variable">$JAVA_OPTS</span> -jar <span class="variable">$CLOUD_HOME</span>/<span class="variable">$jar_file</span> >/dev/null 2> <span class="variable">$CLOUD_HOME</span>/<span class="variable">$jar_file_name</span>.run &</span><br><span class="line"><span class="comment">#nohup java $JAVA_OPTS -jar $CLOUD_HOME/$jar_file > $CLOUD_HOME/$jar_file_name.run 2>&1 &</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"<span class="variable">$jar_file_name</span> started."</span></span><br></pre></td></tr></table></figure></p>
<div class="note info">
<p>拷贝以下代码放入 txt 文本,<span class="exturl" data-url="aHR0cDovL3huLS1zdG9wLXVoNWZ0MjJhOWs1YXBidS5zaA==">然后改为 stop.sh</span></p>
</div>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#!/bin/bash</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">export</span> CLOUD_HOME=`<span class="built_in">pwd</span>`</span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取当前目录中的第一个JAR文件的名称</span></span><br><span class="line">jar_file=$(find . -maxdepth 1 -<span class="built_in">type</span> f -name <span class="string">"*.jar"</span> | <span class="built_in">head</span> -n 1)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$jar_file</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> jar_file=<span class="variable">${jar_file#./}</span></span><br><span class="line"> <span class="comment">#echo "JAR文件的名称是: $jar_file"</span></span><br><span class="line"> jar_file_name=$(<span class="built_in">basename</span> <span class="string">"<span class="variable">$jar_file</span>"</span> .jar)</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"当前目录没有JAR文件."</span></span><br><span class="line"> <span class="built_in">exit</span></span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 获取当前目录中的第一个yml文件的名称</span></span><br><span class="line">yml_file=$(find . -maxdepth 1 -<span class="built_in">type</span> f -name <span class="string">"*.yml"</span> | <span class="built_in">head</span> -n 1)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> [ -n <span class="string">"<span class="variable">$yml_file</span>"</span> ]; <span class="keyword">then</span></span><br><span class="line"> yml_file=<span class="variable">${yml_file#./}</span></span><br><span class="line"> <span class="comment">#echo "YML文件的名称是: $yml_file"</span></span><br><span class="line"><span class="keyword">else</span></span><br><span class="line"> <span class="built_in">echo</span> <span class="string">"当前目录中没有YML文件."</span></span><br><span class="line"><span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line">pids=$(ps -ef | grep java | grep <span class="variable">$jar_file_name</span> | grep -v grep | awk <span class="string">'{print $2}'</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> pid <span class="keyword">in</span> <span class="variable">$pids</span>; <span class="keyword">do</span></span><br><span class="line"> <span class="built_in">kill</span> -9 <span class="variable">$pid</span></span><br><span class="line"><span class="keyword">done</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"<span class="variable">$jar_file_name</span> is stopping..."</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">sleep</span> 5</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> <span class="string">"<span class="variable">$jar_file_name</span> stopped."</span></span><br></pre></td></tr></table></figure></p>
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://nas.hitoli.com:18014/images/2023/10/29/c7b84a3d703a.jpg" alt="" /><br />
<img data-src="https://nas.hitoli.com:18014/images/2023/10/29/fd2e099d875d.jpg" alt="" /><br />
<img data-src="https://nas.hitoli.com:18014/images/2023/10/29/0fea7641ccde.jpg" alt="" /><br />
<img data-src="https://nas.hitoli.com:18014/images/2023/10/29/73c63c1438a8.jpg" alt="" /><br />
<img data-src="https://nas.hitoli.com:18014/images/2023/10/29/4c5d526af3e7.jpg" alt="" /><br />
<img data-src="https://nas.hitoli.com:18014/images/2023/10/29/4b9bcbecbca3.jpg" alt="" /><br />
<img data-src="https://nas.hitoli.com:18014/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>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line">@ECHO OFF</span><br><span class="line">setlocal enabledelayedexpansion</span><br><span class="line"></span><br><span class="line">REM 关闭上次进程</span><br><span class="line">SET <span class="string">"pidFile=pid.txt"</span></span><br><span class="line"><span class="keyword">if</span> exist <span class="string">"%pidFile%"</span> (</span><br><span class="line"> <span class="keyword">for</span> /f <span class="string">"usebackq"</span> %%a <span class="keyword">in</span> (<span class="string">"pid.txt"</span>) <span class="keyword">do</span> (</span><br><span class="line"> <span class="built_in">set</span> PID=%%a</span><br><span class="line"> )</span><br><span class="line"> <span class="keyword">if</span> not <span class="string">"!PID!"</span>==<span class="string">""</span> (</span><br><span class="line"> taskkill /F /T /PID !pid!</span><br><span class="line"> del pid.txt</span><br><span class="line"> )</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">REM 存储当前进程</span><br><span class="line"><span class="keyword">for</span> /f %%i <span class="keyword">in</span> (<span class="string">'wmic process where "name='</span>cmd.exe<span class="string">' and CommandLine like '</span>%%<scriptname>.bat%%<span class="string">'" get ParentProcessId ^| findstr /r "[0-9]"'</span>) <span class="keyword">do</span> <span class="built_in">set</span> pid=%%i</span><br><span class="line"><span class="built_in">echo</span> %PID% > pid.txt</span><br><span class="line"></span><br><span class="line">REM 设置title</span><br><span class="line"><span class="keyword">for</span> /f <span class="string">"tokens=2"</span> %%i <span class="keyword">in</span> (<span class="string">'chcp'</span>) <span class="keyword">do</span> <span class="built_in">set</span> codepage=%%i</span><br><span class="line">chcp 65001 > nul</span><br><span class="line">title 我的SpringBoot项目</span><br><span class="line">chcp %codepage% > nul</span><br><span class="line"></span><br><span class="line"><span class="built_in">cd</span> %~dp0</span><br><span class="line"></span><br><span class="line">REM 获取jar</span><br><span class="line"><span class="built_in">set</span> <span class="string">"jarFile="</span></span><br><span class="line"><span class="keyword">for</span> %%i <span class="keyword">in</span> (*.jar) <span class="keyword">do</span> (</span><br><span class="line"> <span class="keyword">if</span> not defined jarFile (</span><br><span class="line"> <span class="built_in">set</span> <span class="string">"jarFile=%%i"</span></span><br><span class="line"> )</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> not defined jarFile (</span><br><span class="line"> <span class="built_in">echo</span> not find jar</span><br><span class="line"> pause</span><br><span class="line"> <span class="built_in">exit</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">SET JAVA_OPTS=-Djava.security.egd=file:/dev/./urandom -Dfile.encoding=UTF-8</span><br><span class="line"><span class="built_in">set</span> JAVA_OPTS=%JAVA_OPTS% -Dsun.jnu.encoding=UTF8 -Xms512m -Xmx1024m</span><br><span class="line"><span class="built_in">set</span> JAVA_OPTS=%JAVA_OPTS% -agentlib:jdwp=transport=dt_socket,server=y,<span class="built_in">suspend</span>=n,address=5007</span><br><span class="line"><span class="built_in">set</span> JAVA_OPTS=%JAVA_OPTS% -Dpid.path=./temp</span><br><span class="line"></span><br><span class="line">REM 获取yml</span><br><span class="line"><span class="built_in">set</span> <span class="string">"ymlFile="</span></span><br><span class="line"><span class="keyword">for</span> %%i <span class="keyword">in</span> (*.yml) <span class="keyword">do</span> (</span><br><span class="line"> <span class="keyword">if</span> not defined ymlFile (</span><br><span class="line"> <span class="built_in">set</span> <span class="string">"ymlFile=%%i"</span></span><br><span class="line"> )</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> defined ymlFile (</span><br><span class="line"> <span class="built_in">set</span> JAVA_OPTS=%JAVA_OPTS% -Dspring.config.additional-location=!ymlFile!</span><br><span class="line">) <span class="keyword">else</span> (</span><br><span class="line"> <span class="built_in">echo</span> not find yml</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">REM 启动服务</span><br><span class="line">java %JAVA_OPTS% -jar !jarFile!</span><br><span class="line">pause</span><br></pre></td></tr></table></figure></p>
<div class="note info">
<p>拷贝以下代码放入 txt 文本,然后改为 stop.bat</p>
</div>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">@ECHO OFF</span><br><span class="line">setlocal enabledelayedexpansion</span><br><span class="line"></span><br><span class="line">REM 关闭上次进程</span><br><span class="line">SET <span class="string">"pidFile=pid.txt"</span></span><br><span class="line"><span class="keyword">if</span> exist <span class="string">"%pidFile%"</span> (</span><br><span class="line"> <span class="keyword">for</span> /f <span class="string">"usebackq"</span> %%a <span class="keyword">in</span> (<span class="string">"pid.txt"</span>) <span class="keyword">do</span> (</span><br><span class="line"> <span class="built_in">set</span> PID=%%a</span><br><span class="line"> )</span><br><span class="line"> <span class="keyword">if</span> not <span class="string">"!PID!"</span>==<span class="string">""</span> (</span><br><span class="line"> taskkill /F /T /PID !pid!</span><br><span class="line"> del pid.txt</span><br><span class="line"> )</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="built_in">exit</span></span><br></pre></td></tr></table></figure></p>
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>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fdisk -l 查看当前磁盘的分区情况</span><br></pre></td></tr></table></figure><br />
<img data-src="https://nas.hitoli.com:18014/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>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">df</span> -TH 分区的文件系统类型</span><br></pre></td></tr></table></figure><br />
<img data-src="https://nas.hitoli.com:18014/images/2023/10/28/8996c9620632.png" alt="" /><br />
可从图中获取以下信息:<br />
/dev/vdb1 文件系统类型为 ext4,已挂载至 /mnt/disk1。<br />
/dev/vdc1 文件系统类型为 xfs,已挂载至 /mnt/disk2。<br />
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">fdisk /dev/vdb 查看新磁盘情况</span><br></pre></td></tr></table></figure><br />
<img data-src="https://nas.hitoli.com:18014/images/2023/10/28/0f1237aef57b.png" alt="" /><br />
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">lsbl 查看分区情况</span><br></pre></td></tr></table></figure><br />
<img data-src="https://nas.hitoli.com:18014/images/2023/10/28/8071a3832e29.png" alt="" /></p>
<h4 id="挂载新硬盘"><a class="anchor" href="#挂载新硬盘">#</a> 挂载新硬盘</h4>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mkfs.ext4 /dev/vdb 格式化磁盘</span><br></pre></td></tr></table></figure><br />
<img data-src="https://nas.hitoli.com:18014/images/2023/10/28/9353dd85579f.png" alt="" /><br />
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> /mnt</span><br><span class="line"><span class="built_in">mkdir</span> data 新建挂载点</span><br><span class="line">mount /dev/vdb /mnt/data 挂载</span><br></pre></td></tr></table></figure><br />
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">df</span> -h 查看挂载情况</span><br></pre></td></tr></table></figure><br />
<img data-src="https://nas.hitoli.com:18014/images/2023/10/28/ead4f7b1323f.png" alt="" /><br />
查看 UUID 有三种方式:<br />
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">blkid</span><br></pre></td></tr></table></figure><br />
<img data-src="https://nas.hitoli.com:18014/images/2023/10/28/236412bc1e3f.png" alt="" /><br />
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">lsblk -f</span><br></pre></td></tr></table></figure><br />
<img data-src="https://nas.hitoli.com:18014/images/2023/10/28/35d7182c5647.png" alt="" /><br />
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ll /dev/disk/by-uuid/</span><br></pre></td></tr></table></figure><br />
<img data-src="https://nas.hitoli.com:18014/images/2023/10/28/3f9d4f69d8ea.png" alt="" /><br />
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">设置自动挂载:</span><br><span class="line"><span class="built_in">echo</span> <span class="string">"UUID=c8ac09ca-fd4d-4511-bd2c-4fdf96f08168 /data ext4 defaults 0 0"</span> >> /etc/fstab</span><br><span class="line">自动挂载/etc/fstab里面的东西</span><br><span class="line">mount -a</span><br></pre></td></tr></table></figure></p>
<h4 id="临时卸载"><a class="anchor" href="#临时卸载">#</a> 临时卸载</h4>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">umount /dev/vdb 重启机器之后又恢复到挂载状态</span><br></pre></td></tr></table></figure></p>
<h4 id="永久卸载"><a class="anchor" href="#永久卸载">#</a> 永久卸载</h4>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim /etc/fstab 把添加的磁盘信息删除即可。</span><br></pre></td></tr></table></figure></p>
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>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">apt-get install -y squid</span><br></pre></td></tr></table></figure></p>
<ul>
<li>2、配置</li>
</ul>
<div class="note info">
<p>生成用户文件</p>
</div>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">apt-get install apache2-utils</span><br><span class="line">htpasswd -c /etc/squid/squid_user.txt 用户名</span><br></pre></td></tr></table></figure></p>
<div class="note info">
<p>修改 squid 配置<br />
1、直接修改 /etc/squid/squid.conf 文件<br />
2、修改 /etc/squid/conf.d/debian.conf 文件<br />
两种方式都一样,在底部加入以下代码</p>
</div>
<p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#dns服务器地址</span></span><br><span class="line"><span class="string">dns_nameservers</span> <span class="number">8.8</span><span class="number">.8</span><span class="number">.8</span> <span class="number">8.8</span><span class="number">.4</span><span class="number">.4</span></span><br><span class="line"><span class="string">dns_v4_first</span> <span class="string">on</span></span><br><span class="line"><span class="comment"># 监听端口</span></span><br><span class="line"><span class="string">http_port</span> <span class="number">3128</span></span><br><span class="line"><span class="comment"># 定义squid密码文件与ncsa_auth文件位置</span></span><br><span class="line"><span class="string">auth_param</span> <span class="string">basic</span> <span class="string">program</span> <span class="string">/usr/lib/squid/basic_ncsa_auth</span> <span class="string">/etc/squid/squid_user.txt</span></span><br><span class="line"><span class="comment"># 认证进程的数量</span></span><br><span class="line"><span class="string">auth_param</span> <span class="string">basic</span> <span class="string">children</span> <span class="number">15</span></span><br><span class="line"><span class="comment"># 认证对话框显示提示信息</span></span><br><span class="line"><span class="string">auth_param</span> <span class="string">basic</span> <span class="string">realm</span> <span class="string">Squid</span> <span class="string">proxy-caching</span> <span class="string">web</span> <span class="string">server</span></span><br><span class="line"><span class="comment"># 认证有效期</span></span><br><span class="line"><span class="string">auth_param</span> <span class="string">basic</span> <span class="string">credentialsttl</span> <span class="number">24</span> <span class="string">hours</span></span><br><span class="line"><span class="comment"># 是否区分用户名大小,off为不区分</span></span><br><span class="line"><span class="string">auth_param</span> <span class="string">basic</span> <span class="string">casesensitive</span> <span class="string">off</span></span><br><span class="line"><span class="comment"># 对定义的squid_user文件内的用户开启认证访问</span></span><br><span class="line"><span class="string">acl</span> <span class="string">用户名</span> <span class="string">proxy_auth</span> <span class="string">REQUIRED</span></span><br><span class="line"><span class="comment"># 允许squid_user文件内用户进行代理</span></span><br><span class="line"><span class="string">http_access</span> <span class="string">allow</span> <span class="string">用户名</span></span><br><span class="line"><span class="comment"># 顺序匹配,最后添加拒绝所有未允许的规则。不添加会发现,未匹配到的规则会被放行</span></span><br><span class="line"><span class="string">http_access</span> <span class="string">deny</span> <span class="string">all</span></span><br><span class="line"><span class="comment"># 缓存设置</span></span><br><span class="line"><span class="string">cache_dir</span> <span class="string">ufs</span> <span class="string">/var/spool/squid</span> <span class="number">100</span> <span class="number">16</span> <span class="number">256</span> <span class="string">read-only</span></span><br><span class="line"><span class="string">cache_mem</span> <span class="number">0</span> <span class="string">MB</span></span><br><span class="line"><span class="string">coredump_dir</span> <span class="string">/var/spool/squid</span></span><br><span class="line"><span class="comment"># 配置高匿,不允许设置任何多余头信息,保持原请求header。</span></span><br><span class="line"><span class="string">header_access</span> <span class="string">Via</span> <span class="string">deny</span> <span class="string">all</span></span><br><span class="line"><span class="string">header_access</span> <span class="string">X-Forwarded-For</span> <span class="string">deny</span> <span class="string">all</span></span><br><span class="line"><span class="string">header_access</span> <span class="string">Server</span> <span class="string">deny</span> <span class="string">all</span></span><br><span class="line"><span class="string">header_access</span> <span class="string">X-Cache</span> <span class="string">deny</span> <span class="string">all</span></span><br><span class="line"><span class="string">header_access</span> <span class="string">X-Cache-Lookup</span> <span class="string">deny</span> <span class="string">all</span></span><br><span class="line"><span class="string">forwarded_for</span> <span class="string">off</span></span><br><span class="line"><span class="string">via</span> <span class="string">off</span></span><br><span class="line"><span class="comment"># logs相关配置</span></span><br><span class="line"><span class="string">emulate_httpd_log</span> <span class="string">on</span></span><br><span class="line"><span class="string">logformat</span> <span class="string">squid</span> <span class="string">%{X-Forwarded-For}>h</span> <span class="string">%ui</span> <span class="string">%un</span> [<span class="string">%tl</span>] <span class="string">"%rm %ru HTTP/%rv"</span> <span class="string">%Hs</span> <span class="string">%<st</span> <span class="string">"<span class="template-variable">%{Referer}</span>>h"</span> <span class="string">"<span class="template-variable">%{User-Agent}</span>>h"</span> <span class="string">%Ss:%Sh</span></span><br><span class="line"><span class="string">access_log</span> <span class="string">/var/log/squid/access.log</span> <span class="string">squid</span></span><br><span class="line"><span class="string">cache_log</span> <span class="string">/var/log/squid/cache.log</span></span><br><span class="line"><span class="string">cache_store_log</span> <span class="string">/var/log/squid/store.log</span></span><br><span class="line"><span class="string">logfile_rotate</span> <span class="number">20</span></span><br></pre></td></tr></table></figure></p>
<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>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">apt-get install -y stunnel</span><br></pre></td></tr></table></figure></p>
<ul>
<li>2、生成 TLS/SSL 证书</li>
</ul>
<p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">openssl req -new -x509 -days 3650 -nodes -out stunnel.pem -keyout stunnel.pem</span><br></pre></td></tr></table></figure></p>
<ul>
<li>
<p>3、将证书 stunnel.pem 放到 /etc/stunnel/ 目录下</p>
</li>
<li>
<p>4、修改 stunnel 配置 (/etc/stunnle/stunnle.conf)</p>
</li>
</ul>
<p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">;</span> <span class="string">设置stunnel的pid文件路径</span></span><br><span class="line"><span class="string">pid</span> <span class="string">=</span> <span class="string">/etc/stunnel/stunnel.pid</span></span><br><span class="line"><span class="string">;</span> <span class="string">设置stunnel工作的用户(组)</span></span><br><span class="line"><span class="string">setuid</span> <span class="string">=</span> <span class="string">root</span></span><br><span class="line"><span class="string">setgid</span> <span class="string">=</span> <span class="string">root</span></span><br><span class="line"></span><br><span class="line"><span class="string">;</span> <span class="string">开启日志等级:emerg</span> <span class="string">(0),</span> <span class="string">alert</span> <span class="string">(1),</span> <span class="string">crit</span> <span class="string">(2),</span> <span class="string">err</span> <span class="string">(3),</span> <span class="string">warning</span> <span class="string">(4),</span> <span class="string">notice</span> <span class="string">(5),</span> <span class="string">info</span> <span class="string">(6),</span> <span class="string">or</span> <span class="string">debug</span> <span class="string">(7)</span></span><br><span class="line"><span class="string">debug</span> <span class="string">=</span> <span class="number">7</span></span><br><span class="line"><span class="string">;</span> <span class="string">日志文件路径</span></span><br><span class="line"><span class="string">output</span> <span class="string">=</span> <span class="string">/etc/stunnel/stunnel.log</span></span><br><span class="line"></span><br><span class="line"><span class="string">;</span> <span class="string">证书文件</span></span><br><span class="line"><span class="string">cert</span> <span class="string">=</span> <span class="string">/etc/stunnel/stunnel.pem</span></span><br><span class="line"><span class="string">;</span> <span class="string">私钥文件</span></span><br><span class="line"><span class="string">key</span> <span class="string">=</span> <span class="string">/etc/stunnel/stunnel.pem</span></span><br><span class="line"></span><br><span class="line"><span class="string">;</span> <span class="string">自定义服务名squid-proxy</span></span><br><span class="line">[<span class="string">squid-proxy</span>]</span><br><span class="line"><span class="string">;</span> <span class="string">服务监听的端口,client要连接这个端口与server通信</span></span><br><span class="line"><span class="string">accept</span> <span class="string">=</span> <span class="number">1234</span><span class="string">(自定义)</span></span><br><span class="line"><span class="string">;</span> <span class="string">服务要连接的端口,连接到squid的3128端口,将数据发给squid</span></span><br><span class="line"><span class="string">connect</span> <span class="string">=</span> <span class="number">3128</span></span><br></pre></td></tr></table></figure></p>
<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>
<p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">[<span class="string">squid-proxy</span>]</span><br><span class="line"><span class="string">client</span> <span class="string">=</span> <span class="literal">yes</span></span><br><span class="line"><span class="string">;</span> <span class="string">监听3128端口,那么用户浏览器的代理设置就是</span> <span class="string">stunnel-client-ip:3128</span></span><br><span class="line"><span class="string">accept</span> <span class="string">=</span> <span class="number">3128</span></span><br><span class="line"><span class="string">;</span> <span class="string">要连接到的stunnel</span> <span class="string">server的ip与端口</span></span><br><span class="line"><span class="string">connect</span> <span class="string">=</span> <span class="string">stunnel服务端ip:1234(服务端自定义端口)</span></span><br><span class="line"></span><br><span class="line"><span class="string">;</span> <span class="string">需要验证对方发过来的证书</span></span><br><span class="line"><span class="string">verify</span> <span class="string">=</span> <span class="number">2</span></span><br><span class="line"><span class="string">;</span> <span class="string">用来进行证书验证的文件(stunnel服务端生成的证书复制到以下目录并改名为stunnel-server.pem)</span></span><br><span class="line"><span class="string">CAfile</span> <span class="string">=</span> <span class="string">C:\Program</span> <span class="string">Files</span> <span class="string">(x86)\stunnel\config\stunnel-server.pem</span></span><br></pre></td></tr></table></figure></p>
<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://nas.hitoli.com:18014/images/2023/09/09/6a38fcb32752.png" alt="" /><br />
<img data-src="https://nas.hitoli.com:18014/images/2023/09/09/72892168bfeb.png" alt="" /></p>
2023-09-09T08:48:00.000Z
https://hitoli.com/2023/09/09/Windows-11%E5%8F%B3%E9%94%AE%E8%8F%9C%E5%8D%95%E6%81%A2%E5%A4%8D%E8%80%81%E7%89%88%E6%9C%AC/
Windows 11右键菜单恢复老版本
<h4 id="恢复方法"><a class="anchor" href="#恢复方法">#</a> 恢复方法</h4>
<p>1、按【Win+X】</p>
<p>2、选择【终端管理员】</p>
<p>3、输入以下命令并回车:<br />
<code>reg add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f /ve</code></p>
<p>4、重启电脑</p>
2023-09-09T08:38:00.000Z
https://hitoli.com/2023/07/08/%E8%A7%A3%E5%86%B3Lombok%E6%8A%A5%E9%94%99/
解决Lombok报错
<h4 id="问题描述"><a class="anchor" href="#问题描述">#</a> 问题描述</h4>
<ol>
<li>报错详情</li>
</ol>
<div class="note info">
<p>java: You aren’t using a compiler supported by lombok, so lombok will not work and has been disabled.<br />
Your processor is: com.sun.proxy.$Proxy26<br />
Lombok supports: OpenJDK javac, ECJ</p>
</div>
<p><img data-src="https://nas.hitoli.com:18014/images/2023/07/08/393a238856e4.png" alt="" /></p>
<ol start="2">
<li>
<p>问题分析<br />
属于 lombok 编译不通过,原因可能是因为依赖没有更到最新版本</p>
</li>
<li>
<p>解决办法<br />
在 IntelliJ IDEA 的全局配置 Compiler 中添加如下配置:<br />
<figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">-Djps.track.ap.dependencies=false</span></span><br></pre></td></tr></table></figure><br />
<img data-src="https://nas.hitoli.com:18014/images/2023/07/08/34bac08a5d10.png" alt="" /></p>
</li>
</ol>
2023-07-08T02:51:00.000Z
https://hitoli.com/2023/07/01/shoka%E4%B8%BB%E9%A2%98%E9%80%9F%E5%BA%A6%E4%BC%98%E5%8C%96-%E6%8B%86%E5%88%86jsdelivr/
shoka主题速度优化-拆分jsdelivr
<h4 id="前言"><a class="anchor" href="#前言">#</a> 前言</h4>
<div class="note primary">
<p>该篇文章介绍了如何对 shoka 主题进行 jsdelivr 聚合拆分,以便使用国内镜像源和异步加载,从而优化网站速度。具体操作包括更改模板、注册 helper 和更改配置。其中,推荐使用 advVendors 配置,可自定义加载源和 js 文件名,同时支持异步加载、pjax 刷新和 integrity 防 XXS 等特性。</p>
</div>
<p>众所周知,jsdelivr 在国内的速度可以用慢的一批来形容而 shoka 主题使用了 jsdelivr 的 combine 功能加载第三方 js, 而 combine 在国内没有镜像源并且阻断了使用 CDN 并发加速的道路,本篇博文会将 jsdelivr 聚合拆分为几个独立的 js, 以便使用国内镜像源和异步加载。</p>
<div class="note info">
<p>此方案相较于本地化而言有较大速度优势,尤其在 CDN 并发加持下</p>
</div>
<h4 id="拆分-jsdelivr"><a class="anchor" href="#拆分-jsdelivr">#</a> 拆分 jsdelivr</h4>
<ol>
<li>更改模板</li>
</ol>
<p>打开 <span class="red">shoka\layout\_partials\layout.njk</span>,找到第 144 行左右:</p>
<p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://cdn.polyfill.io/v3/polyfill.js"</span>></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="symbol">&#123;</span><span class="symbol">&#123;</span> _vendor_js() <span class="symbol">&#125;</span><span class="symbol">&#125;</span></span><br><span class="line"><span class="symbol">&#123;</span><span class="symbol">&#123;</span> _js('app.js') <span class="symbol">&#125;</span><span class="symbol">&#125;</span></span><br><span class="line"><span class="symbol">&#123;</span><span class="symbol">&#123;</span> partial('_partials/third-party/baidu-analytics.njk', <span class="symbol">&#123;</span><span class="symbol">&#125;</span>, <span class="symbol">&#123;</span>cache: true<span class="symbol">&#125;</span>) <span class="symbol">&#125;</span><span class="symbol">&#125;</span></span><br></pre></td></tr></table></figure></p>
<p>更改为如下内容:</p>
<p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://cdn.polyfill.io/v3/polyfill.js"</span>></span><span class="tag"></<span class="name">script</span>></span></span><br><span class="line"><span class="symbol">&#123;</span>%- if theme.advVendors.enable %<span class="symbol">&#125;</span></span><br><span class="line"> <span class="symbol">&#123;</span>% for i in _list_vendor_js() %<span class="symbol">&#125;</span></span><br><span class="line"> <span class="symbol">&#123;</span><span class="symbol">&#123;</span> _adv_vendor_js(i) <span class="symbol">&#125;</span><span class="symbol">&#125;</span></span><br><span class="line"> <span class="symbol">&#123;</span>% endfor %<span class="symbol">&#125;</span></span><br><span class="line"><span class="symbol">&#123;</span>%- else %<span class="symbol">&#125;</span></span><br><span class="line"><span class="symbol">&#123;</span><span class="symbol">&#123;</span> _vendor_js() <span class="symbol">&#125;</span><span class="symbol">&#125;</span></span><br><span class="line"><span class="symbol">&#123;</span>%- endif %<span class="symbol">&#125;</span></span><br><span class="line"><span class="symbol">&#123;</span><span class="symbol">&#123;</span> _js('app.js')<span class="symbol">&#125;</span><span class="symbol">&#125;</span></span><br><span class="line"><span class="symbol">&#123;</span><span class="symbol">&#123;</span> partial('_partials/third-party/baidu-analytics.njk', <span class="symbol">&#123;</span><span class="symbol">&#125;</span>, <span class="symbol">&#123;</span>cache: true<span class="symbol">&#125;</span>) <span class="symbol">&#125;</span><span class="symbol">&#125;</span></span><br></pre></td></tr></table></figure></p>
<ol start="2">
<li>注册 helper</li>
</ol>
<p>打开 <span class="red">shoka\scripts\helpers\asset.js</span>, 最后一行新建空行,增加如下内容:</p>
<p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line">hexo.<span class="property">extend</span>.<span class="property">helper</span>.<span class="title function_">register</span>(<span class="string">'_list_vendor_js'</span>, <span class="function">() =></span> {</span><br><span class="line"> <span class="keyword">return</span> hexo.<span class="property">theme</span>.<span class="property">config</span>.<span class="property">vendorsList</span>.<span class="property">js</span>;</span><br><span class="line">});</span><br><span class="line"></span><br><span class="line">hexo.<span class="property">extend</span>.<span class="property">helper</span>.<span class="title function_">register</span>(<span class="string">'_adv_vendor_js'</span>, <span class="keyword">function</span> (<span class="params">js_name</span>) {</span><br><span class="line"> <span class="keyword">const</span> config = hexo.<span class="property">theme</span>.<span class="property">config</span>.<span class="property">advVendors</span>.<span class="property">js</span>[js_name];</span><br><span class="line"> <span class="keyword">const</span> src = config[<span class="string">"src"</span>];</span><br><span class="line"> <span class="keyword">let</span> result;</span><br><span class="line"> <span class="keyword">if</span> (src.<span class="title function_">indexOf</span>(<span class="string">"http"</span>) !== -<span class="number">1</span>) {</span><br><span class="line"> result = src;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (src.<span class="title function_">indexOf</span>(<span class="string">"combine"</span>) !== -<span class="number">1</span>) {</span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">"The combine feature is not recommended!"</span>)</span><br><span class="line"> result = hexo.<span class="property">theme</span>.<span class="property">config</span>.<span class="property">advVendors</span>.<span class="property">combine</span> + src;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (src.<span class="title function_">indexOf</span>(<span class="string">"npm"</span>) !== -<span class="number">1</span>) {</span><br><span class="line"> result = hexo.<span class="property">theme</span>.<span class="property">config</span>.<span class="property">advVendors</span>.<span class="property">npm</span> + src.<span class="title function_">slice</span>(<span class="number">4</span>);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (src.<span class="title function_">indexOf</span>(<span class="string">"gh"</span>) !== -<span class="number">1</span>) {</span><br><span class="line"> result = hexo.<span class="property">theme</span>.<span class="property">config</span>.<span class="property">advVendors</span>.<span class="property">github</span> + src.<span class="title function_">slice</span>(<span class="number">3</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> result = <span class="string">"/"</span> + src;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">let</span> attr = {<span class="attr">src</span>: result};</span><br><span class="line"> <span class="keyword">if</span> (config[<span class="string">"async"</span>]) attr[<span class="string">"async"</span>] = <span class="string">"async"</span>;</span><br><span class="line"> <span class="keyword">if</span> (config[<span class="string">"data-pjax"</span>]) attr[<span class="string">"data-pjax"</span>] = <span class="string">"data-pjax"</span>;</span><br><span class="line"> <span class="keyword">if</span> (config[<span class="string">"hash-value"</span>]) attr[<span class="string">"integrity"</span>]=config[<span class="string">"hash-value"</span>];</span><br><span class="line"> <span class="keyword">if</span> (config[<span class="string">"deferLoad"</span>]) {</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">htmlTag</span>(<span class="string">'script'</span>, {<span class="string">"data-pjax"</span>: <span class="literal">true</span>}, <span class="string">`</span></span><br><span class="line"><span class="string"> const script=document.createElement("script");script.src="<span class="subst">${result}</span>",script.async=true,document.body.appendChild(script)</span></span><br><span class="line"><span class="string"> `</span>)</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="title function_">htmlTag</span>(<span class="string">'script'</span>, attr, <span class="string">''</span>);</span><br><span class="line">})</span><br></pre></td></tr></table></figure></p>
<ol start="3">
<li>更改配置</li>
</ol>
<p>在 shoka 目录下 <span class="red">_config.yml</span> 增加如下内容:</p>
<div class="note info">
<p>推荐内容,可根据自己情况更改</p>
</div>
<p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">advVendors:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">github:</span> <span class="string">"https://cdn.jsdelivr.net/gh/"</span></span><br><span class="line"> <span class="attr">combine:</span> <span class="string">"https://cdn.jsdelivr.net/"</span></span><br><span class="line"> <span class="attr">npm:</span> <span class="string">"https://unpkg.com/"</span></span><br><span class="line"> <span class="attr">js:</span></span><br><span class="line"> <span class="attr">pace:</span></span><br><span class="line"> <span class="attr">src:</span> <span class="string">https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/pace/1.0.2/pace.min.js</span></span><br><span class="line"> <span class="attr">pjax:</span></span><br><span class="line"> <span class="attr">src:</span> <span class="string">https://lib.baomitu.com/pjax/0.2.8/pjax.min.js</span></span><br><span class="line"> <span class="attr">fetch:</span></span><br><span class="line"> <span class="attr">src:</span> <span class="string">npm/whatwg-fetch@3.4.0/dist/fetch.umd.js</span></span><br><span class="line"> <span class="attr">anime:</span></span><br><span class="line"> <span class="attr">src:</span> <span class="string">https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/animejs/3.2.0/anime.min.js</span></span><br><span class="line"> <span class="attr">algolia:</span></span><br><span class="line"> <span class="attr">src:</span> <span class="string">https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/algoliasearch/4.12.1/algoliasearch-lite.umd.min.js</span></span><br><span class="line"> <span class="attr">instantsearch:</span></span><br><span class="line"> <span class="attr">src:</span> <span class="string">https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/instantsearch.js/4.39.0/instantsearch.production.min.js</span></span><br><span class="line"> <span class="attr">lazyload:</span></span><br><span class="line"> <span class="attr">src:</span> <span class="string">https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/lozad.js/1.16.0/lozad.min.js</span></span><br><span class="line"> <span class="attr">quicklink:</span></span><br><span class="line"> <span class="attr">src:</span> <span class="string">https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/quicklink/2.2.0/quicklink.umd.min.js</span></span><br><span class="line"> <span class="attr">fancybox:</span></span><br><span class="line"> <span class="attr">src:</span> <span class="string">https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/??jquery/3.5.1/jquery.min.js,fancybox/3.5.7/jquery.fancybox.min.js,justifiedGallery/3.8.1/js/jquery.justifiedGallery.min.js</span></span><br><span class="line"> <span class="attr">async:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">valine:</span></span><br><span class="line"> <span class="attr">src:</span> <span class="string">gh/amehime/MiniValine@4.2.2-beta10/dist/MiniValine.min.js</span></span><br><span class="line"> <span class="attr">copy_tex:</span></span><br><span class="line"> <span class="attr">src:</span> <span class="string">https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/KaTeX/0.12.0/contrib/copy-tex.min.js</span></span><br><span class="line"> <span class="attr">async:</span> <span class="literal">true</span></span><br><span class="line"> <span class="attr">chart:</span></span><br><span class="line"> <span class="attr">src:</span> <span class="string">npm/frappe-charts@1.5.0/dist/frappe-charts.min.iife.js</span></span><br><span class="line"></span><br><span class="line"><span class="attr">vendorsList:</span></span><br><span class="line"> <span class="attr">js:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">pace</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">pjax</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">fetch</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">anime</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">algolia</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">instantsearch</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">lazyload</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">quicklink</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">fancybox</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">valine</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">copy_tex</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">chart</span></span><br></pre></td></tr></table></figure></p>
<p>下面为结构详解:</p>
<p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">advVendors:</span></span><br><span class="line"> <span class="attr">enable:</span> <span class="literal">true</span> <span class="comment">#是否开启,关闭使用主题默认加载</span></span><br><span class="line"> <span class="attr">github:</span> <span class="comment">#github 使用的加载源,需要协议头和末尾斜杠</span></span><br><span class="line"> <span class="attr">combine:</span> <span class="comment">#聚合 js 使用的加载源 (不建议使用)</span></span><br><span class="line"> <span class="attr">npm:</span> <span class="comment">#npm 的加载源</span></span><br><span class="line"> <span class="attr">js:</span></span><br><span class="line"> <span class="attr">jspackage:</span> <span class="comment">#js 名,可以与文件名不一致</span></span><br><span class="line"> <span class="attr">src:</span> <span class="string">"资源地址,详情见后面"</span></span><br><span class="line"> <span class="comment"># async: true 异步加载此 js</span></span><br><span class="line"> <span class="comment"># data-pjax: true 在 pjax 加载时刷新此 js</span></span><br><span class="line"> <span class="comment"># hash-value: 这个资源的 integrity 值,用于防 XXS</span></span><br><span class="line"> <span class="comment"># deferLoad: true 使用动态 DOM 节点添加延迟 js 加载 (实验性)</span></span><br><span class="line"></span><br><span class="line"><span class="attr">vendorsList:</span></span><br><span class="line"> <span class="attr">js:</span></span><br><span class="line"> <span class="bullet">-</span> <span class="string">jspackage</span> <span class="comment">#与上方 jspackage 一致即可</span></span><br></pre></td></tr></table></figure></p>
<p>资源地址格式如下:</p>
<p><span class="red"><span class="exturl" data-url="aHR0cHM6Ly9leGFtcGxlLmNvbS94eHguanM=">https://example.com/xxx.js</span></span> 使用 http (s) 地址加载 js<br />
<span class="red">combine/xxx.js,xxx.js</span> 使用 jsdelivr 的 combine 功能加载 (不推荐)<br />
<span class="red">npm/xxx/xxx.js</span> 使用 npm 源加载 js<br />
<span class="red">gh/xxx/xxx.js</span> 使用 gh 源加载 js<br />
<span class="red">xxx.js</span> 从本地加载 js<br />
优先级如下:<br />
<span class="red">http>combine>npm>gh > 本地</span></p>
2023-06-30T17:15:00.000Z
https://hitoli.com/2023/05/30/http%E8%AF%B7%E6%B1%82%E4%B9%8BrestTemplate%E9%85%8D%E7%BD%AE%E8%B6%85%E6%97%B6%E6%97%B6%E9%97%B4/
http请求之restTemplate配置超时时间
<h4 id="问题"><a class="anchor" href="#问题">#</a> 问题</h4>
<p>http 请求发起后接收不到返回数据!!!【测试环境没出问题,发到正式环境就有问题】</p>
<p>项目中通过 restTemplate 发起请求:<br />
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">log.info(<span class="string">"请求入参:{}"</span>,JSON.toJSONString(request));<span class="comment">//打印日志1</span></span><br><span class="line"><span class="comment">// 配置http请求的连接超时时间和读取超时时间</span></span><br><span class="line"><span class="type">HttpsClientRequestFactory</span> <span class="variable">factory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HttpsClientRequestFactory</span>();</span><br><span class="line">factory.setConnectTimeout(<span class="number">60</span> * <span class="number">1000</span>);</span><br><span class="line">factory.setReadTimeout(<span class="number">5</span> * <span class="number">60</span> * <span class="number">1000</span>);</span><br><span class="line"><span class="type">RestTemplate</span> <span class="variable">restTemplate</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">RestTemplate</span>(factory);</span><br><span class="line">Result<InventoryResult> result = restTemplate.postForObject(address.concat(inventoryUrl), request, Result.class);</span><br><span class="line">log.info(<span class="string">"库存同步,返回数据: {}"</span>, result);<span class="comment">//打印日志2</span></span><br></pre></td></tr></table></figure></p>
<ul>
<li>打印日志 1 内容为:</li>
</ul>
<p>http 请求入参:{data=[{ productStatus=10,skuCode=null}], messageId=ewpfpr1t6ey5r6qj0su0w1h6rt73hr,token=vgvU5EJKuZbuHii7WH6pTINp40ZRicaqLz4dq5P7L6pDzWir8EEGZhCKPucQjljsw69EHasEy+iJfdTofDg==}</p>
<ul>
<li>
<p>打印日志 2 内容为:没有打印内容!!!</p>
</li>
<li>
<p>最后发现是因为测试环境中数据量较小,http 请求后,很快能得到相应,而正式环境数据量较大,没有及时得到响应,连接或者读取超时!!!</p>
</li>
</ul>
<h4 id="解决方式"><a class="anchor" href="#解决方式">#</a> 解决方式</h4>
<h6 id="第一种"><a class="anchor" href="#第一种">#</a> 第一种</h6>
<ol>
<li>
<p>添加 HttpsClientRequestFactory 类,并继承 SimpleClientHttpRequestFactory<br />
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 兼容调Https接口</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HttpsClientRequestFactory</span> <span class="keyword">extends</span> <span class="title class_">SimpleClientHttpRequestFactory</span> {</span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">prepareConnection</span><span class="params">(HttpURLConnection connection, String httpMethod)</span></span><br><span class="line"> <span class="keyword">throws</span> IOException {</span><br><span class="line"> <span class="keyword">if</span> (connection <span class="keyword">instanceof</span> HttpsURLConnection) {</span><br><span class="line"> prepareHttpsConnection((HttpsURLConnection) connection);</span><br><span class="line"> }</span><br><span class="line"> <span class="built_in">super</span>.prepareConnection(connection, httpMethod);</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">prepareHttpsConnection</span><span class="params">(HttpsURLConnection connection)</span> {</span><br><span class="line"> connection.setHostnameVerifier(<span class="keyword">new</span> <span class="title class_">SkipHostnameVerifier</span>());</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> connection.setSSLSocketFactory(createSslSocketFactory());</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">catch</span> (Exception ex) {</span><br><span class="line"> <span class="comment">// Ignore</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> SSLSocketFactory <span class="title function_">createSslSocketFactory</span><span class="params">()</span> <span class="keyword">throws</span> Exception {</span><br><span class="line"> <span class="type">SSLContext</span> <span class="variable">context</span> <span class="operator">=</span> SSLContext.getInstance(<span class="string">"TLS"</span>);</span><br><span class="line"> context.init(<span class="literal">null</span>, <span class="keyword">new</span> <span class="title class_">TrustManager</span>[] { <span class="keyword">new</span> <span class="title class_">SkipX509TrustManager</span>() },</span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">SecureRandom</span>());</span><br><span class="line"> <span class="keyword">return</span> context.getSocketFactory();</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">class</span> <span class="title class_">SkipHostnameVerifier</span> <span class="keyword">implements</span> <span class="title class_">HostnameVerifier</span> {</span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">verify</span><span class="params">(String s, SSLSession sslSession)</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">SkipX509TrustManager</span> <span class="keyword">implements</span> <span class="title class_">X509TrustManager</span> {</span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> X509Certificate[] getAcceptedIssuers() {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">X509Certificate</span>[<span class="number">0</span>];</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">checkClientTrusted</span><span class="params">(X509Certificate[] chain, String authType)</span> {</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">checkServerTrusted</span><span class="params">(X509Certificate[] chain, String authType)</span> {</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
</li>
<li>
<p>使用 restTemplate 发起请求前先设置连接和超时时间或者通过容器加载配置类然后设置超时时间<br />
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//配置http请求的连接超时时间和读取超时时间</span></span><br><span class="line"><span class="type">HttpsClientRequestFactory</span> <span class="variable">factory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HttpsClientRequestFactory</span>();</span><br><span class="line">factory.setConnectTimeout(<span class="number">60</span> * <span class="number">1000</span>);</span><br><span class="line">factory.setReadTimeout(<span class="number">5</span> * <span class="number">60</span> * <span class="number">1000</span>);</span><br><span class="line"><span class="type">RestTemplate</span> <span class="variable">restTemplate</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">RestTemplate</span>(factory);</span><br><span class="line">BaseResult<QueryInventoryResult> result = restTemplate.postForObject(address.concat(inventoryUrl), request, Result.class);</span><br></pre></td></tr></table></figure><br />
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RestConfig</span> {</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//60 * 1000</span></span><br><span class="line"> <span class="meta">@Value("${rest.connectTimeout:60000}")</span></span><br><span class="line"> <span class="keyword">private</span> <span class="type">int</span> connectTimeout;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//5 * 60 * 1000</span></span><br><span class="line"> <span class="meta">@Value("${rest.readTimeout:300000}")</span></span><br><span class="line"> <span class="keyword">private</span> <span class="type">int</span> readTimeout;</span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="keyword">public</span> RestTemplate <span class="title function_">restTemplate</span><span class="params">()</span> {</span><br><span class="line"> <span class="type">SimpleClientHttpRequestFactory</span> <span class="variable">simpleClientHttpRequestFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SimpleClientHttpRequestFactory</span>();</span><br><span class="line"> simpleClientHttpRequestFactory.setConnectTimeout(connectTimeout);</span><br><span class="line"> simpleClientHttpRequestFactory.setReadTimeout(readTimeout);</span><br><span class="line"> <span class="type">RestTemplate</span> <span class="variable">restTemplate</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">RestTemplate</span>(simpleClientHttpRequestFactory);</span><br><span class="line"> <span class="keyword">return</span> restTemplate;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure></p>
</li>
</ol>
<h6 id="第二种"><a class="anchor" href="#第二种">#</a> 第二种</h6>
<p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RestConfig</span> {</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//60 * 1000</span></span><br><span class="line"> <span class="meta">@Value("${rest.connectTimeout:60000}")</span></span><br><span class="line"> <span class="keyword">private</span> <span class="type">int</span> connectTimeout;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//5 * 60 * 1000</span></span><br><span class="line"> <span class="meta">@Value("${rest.readTimeout:300000}")</span></span><br><span class="line"> <span class="keyword">private</span> <span class="type">int</span> readTimeout; </span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Value("${rest.connectionRequestTimeout:300000}")</span></span><br><span class="line"> <span class="keyword">private</span> <span class="type">int</span> connectionRequestTimeout; </span><br><span class="line"> </span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 使用 HttpComponentsClientHttpRequestFactory创建http请求(推荐)</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="keyword">public</span> RestTemplate <span class="title function_">restTemplate</span><span class="params">()</span> {</span><br><span class="line"> <span class="type">HttpComponentsClientHttpRequestFactory</span> <span class="variable">httpRequestFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HttpComponentsClientHttpRequestFactory</span>();</span><br><span class="line"> httpRequestFactory.setConnectionRequestTimeout(connectionRequestTimeout);</span><br><span class="line"> httpRequestFactory.setConnectTimeout(connectTimeout);</span><br><span class="line"> httpRequestFactory.setReadTimeout(readTimeout);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">RestTemplate</span>(httpRequestFactory);</span><br><span class="line"> </span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<h6 id="第三种基于第二种升级"><a class="anchor" href="#第三种基于第二种升级">#</a> 第三种(基于第二种升级)</h6>
<p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RestConfig</span> {</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 高并发采用HttpClient连接池</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="keyword">public</span> RestTemplate <span class="title function_">restTemplate</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">RestTemplate</span>(httpRequestFactory());</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="keyword">public</span> ClientHttpRequestFactory <span class="title function_">httpRequestFactory</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">HttpComponentsClientHttpRequestFactory</span>(httpClient());</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Bean</span></span><br><span class="line"> <span class="keyword">public</span> HttpClient <span class="title function_">httpClient</span><span class="params">()</span> {</span><br><span class="line"> Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()</span><br><span class="line"> .register(<span class="string">"http"</span>, PlainConnectionSocketFactory.getSocketFactory())</span><br><span class="line"> .register(<span class="string">"https"</span>, SSLConnectionSocketFactory.getSocketFactory())</span><br><span class="line"> .build();</span><br><span class="line"> <span class="type">PoolingHttpClientConnectionManager</span> <span class="variable">connectionManager</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">PoolingHttpClientConnectionManager</span>(registry);</span><br><span class="line"> <span class="comment">//设置整个连接池最大连接数</span></span><br><span class="line"> connectionManager.setMaxTotal(<span class="number">1000</span>);</span><br><span class="line"> <span class="comment">//路由是对maxTotal的细分</span></span><br><span class="line"> connectionManager.setDefaultMaxPerRoute(<span class="number">100</span>);</span><br><span class="line"> <span class="comment">//定义不活动的时间(毫秒),超过的连接从连接池拿取需要重新验证</span></span><br><span class="line"> connectionManager.setValidateAfterInactivity(<span class="number">200</span>);</span><br><span class="line"> <span class="type">RequestConfig</span> <span class="variable">requestConfig</span> <span class="operator">=</span> RequestConfig.custom()</span><br><span class="line"> .setSocketTimeout(<span class="number">30000</span>) <span class="comment">//返回数据的超时时间</span></span><br><span class="line"> .setConnectTimeout(<span class="number">20000</span>) <span class="comment">//连接上服务器的超时时间</span></span><br><span class="line"> .setConnectionRequestTimeout(<span class="number">1000</span>) <span class="comment">//从连接池中获取连接的超时时间</span></span><br><span class="line"> .build();</span><br><span class="line"> <span class="keyword">return</span> HttpClientBuilder.create()</span><br><span class="line"> .setDefaultRequestConfig(requestConfig)</span><br><span class="line"> .setConnectionManager(connectionManager)</span><br><span class="line"> .evictIdleConnections(<span class="number">2</span>, TimeUnit.SECONDS) <span class="comment">//保持空闲的最大时间</span></span><br><span class="line"> .build();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
2023-05-30T09:20:00.000Z
https://hitoli.com/2023/05/25/%E8%A7%A3%E5%86%B3MySQL%E6%8A%A5only-full-group-by%E9%94%99%E8%AF%AF/
解决MySQL报only_full_group_by错误
<h4 id="问题描述"><a class="anchor" href="#问题描述">#</a> 问题描述</h4>
<p>当我们迁移到 MySQL 5.7+ 的版本时,常会碰到 ERROR 1055 only_full_group_by 错误,这是 5.7 之后 SQL_MODE 默认打开了严格模式导致的错误。说明你代码里有地方写的不严谨。</p>
<h4 id="解决方法"><a class="anchor" href="#解决方法">#</a> 解决方法</h4>
<ol>
<li>重写 sql</li>
<li>返回宽松模式<br />
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#查询sql_mode</span><br><span class="line"><span class="keyword">select</span> @<span class="variable">@GLOBAL</span>.sql_mode;</span><br><span class="line">#删除ONLY_FULL_GROUP_BY</span><br><span class="line">#设置sql_mode</span><br><span class="line"><span class="keyword">set</span> @<span class="variable">@GLOBAL</span>.sql_mode<span class="operator">=</span><span class="string">'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'</span>;</span><br></pre></td></tr></table></figure></li>
<li>使用聚合函数<br />
如果某些特别的原因就是要查询未分组字段,但你又没空改代码,那么我们可使用聚合函数来规避这类错误,算是一种折中的方案了,语法改严谨了,代码又不需要大动。如 ANY_VALUE ()、MAX ()、MIN () 或者 GROUP_CONCAT () 等聚合函数。</li>
</ol>
2023-05-25T10:25:00.000Z
https://hitoli.com/2023/05/25/MySQL%E4%B8%AD%E7%9A%84any-value-%E5%87%BD%E6%95%B0/
MySQL中的any_value()函数
<h4 id="问题"><a class="anchor" href="#问题">#</a> 问题</h4>
<p>业务要求:查询所有省份:<br />
<img data-src="https://nas.hitoli.com:18014/images/2023/05/25/778f34f5670d.png" alt="" /></p>
<h4 id="方法"><a class="anchor" href="#方法">#</a> 方法</h4>
<ol>
<li>
<p>distinct 排除重复<br />
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span></span><br><span class="line"> <span class="keyword">DISTINCT</span>(province_code),</span><br><span class="line"> province_name</span><br><span class="line"><span class="keyword">FROM</span></span><br><span class="line"> t_mip_base_area</span><br></pre></td></tr></table></figure></p>
</li>
<li>
<p>group by 根据身份编码分组<br />
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> </span><br><span class="line"> province_code,</span><br><span class="line"> any_value(province_name)</span><br><span class="line"><span class="keyword">FROM</span> t_mip_base_area</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> province_code</span><br></pre></td></tr></table></figure></p>
</li>
</ol>
<h6 id="若这样写"><a class="anchor" href="#若这样写">#</a> 若这样写</h6>
<p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> </span><br><span class="line"> province_code,</span><br><span class="line"> province_name</span><br><span class="line"><span class="keyword">FROM</span> t_mip_base_area</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> province_code</span><br></pre></td></tr></table></figure><br />
则会报错<br />
<img data-src="https://nas.hitoli.com:18014/images/2023/05/25/c57a8e811928.png" alt="" /></p>
<h4 id="总结"><a class="anchor" href="#总结">#</a> 总结:</h4>
<ol>
<li>
<p>MySQL5.7 之后,sql_mode 中 ONLY_FULL_GROUP_BY 模式默认设置为打开状态。</p>
</li>
<li>
<p>ONLY_FULL_GROUP_BY 的语义就是确定 select target list 中的所有列的值都是明确语义,简单的说来,在此模式下,target list 中的值要么是来自于聚合函数(sum、avg、max 等)的结果,要么是来自于 group by list 中的表达式的值</p>
</li>
<li>
<p>MySQL 提供了 any_value () 函数来抑制 ONLY_FULL_GROUP_BY 值被拒绝</p>
</li>
<li>
<p>any_value () 会选择被分到同一组的数据里第一条数据的指定列值作为返回数据</p>
</li>
</ol>
2023-05-25T10:07:00.000Z